File indexing completed on 2024-05-12 15:28:15
0001 /*************************************************************************** 0002 File : WelcomeScreenHelper.cpp 0003 Project : LabPlot 0004 -------------------------------------------------------------------- 0005 Copyright : (C) 2019 Ferencz Kovacs (kferike98@gmail.com) 0006 Description : Helper class for the welcome screen 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 * This program is distributed in the hope that it will be useful, * 0017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0019 * GNU General Public License for more details. * 0020 * * 0021 * You should have received a copy of the GNU General Public License * 0022 * along with this program; if not, write to the Free Software * 0023 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0024 * Boston, MA 02110-1301 USA * 0025 * * 0026 ***************************************************************************/ 0027 #include "WelcomeScreenHelper.h" 0028 #include "kdefrontend/DatasetModel.h" 0029 #include "kdefrontend/datasources/ImportDatasetWidget.h" 0030 #include "backend/datasources/DatasetHandler.h" 0031 0032 #include <QBuffer> 0033 #include <QDebug> 0034 #include <QFile> 0035 #include <QJsonDocument> 0036 #include <QJsonArray> 0037 #include <QJsonObject> 0038 #include <QStandardPaths> 0039 #include <QTimer> 0040 #include <QUrl> 0041 0042 #include <KConfigGroup> 0043 #include <KCompressionDevice> 0044 #include <KFilterDev> 0045 #include <KSharedConfig> 0046 0047 /*! 0048 \class WelcomeScreenHelper 0049 \brief Helper class for the welcome screen 0050 0051 \ingroup kdefrontend 0052 */ 0053 WelcomeScreenHelper::WelcomeScreenHelper() : m_datasetWidget(new ImportDatasetWidget(0)) { 0054 m_datasetWidget->hide(); 0055 0056 QIcon icon = QIcon::fromTheme("labplot-maximize"); 0057 m_maxIcon = icon.pixmap(icon.availableSizes().constFirst()); 0058 0059 icon = QIcon::fromTheme("labplot-minimize"); 0060 m_minIcon = icon.pixmap(icon.availableSizes().constFirst()); 0061 0062 m_datasetModel = new DatasetModel(m_datasetWidget->getDatasetsMap()); 0063 0064 loadConfig(); 0065 processExampleProjects(); 0066 } 0067 0068 WelcomeScreenHelper::~WelcomeScreenHelper() { 0069 //save width&height ratio values 0070 KConfigGroup conf(KSharedConfig::openConfig(), "WelcomeScreenHelper"); 0071 0072 int widthCount = m_widthScale.size(); 0073 conf.writeEntry("width_count", widthCount); 0074 int currentWidthIndex = 0; 0075 0076 for(auto item = m_widthScale.begin(); item != m_widthScale.end() && currentWidthIndex < widthCount; ++item) { 0077 conf.writeEntry("widthName_" + QString::number(currentWidthIndex), item.key()); 0078 conf.writeEntry("widthValue_" + QString::number(currentWidthIndex), QString::number(item.value())); 0079 currentWidthIndex++; 0080 } 0081 0082 int heightCount = m_heightScale.size(); 0083 conf.writeEntry("height_count", widthCount); 0084 int currentHeightIndex = 0; 0085 0086 for(auto item = m_heightScale.begin(); item != m_heightScale.end() && currentHeightIndex < heightCount; ++item) { 0087 conf.writeEntry("heightName_" + QString::number(currentHeightIndex), item.key()); 0088 conf.writeEntry("heightValue_" + QString::number(currentHeightIndex), QString::number(item.value())); 0089 currentHeightIndex++; 0090 } 0091 } 0092 0093 /** 0094 * @brief Loads the saved configuration 0095 */ 0096 void WelcomeScreenHelper::loadConfig() { 0097 KConfigGroup conf(KSharedConfig::openConfig(), "WelcomeScreenHelper"); 0098 0099 int widthCount = conf.readEntry("width_count", -1); 0100 for(int i = 0; i < widthCount; ++i) { 0101 QString id = conf.readEntry("widthName_" + QString::number(i), ""); 0102 double value = QString(conf.readEntry("widthValue_" + QString::number(i), "-1")).toDouble(); 0103 0104 if(!id.isEmpty() && value != -1) 0105 m_widthScale[id] = value; 0106 } 0107 0108 int heightCount = conf.readEntry("height_count", -1); 0109 for(int i = 0; i < heightCount; ++i) { 0110 QString id = conf.readEntry("heightName_" + QString::number(i), ""); 0111 double value = QString(conf.readEntry("heightValue_" + QString::number(i), "-1")).toDouble(); 0112 0113 if(!id.isEmpty() && value != -1) 0114 m_heightScale[id] = value; 0115 } 0116 } 0117 0118 /** 0119 * @brief Handles a dataset being clicked in the dataset section of the WelcomeScreen. 0120 * Initiates listing information about the dataset in the previously mentioned section. 0121 * 0122 * @param category the category the dataset belongs to 0123 * @param subcategory the subcategory the dataset belongs to 0124 * @param datasetName the name of the dataset 0125 */ 0126 void WelcomeScreenHelper::datasetClicked(const QString& category, const QString& subcategory, const QString& datasetName) { 0127 m_datasetWidget->setCollection("All"); 0128 m_datasetWidget->setCategory(category); 0129 m_datasetWidget->setSubcategory(subcategory); 0130 m_datasetWidget->setDataset(datasetName); 0131 m_spreadsheet.reset(new Spreadsheet(i18n("Dataset%1", 1))); 0132 0133 if(m_datasetHandler) 0134 delete m_datasetHandler; 0135 m_datasetHandler = new DatasetHandler(m_spreadsheet.get()); 0136 0137 m_datasetWidget->import(m_datasetHandler); 0138 0139 QTimer timer; 0140 timer.setSingleShot(true); 0141 QEventLoop loop; 0142 connect(m_datasetHandler, &DatasetHandler::downloadCompleted, &loop, &QEventLoop::quit); 0143 connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); 0144 timer.start(1500); 0145 loop.exec(); 0146 0147 if(timer.isActive()){ 0148 timer.stop(); 0149 emit datasetFound(); 0150 } else 0151 emit datasetNotFound(); 0152 } 0153 0154 /** 0155 * @brief Returns the dataset's full name. 0156 */ 0157 QVariant WelcomeScreenHelper::datasetName() { 0158 return QVariant(m_spreadsheet->name()); 0159 } 0160 0161 /** 0162 * @brief Returns the dataset's descripton. 0163 */ 0164 QVariant WelcomeScreenHelper::datasetDescription() { 0165 return QVariant(m_spreadsheet->comment()); 0166 } 0167 0168 /** 0169 * @brief Returns the number of the dataset's columns. 0170 */ 0171 QVariant WelcomeScreenHelper::datasetColumns() { 0172 return QVariant(m_spreadsheet->columnCount()); 0173 } 0174 0175 /** 0176 * @brief Returns the number of the dataset's rows. 0177 */ 0178 QVariant WelcomeScreenHelper::datasetRows() { 0179 return QVariant(m_spreadsheet->rowCount()); 0180 } 0181 0182 /** 0183 * @brief Returns a pointer to the spreadsheet in which the data of the dataset was loaded. 0184 */ 0185 Spreadsheet* WelcomeScreenHelper::releaseConfiguredSpreadsheet() { 0186 return m_spreadsheet.release(); 0187 } 0188 0189 /** 0190 * @brief Returns the thumbnail image saved with the project. 0191 * @param url the path to the saved project file. 0192 */ 0193 QVariant WelcomeScreenHelper::getProjectThumbnail(const QUrl& url) { 0194 QString filename; 0195 if (url.isLocalFile()) // fix for Windows 0196 filename = url.toLocalFile(); 0197 else 0198 filename = url.path(); 0199 0200 QIODevice* file; 0201 // first try gzip compression, because projects can be gzipped and end with .lml 0202 if (filename.endsWith(QLatin1String(".lml"), Qt::CaseInsensitive)) 0203 file = new KCompressionDevice(filename,KFilterDev::compressionTypeForMimeType("application/x-gzip")); 0204 else // opens filename using file ending 0205 file = new KFilterDev(filename); 0206 0207 if (!file) 0208 file = new QFile(filename); 0209 0210 if (!file->open(QIODevice::ReadOnly)) { 0211 qDebug() << "Could not open file for reading."; 0212 return QVariant(); 0213 } 0214 0215 char c; 0216 bool rc = file->getChar(&c); 0217 if (!rc) { 0218 qDebug() << "The project file is empty."; 0219 file->close(); 0220 delete file; 0221 return false; 0222 } 0223 file->seek(0); 0224 0225 //parse XML 0226 XmlStreamReader reader(file); 0227 while (!(reader.isStartDocument() || reader.atEnd())) 0228 reader.readNext(); 0229 0230 if (!(reader.atEnd())) { 0231 if (!reader.skipToNextTag()) 0232 return false; 0233 0234 if (reader.name() == "project") { 0235 QString thumbnail = reader.attributes().value("thumbnail").toString(); 0236 0237 thumbnail.prepend("data:image/jpg;base64,"); 0238 return QVariant(thumbnail); 0239 } 0240 } 0241 return QVariant(); 0242 } 0243 0244 /** 0245 * @brief Returns a pointer to the datasetModel of the class. 0246 */ 0247 DatasetModel* WelcomeScreenHelper::getDatasetModel() { 0248 return m_datasetModel; 0249 } 0250 0251 /** 0252 * @brief Processes metadata file containing example projects. 0253 */ 0254 void WelcomeScreenHelper::processExampleProjects() { 0255 0256 const QString filePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, "example_projects/example_projects.json"); 0257 QFile file(filePath); 0258 0259 if (file.open(QIODevice::ReadOnly)) { 0260 QJsonDocument document = QJsonDocument::fromJson(file.readAll()); 0261 QJsonArray exampleArray = document.array(); 0262 0263 //processing examples 0264 for(int i = 0 ; i < exampleArray.size(); ++i) { 0265 const QJsonObject currentExample = exampleArray[i].toObject(); 0266 0267 const QString exampleName = currentExample.value("name").toString(); 0268 if(m_projectNameList.contains(exampleName)) { 0269 qDebug() << "There is already an example file with this name"; 0270 } else { 0271 m_projectNameList.append(exampleName); 0272 const QString exampleFile = currentExample.value("fileName").toString(); 0273 m_pathMap[exampleName] = exampleFile; 0274 0275 //processing tags 0276 const QJsonArray tags = currentExample.value("tags").toArray(); 0277 for(int j = 0; j < tags.size(); ++j) { 0278 QString tagName = tags[j].toString(); 0279 m_tagMap[tagName].append(exampleName); 0280 m_datasetTag[exampleName].append(tagName); 0281 } 0282 } 0283 } 0284 0285 file.close(); 0286 } else { 0287 qDebug("Couldn't open dataset category file"); 0288 } 0289 } 0290 0291 /** 0292 * @brief Returns in string format the thumbnail for the given example file 0293 */ 0294 QVariant WelcomeScreenHelper::getExampleProjectThumbnail(const QString& exampleName) { 0295 const QString filePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, "example_projects/" + m_pathMap[exampleName]); 0296 return getProjectThumbnail(filePath); 0297 } 0298 0299 /** 0300 * @brief Returns the list of example projects. 0301 */ 0302 QVariant WelcomeScreenHelper::getExampleProjects() { 0303 return QVariant(m_projectNameList); 0304 } 0305 0306 /** 0307 * @brief Returns the tags of the given example project. 0308 */ 0309 QVariant WelcomeScreenHelper::getExampleProjectTags(const QString& exampleName) { 0310 QString tags; 0311 const QStringList& tagList = m_datasetTag[exampleName]; 0312 0313 for(int i = 0; i < tagList.size(); i++) { 0314 tags.append(tagList[i]); 0315 if(i < tagList.size() - 1) 0316 tags.append(", "); 0317 } 0318 0319 return QVariant(tags); 0320 } 0321 0322 /** 0323 * @brief Handles an example project being clicked in the welcome screen. 0324 * @param exampleName the name of the clicked example project 0325 */ 0326 void WelcomeScreenHelper::exampleProjectClicked(const QString& exampleName) { 0327 QString path = QStandardPaths::locate(QStandardPaths::AppDataLocation, "example_projects/" + m_pathMap[exampleName]); 0328 emit openExampleProject(path); 0329 } 0330 0331 /** 0332 * @brief Searches among the example projects based on the text introduce in the search bar of the welcome screen. 0333 * @param searchtext - the text based on which we'll have to search 0334 * @return Returns the results 0335 */ 0336 QVariant WelcomeScreenHelper::searchExampleProjects(const QString& searchtext) { 0337 QStringList results; 0338 0339 //search based on tags 0340 for(auto tag = m_tagMap.begin(); tag != m_tagMap.end(); ++tag) { 0341 if (tag.key().contains(searchtext)) { 0342 for(QString example : tag.value()) { 0343 if(!results.contains(example)) 0344 results.append(example); 0345 } 0346 } 0347 } 0348 0349 //search based on name 0350 for(QString example : m_projectNameList) { 0351 if(example.contains(searchtext) && !results.contains(example)) 0352 results.append(example); 0353 } 0354 0355 return QVariant(results); 0356 } 0357 0358 /** 0359 * @brief Sets the width scale for the given section, which will be saved. 0360 */ 0361 void WelcomeScreenHelper::setWidthScale(const QString& sectionID, double scale) { 0362 m_widthScale[sectionID] = scale; 0363 } 0364 0365 /** 0366 * @brief Sets the height scale for the given section, which will be saved. 0367 */ 0368 void WelcomeScreenHelper::setHeightScale(const QString& sectionID, double scale) { 0369 m_heightScale[sectionID] = scale; 0370 } 0371 0372 /** 0373 * @brief Returns the width scale for the given section. 0374 */ 0375 QVariant WelcomeScreenHelper::getWidthScale(const QString& sectionID) { 0376 if(m_widthScale.contains(sectionID)) 0377 return QVariant(m_widthScale[sectionID]); 0378 0379 return QVariant(-1); 0380 } 0381 0382 /** 0383 * @brief Returns the height scale for the given section. 0384 */ 0385 QVariant WelcomeScreenHelper::getHeightScale(const QString& sectionID) { 0386 if(m_heightScale.contains(sectionID)) 0387 return QVariant(m_heightScale[sectionID]); 0388 0389 return QVariant(-1);; 0390 } 0391 0392 /** 0393 * @brief Returns the maximize icon. 0394 */ 0395 QVariant WelcomeScreenHelper::getMaxIcon() { 0396 QByteArray bArray; 0397 QBuffer buffer(&bArray); 0398 buffer.open(QIODevice::WriteOnly); 0399 m_maxIcon.save(&buffer, "PNG"); 0400 QString image = QString::fromLatin1(bArray.toBase64().data()); 0401 image.prepend("data:image/png;base64,"); 0402 return QVariant(image); 0403 } 0404 0405 /** 0406 * @brief Returns the minimize icon. 0407 */ 0408 QVariant WelcomeScreenHelper::getMinIcon() { 0409 QByteArray bArray; 0410 QBuffer buffer(&bArray); 0411 buffer.open(QIODevice::WriteOnly); 0412 m_minIcon.save(&buffer, "PNG"); 0413 QString image = QString::fromLatin1(bArray.toBase64().data()); 0414 image.prepend("data:image/png;base64,"); 0415 return QVariant(image); 0416 } 0417 0418 /** 0419 * @brief Returns the go-back icon. 0420 */ 0421 QVariant WelcomeScreenHelper::getBackIcon() { 0422 QIcon icon = QIcon::fromTheme("labplot-back"); 0423 QPixmap pixmap = icon.pixmap(icon.availableSizes().constFirst()); 0424 QByteArray bArray; 0425 QBuffer buffer(&bArray); 0426 buffer.open(QIODevice::WriteOnly); 0427 pixmap.save(&buffer, "PNG"); 0428 QString image = QString::fromLatin1(bArray.toBase64().data()); 0429 image.prepend("data:image/png;base64,"); 0430 return QVariant(image); 0431 } 0432 0433 /** 0434 * @brief Returns the go-forward icon. 0435 */ 0436 QVariant WelcomeScreenHelper::getForwardIcon() { 0437 QIcon icon = QIcon::fromTheme("labplot-forward"); 0438 QPixmap pixmap = icon.pixmap(icon.availableSizes().constFirst()); 0439 QByteArray bArray; 0440 QBuffer buffer(&bArray); 0441 buffer.open(QIODevice::WriteOnly); 0442 pixmap.save(&buffer, "PNG"); 0443 QString image = QString::fromLatin1(bArray.toBase64().data()); 0444 image.prepend("data:image/png;base64,"); 0445 return QVariant(image); 0446 }