diff --git a/src/kdefrontend/datasources/ImportDatasetDialog.cpp b/src/kdefrontend/datasources/ImportDatasetDialog.cpp index 16c28a6d6..9897de8a3 100644 --- a/src/kdefrontend/datasources/ImportDatasetDialog.cpp +++ b/src/kdefrontend/datasources/ImportDatasetDialog.cpp @@ -1,127 +1,129 @@ /*************************************************************************** File : ImportDatasetDialog.cpp Project : LabPlot Description : import dataset data dialog -------------------------------------------------------------------- Copyright : (C) 2019 Ferencz Koovacs (kferike98@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "ImportDatasetDialog.h" #include "ImportDatasetWidget.h" #include "backend/datasources/DatasetHandler.h" #include "KConfigGroup" #include "KSharedConfig" #include "KWindowConfig" #include "QWindow" #include "QProgressBar" #include "QDialogButtonBox" #include "QStatusBar" #include "QDebug" /*! \class ImportDatasetDialog \brief Dialog for importing data from a dataset. Embeds \c ImportDatasetWidget and provides the standard buttons. \ingroup kdefrontend */ ImportDatasetDialog::ImportDatasetDialog(MainWin* parent, const QString& fileName) : ImportDialog(parent), m_importDatasetWidget(new ImportDatasetWidget(this)){ + Q_UNUSED(fileName); vLayout->addWidget(m_importDatasetWidget); connect(m_importDatasetWidget, &ImportDatasetWidget::datasetSelected, this, &ImportDatasetDialog::checkOkButton); connect(m_importDatasetWidget, &ImportDatasetWidget::datasetDoubleClicked, [this]() { checkOkButton(); if(okButton->isEnabled()) accept(); }); //dialog buttons QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok |QDialogButtonBox::Cancel); okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setEnabled(false); //ok is only available if a valid container was selected vLayout->addWidget(buttonBox); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); setWindowTitle(i18nc("@title:window", "Add new Dataset")); create(); QApplication::processEvents(QEventLoop::AllEvents, 0); KConfigGroup conf(KSharedConfig::openConfig(), "ImportDatasetDialog"); if (conf.exists()) { KWindowConfig::restoreWindowSize(windowHandle(), conf); resize(windowHandle()->size()); } else { resize(QSize(0, 0).expandedTo(minimumSize())); } checkOkButton(); } ImportDatasetDialog::~ImportDatasetDialog() { KConfigGroup conf(KSharedConfig::openConfig(), "ImportDatasetDialog"); KWindowConfig::saveWindowSize(windowHandle(), conf); } QString ImportDatasetDialog::selectedObject() const { return QString(); } /*! triggers the import of a dataset's data */ void ImportDatasetDialog::importToDataset(DatasetHandler* datasetHandler, QStatusBar* statusBar) const { //show a progress bar in the status bar auto* progressBar = new QProgressBar(); progressBar->setRange(0, 100); connect(datasetHandler, &DatasetHandler::downloadProgress, progressBar, &QProgressBar::setValue); statusBar->clearMessage(); statusBar->addWidget(progressBar, 1); WAIT_CURSOR; QApplication::processEvents(QEventLoop::AllEvents, 100); QTime timer; timer.start(); m_importDatasetWidget->loadDatasetToProcess(datasetHandler); statusBar->showMessage(i18n("Dataset imported in %1 seconds.", static_cast(timer.elapsed()/1000))); RESET_CURSOR; statusBar->removeWidget(progressBar); } /** * @brief Checks whether the OK button of the dialog can be pressed or not */ void ImportDatasetDialog::checkOkButton() { bool enable = (!m_importDatasetWidget->getSelectedDataset().isEmpty()); okButton->setEnabled(enable); } void ImportDatasetDialog::importTo(QStatusBar* statusBar) const { + Q_UNUSED(statusBar); } diff --git a/src/kdefrontend/datasources/ImportDatasetWidget.cpp b/src/kdefrontend/datasources/ImportDatasetWidget.cpp index af55ac56e..1ca849970 100644 --- a/src/kdefrontend/datasources/ImportDatasetWidget.cpp +++ b/src/kdefrontend/datasources/ImportDatasetWidget.cpp @@ -1,897 +1,898 @@ /*************************************************************************** File : ImportDatasetWidget.cpp Project : LabPlot Description : import online dataset widget -------------------------------------------------------------------- Copyright : (C) 2019 Kovacs Ferencz (kferike98@gmail.com) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "src/backend/datasources/DatasetHandler.h" #include "src/kdefrontend/datasources/ImportDatasetWidget.h" #include "src/kdefrontend/datasources/DatasetMetadataManagerDialog.h" #include "src/kdefrontend/DatasetModel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*! \class ImportDatasetWidget \brief Widget for importing data from a dataset. \ingroup kdefrontend */ ImportDatasetWidget::ImportDatasetWidget(QWidget* parent) : QWidget(parent), m_categoryCompleter(new QCompleter), m_datasetCompleter(new QCompleter), m_loadingCategories(false) { const QString baseDir = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).first(); QString containingDir = "labplot_data"; m_jsonDir = baseDir + QDir::separator() + containingDir + QDir::separator(); ui.setupUi(this); if(!QFile(m_jsonDir + "DatasetCollections.json").exists()) downloadCollectionsFile(); loadDatasetCategoriesFromJson(); ui.lwDatasets->setSelectionMode(QAbstractItemView::SingleSelection); ui.twCategories->setSelectionMode(QAbstractItemView::SingleSelection); ui.lDescription->setWordWrap(true); ui.lFullName->setWordWrap(true); showDetails(m_showDetails); connect(ui.cbCollections, &QComboBox::currentTextChanged, this, &ImportDatasetWidget::updateCategoryTree); connect(ui.twCategories, &QTreeWidget::itemDoubleClicked, this, &ImportDatasetWidget::listDatasetsForSubcategory); connect(ui.twCategories, &QTreeWidget::itemSelectionChanged, [this] { if(!m_loadingCategories) listDatasetsForSubcategory(ui.twCategories->selectedItems().first()); }); connect(ui.leSearchDatasets, &QLineEdit::textChanged, this, &ImportDatasetWidget::scrollToDatasetListItem); connect(ui.bClearCache, &QPushButton::clicked, this, &ImportDatasetWidget::clearCache); connect(ui.leSearchCategories, &QLineEdit::textChanged, this, &ImportDatasetWidget::scrollToCategoryTreeItem); connect(ui.bRefresh, &QPushButton::clicked, this, &ImportDatasetWidget::refreshCategories); connect(ui.bRestore, &QPushButton::clicked, this, &ImportDatasetWidget::restoreBackup); connect(ui.bNewDataset, &QPushButton::clicked, this, &ImportDatasetWidget::showDatasetMetadataManager); connect(ui.lwDatasets, &QListWidget::itemSelectionChanged, [this]() { emit datasetSelected(); if(m_showDetails) updateDetails(); }); connect(ui.lwDatasets, &QListWidget::doubleClicked, [this]() { emit datasetDoubleClicked(); }); connect(ui.bShowDetails, &QPushButton::clicked, [this]() { m_showDetails = !m_showDetails; if(m_showDetails) { ui.bShowDetails->setText("Hide details"); } else { ui.bShowDetails->setText("Show details"); } showDetails(m_showDetails); }); } ImportDatasetWidget::~ImportDatasetWidget() { if(m_categoryCompleter != nullptr) delete m_categoryCompleter; if(m_datasetCompleter != nullptr) delete m_datasetCompleter; } /** * @brief Locates in the file system the json metadata file that contains the list of categories and subcategories. * @return The location of the file */ QString ImportDatasetWidget::locateCategoryJsonFile() const { qDebug() << "Locating category file" << QStandardPaths::locate(QStandardPaths::AppDataLocation, "datasets/DatasetCategories.json"); return QStandardPaths::locate(QStandardPaths::AppDataLocation, "datasets/DatasetCategories.json"); } /** * @brief Processes the json metadata file that contains the list of categories and subcategories and their datasets. */ void ImportDatasetWidget::loadDatasetCategoriesFromJson() { QString filePath = m_jsonDir + "DatasetCollections.json"; QFile file(filePath); if (file.open(QIODevice::ReadOnly)) { m_datasetsMap.clear(); ui.cbCollections->clear(); QJsonDocument document = QJsonDocument::fromJson(file.readAll()); QJsonArray collections; if(document.isArray()) collections = document.array(); else { qDebug()<< "The DatasetCollections.json file is invalid"; return; } for (int collectionIndex = 0; collectionIndex < collections.size(); collectionIndex++) { const QString currentCollection = collections[collectionIndex].toString(); if(!QFile(m_jsonDir + currentCollection + ".json").exists()) downloadCollectionFile(currentCollection + ".json"); QFile collectionFile(m_jsonDir + currentCollection + ".json"); if (collectionFile.open(QIODevice::ReadOnly)) { QJsonDocument collectionDocument = QJsonDocument::fromJson(collectionFile.readAll()); QJsonObject collectionObject; if(collectionDocument.isObject()) { collectionObject = collectionDocument.object(); } else { qDebug()<< "The " + currentCollection + ".json file is invalid"; return; } if(collectionObject.value("collection_name").toString().compare(currentCollection) != 0) { qDebug()<< "The " + currentCollection + ".json file name is invalid"; return; } QJsonArray categoryArray = collectionObject.value("categories").toArray(); //processing categories for(int i = 0 ; i < categoryArray.size(); ++i) { const QJsonObject currentCategory = categoryArray[i].toObject(); const QString categoryName = currentCategory.value("category_name").toString(); const QJsonArray subcategories = currentCategory.value("subcategories").toArray(); //processing subcategories for(int j = 0; j < subcategories.size(); ++j) { QJsonObject currentSubCategory = subcategories[j].toObject(); QString subcategoryName = currentSubCategory.value("subcategory_name").toString(); const QJsonArray datasetArray = currentSubCategory.value("datasets").toArray(); //processing the datasets o the actual subcategory for (const auto& dataset : datasetArray) { m_datasetsMap[currentCollection][categoryName][subcategoryName].push_back(dataset.toObject().value("filename").toString()); } } } } } if(m_datasetModel != nullptr) delete m_datasetModel; m_datasetModel = new DatasetModel(m_datasetsMap); //Fill up collections combo box ui.cbCollections->addItem(QString("All (" + QString::number(m_datasetModel->allDatasetsList().toStringList().size()) + ")")); for(QString collection : m_datasetModel->collections()) ui.cbCollections->addItem(collection + " (" + QString::number(m_datasetModel->datasetCount(collection)) + ")"); updateCategoryTree(ui.cbCollections->currentText()); restoreSelectedSubcategory(ui.cbCollections->currentText()); file.close(); } else { qDebug("Couldn't open dataset collections file"); } } /** * @brief Returns the valid collection name based on given collection name (containing the count of datasets of the given collection) */ QString ImportDatasetWidget::validCollectionName(const QString &collection) { int index = collection.lastIndexOf(" ("); QString collectionName = collection.left(index); return collectionName; } /** * @brief Updates/fills ui.twCategories based on the selected collection. */ void ImportDatasetWidget::updateCategoryTree(const QString& collectionName) { QString collection = validCollectionName(collectionName); m_loadingCategories = true; ui.lwDatasets->clear(); ui.twCategories->clear(); QStringList categories = (collection.compare("All") == 0) ? m_datasetModel->allCategories().toStringList() : m_datasetModel->categories(collection); //Go through every category that was previously processed. for(auto category : categories) { QStringList categoryList(category); categoryList.append(QString::number(m_datasetModel->datasetCount(collection, category))); QTreeWidgetItem* const currentCategoryItem = new QTreeWidgetItem(categoryList); ui.twCategories->addTopLevelItem(currentCategoryItem); QStringList subcategories = (collection.compare("All") == 0) ? m_datasetModel->allSubcategories(category).toStringList() : m_datasetModel->subcategories(collection, category); //Go through every subcategory of the current category, that was previously processed. for(auto subcategory : subcategories) { QStringList subcategoryList(subcategory); subcategoryList.append(QString::number(m_datasetModel->datasetCount(collection, category, subcategory))); currentCategoryItem->addChild(new QTreeWidgetItem(QStringList(subcategoryList))); } } if(m_selectedCollection.compare(collection) == 0) { restoreSelectedSubcategory(ui.cbCollections->currentText()); } else { m_selectedCollection = collection; m_selectedCategory = ""; m_selectedSubcategory = ""; } m_loadingCategories = false; updateCategoryCompleter(); } /** * @brief Restores the lastly selected collection, category and subcategory making it the selected QTreeWidgetItem and also lists the datasets belonigng to it */ void ImportDatasetWidget::restoreSelectedSubcategory(const QString& collectionName) { QString collection = validCollectionName(collectionName); ui.cbCollections->setCurrentText(collection); if(m_datasetModel->categories(collection).contains(m_selectedCategory)) { const QTreeWidgetItem* const categoryItem = ui.twCategories->findItems(m_selectedCategory, Qt::MatchExactly).first(); if(m_datasetModel->subcategories(collection, m_selectedCategory).contains(m_selectedSubcategory)) { for(int i = 0; i < categoryItem->childCount(); ++i) { if(categoryItem->child(i)->text(0).compare(m_selectedSubcategory) == 0) { QTreeWidgetItem* const subcategoryItem = categoryItem->child(i); ui.twCategories->setCurrentItem(subcategoryItem); subcategoryItem->setSelected(true); m_selectedSubcategory.clear(); listDatasetsForSubcategory(subcategoryItem); break; } } } } } /** * @brief Populates lwDatasets with the datasets of the selected subcategory. * @param item the selected subcategory */ void ImportDatasetWidget::listDatasetsForSubcategory(QTreeWidgetItem* item) { if(item->childCount() == 0) { if(m_selectedSubcategory.compare(item->text(0)) != 0) { m_selectedSubcategory = item->text(0); m_selectedCategory = item->parent()->text(0); QString categoryName = item->parent()->text(0); ui.lwDatasets->clear(); for(QString dataset : m_datasetModel->datasets(m_selectedCollection, categoryName, m_selectedSubcategory)) { ui.lwDatasets->addItem(new QListWidgetItem(dataset)); } updateDatasetCompleter(); highlightLocalMetadataFiles(); } } else { if(item->text(0).compare(m_selectedCategory) != 0) { m_selectedCategory = item->text(0); m_selectedSubcategory = ""; ui.lwDatasets->clear(); item->setExpanded(true); } } } /** * @brief Updates the completer used for searching among datasets. */ void ImportDatasetWidget::updateDatasetCompleter() { QStringList datasetList; for(int i = 0; i count(); ++i) { datasetList.append(ui.lwDatasets->item(i)->text()); } if(!datasetList.isEmpty()) { if(m_datasetCompleter != nullptr) delete m_datasetCompleter; m_datasetCompleter = new QCompleter(datasetList); m_datasetCompleter->setCompletionMode(QCompleter::PopupCompletion); m_datasetCompleter->setCaseSensitivity(Qt::CaseSensitive); ui.leSearchDatasets->setCompleter(m_datasetCompleter); } else ui.leSearchDatasets->setCompleter(nullptr); } /** * @brief Updates the completer used for searching among categories and subcategories. */ void ImportDatasetWidget::updateCategoryCompleter() { QStringList categoryList; for (int i = 0; i < ui.twCategories->topLevelItemCount(); ++i) { categoryList.append(ui.twCategories->topLevelItem(i)->text(0)); for(int j = 0; j < ui.twCategories->topLevelItem(i)->childCount(); ++j) { categoryList.append(ui.twCategories->topLevelItem(i)->text(0) + QLatin1Char(':') + ui.twCategories->topLevelItem(i)->child(j)->text(0)); } } if(!categoryList.isEmpty()) { if(m_categoryCompleter != nullptr) delete m_categoryCompleter; m_categoryCompleter = new QCompleter(categoryList); m_categoryCompleter->setCompletionMode(QCompleter::PopupCompletion); m_categoryCompleter->setCaseSensitivity(Qt::CaseSensitive); ui.leSearchCategories->setCompleter(m_categoryCompleter); } else ui.leSearchCategories->setCompleter(nullptr); } /** * @brief Scrolls the twCategories to the given category or subcategory * @param rootName the name of the category or category+subcategory */ void ImportDatasetWidget::scrollToCategoryTreeItem(const QString& rootName) { int topItemIdx = -1; for (int i = 0; i < ui.twCategories->topLevelItemCount(); ++i) if (rootName.startsWith(ui.twCategories->topLevelItem(i)->text(0))) { topItemIdx = i; break; } if (topItemIdx >= 0) { if(!rootName.contains(QLatin1Char(':'))) { ui.twCategories->scrollToItem(ui.twCategories->topLevelItem(topItemIdx), QAbstractItemView::ScrollHint::PositionAtTop); } else { int childIdx = -1; for(int j = 0; j < ui.twCategories->topLevelItem(topItemIdx)->childCount(); ++j) { if(rootName.endsWith(ui.twCategories->topLevelItem(topItemIdx)->child(j)->text(0))) { childIdx = j; break; } } if(childIdx >= 0) { ui.twCategories->scrollToItem(ui.twCategories->topLevelItem(topItemIdx)->child(childIdx), QAbstractItemView::ScrollHint::PositionAtTop); } else { ui.twCategories->scrollToItem(ui.twCategories->topLevelItem(topItemIdx), QAbstractItemView::ScrollHint::PositionAtTop); } } } } /** * @brief Scrolls the lwDatasets to the given dataset name. * @param rootName the name of the dataset */ void ImportDatasetWidget::scrollToDatasetListItem(const QString& rootName) { int itemIdx = -1; for (int i = 0; i < ui.lwDatasets->count(); ++i) if (ui.lwDatasets->item(i)->text() == rootName) { itemIdx = i; break; } if (itemIdx >= 0) ui.lwDatasets->scrollToItem(ui.lwDatasets->item(itemIdx), QAbstractItemView::ScrollHint::PositionAtTop); } /** * @brief Returns the name of the selected dataset */ QString ImportDatasetWidget::getSelectedDataset() const { if (ui.lwDatasets->selectedItems().count() > 0) return ui.lwDatasets->selectedItems().at(0)->text(); else return QString(); } /** * @brief Initiates the processing of the dataset's metadata file and of the dataset itself. * @param datasetHandler the DatasetHanlder that downloads processes the dataset */ void ImportDatasetWidget::loadDatasetToProcess(DatasetHandler* datasetHandler) { const QString fileName = getSelectedDataset() + QLatin1String(".json"); QString filePath = m_jsonDir; QJsonObject datasetObject = loadDatasetObject(); if(!datasetObject.isEmpty()) { datasetHandler->processMetadata(datasetObject, filePath); } else { QMessageBox::critical(this, i18n("Invalid metadata file"), i18n("The metadata file for the choosen dataset isn't valid")); } } /** * @brief Returns the QJsonObject associated with the currently selected dataset. */ QJsonObject ImportDatasetWidget::loadDatasetObject() { QString filePath = m_jsonDir + "DatasetCollections.json"; QFile file(filePath); bool allCollections = (m_selectedCollection.compare("All") == 0); if (file.open(QIODevice::ReadOnly)) { QJsonDocument document = QJsonDocument::fromJson(file.readAll()); QJsonArray collections; if(document.isArray()) collections = document.array(); else { qDebug()<< "The DatasetCollections.json file is invalid"; return QJsonObject(); } for (int collectionIndex = 0; collectionIndex < collections.size(); collectionIndex++) { const QString currentCollection = collections[collectionIndex].toString(); //we have to find the selected collection in the metadata file. if(currentCollection.compare(m_selectedCollection) == 0 || allCollections) { QFile collectionFile(m_jsonDir + currentCollection + ".json"); //open the metadata file of the current collection if (collectionFile.open(QIODevice::ReadOnly)) { QJsonDocument collectionDocument = QJsonDocument::fromJson(collectionFile.readAll()); QJsonObject collectionObject; if(collectionDocument.isObject()) { collectionObject = collectionDocument.object(); } else { qDebug()<< "The " + currentCollection + ".json file is invalid"; return QJsonObject(); } if(collectionObject.value("collection_name").toString().compare(currentCollection) != 0) { qDebug()<< "The " + currentCollection + ".json file's name is invalid"; return QJsonObject(); } QJsonArray categoryArray = collectionObject.value("categories").toArray(); //processing categories for(int i = 0 ; i < categoryArray.size(); ++i) { const QJsonObject currentCategory = categoryArray[i].toObject(); const QString categoryName = currentCategory.value("category_name").toString(); if(categoryName.compare(m_selectedCategory) == 0) { const QJsonArray subcategories = currentCategory.value("subcategories").toArray(); //processing subcategories for(int j = 0; j < subcategories.size(); ++j) { QJsonObject currentSubCategory = subcategories[j].toObject(); QString subcategoryName = currentSubCategory.value("subcategory_name").toString(); if(subcategoryName.compare(m_selectedSubcategory) == 0) { const QJsonArray datasetArray = currentSubCategory.value("datasets").toArray(); //processing the datasets o the actual subcategory for (const auto& dataset : datasetArray) { if(getSelectedDataset().compare(dataset.toObject().value("filename").toString()) == 0) return dataset.toObject(); } } } } } } } } } return QJsonObject(); } /** * @brief Opens the DatasetMetadataManagerDialog when the user wants to add a new dataset. */ void ImportDatasetWidget::showDatasetMetadataManager() { DatasetMetadataManagerDialog* dlg = new DatasetMetadataManagerDialog(this, m_datasetsMap); if (dlg->exec() == QDialog::Accepted) { const QString pathToJson = m_jsonDir + QLatin1String("DatasetCategories.json"); const QString dirPath = QFileInfo(pathToJson).dir().absolutePath(); //update the metadata document dlg->updateDocument(m_jsonDir); //Not working due to problems with KNS3 library /*uploadCategoryFile(); uploadDatasetFile(dlg->getMetadataFilePath());*/ //process the changes made in the metadata files loadDatasetCategoriesFromJson(); } delete dlg; } /** * @brief Places the metadata file containing the list of collections into a specific directory. */ void ImportDatasetWidget::downloadCollectionsFile() { const QString fileNameOld = QStandardPaths::locate(QStandardPaths::AppDataLocation, "datasets/DatasetCollections.json"); const QString fileNameNew =m_jsonDir + QLatin1String("DatasetCollections.json"); const QString parentDir = m_jsonDir.left(m_jsonDir.left(m_jsonDir.length() - 1).lastIndexOf(QDir::separator())); if(!QDir(m_jsonDir).exists()) { qDebug() << parentDir; QDir(parentDir).mkdir(QLatin1String("labplot_data")); } QFile::copy(fileNameOld, fileNameNew); } /** * @brief Places the metadata file of the given dataset into a specific directory. * @param datasetName the name of the dataset */ void ImportDatasetWidget::downloadCollectionFile(const QString& collectionName) { const QString fileNameOld = QStandardPaths::locate(QStandardPaths::AppDataLocation, QLatin1String("datasets") + QDir::separator() + collectionName); const QString fileNameNew =m_jsonDir + collectionName; QFile::copy(fileNameOld, fileNameNew); } /** * @brief Refreshes the categories, subcategories and datasets. */ void ImportDatasetWidget::refreshCategories() { QMessageBox::StandardButton reply; reply = QMessageBox::question(this, "Refresh metadata files", "Are you sure to refresh all of the metadata files? (every change will be removed, but a backup will be created)", QMessageBox::Yes|QMessageBox::No); if(reply == QMessageBox::Yes) { QString fileNameNew = m_jsonDir + QLatin1String("DatasetCollections.json"); QFile existingCategoriesFile(fileNameNew); if(existingCategoriesFile.exists()) { //Delete old backup QFile oldBackup(m_jsonDir + QLatin1String("DatasetCollections_backup.json")); if(oldBackup.exists()) { oldBackup.remove(); } oldBackup.close(); //Create new backup if(!existingCategoriesFile.rename(m_jsonDir + QLatin1String("DatasetCollections_backup.json"))) qDebug() << " Couldn't create backup because " << existingCategoriesFile.errorString(); } //Obtain the new file downloadCollectionsFile(); QString filePath = m_jsonDir + "DatasetCollections.json"; QFile file(filePath); if (file.open(QIODevice::ReadOnly)) { m_datasetsMap.clear(); QJsonDocument document = QJsonDocument::fromJson(file.readAll()); QJsonArray collections; if(document.isArray()) collections = document.array(); else { qDebug()<< "The DatasetCollections.json file is invalid"; return; } //Go trough every collection's metadata file for (int collectionIndex = 0; collectionIndex < collections.size(); collectionIndex++) { const QString currentCollection = collections[collectionIndex].toString(); QFile existingCollectionFile(m_jsonDir + currentCollection + ".json"); //we copy the file to the data location if it doesn't exist if(!existingCollectionFile.exists()) { downloadCollectionFile(currentCollection + ".json"); } //otherwise we have to create a backup first else { QFile oldBackupCollection(m_jsonDir + currentCollection + "_backup.json"); if(oldBackupCollection.exists()) { oldBackupCollection.remove(); } oldBackupCollection.close(); if(!existingCollectionFile.rename(m_jsonDir + currentCollection + "_backup.json")) qDebug() << " Couldn't create backup because " << existingCollectionFile.errorString(); downloadCollectionFile(currentCollection + ".json"); } } } //process the "refreshed" files and update the widget accordingly loadDatasetCategoriesFromJson(); } } void ImportDatasetWidget::restoreBackup() { QMessageBox::StandardButton reply; reply = QMessageBox::question(this, "Restore backup", "Are you sure to restore the backup metadata files?", QMessageBox::Yes|QMessageBox::No); if(reply == QMessageBox::Yes) { //Restore the collection list first QFile backup(m_jsonDir + QLatin1String("DatasetCollections_backup.json")); if(backup.exists()) { QFile deleteFile(m_jsonDir + QLatin1String("DatasetCollections.json")); deleteFile.remove(); if(!backup.rename(m_jsonDir + QLatin1String("DatasetCollections.json"))) { qDebug() << " Couldn't create backup because " << backup.errorString(); downloadCollectionsFile(); } } QString filePath = m_jsonDir + "DatasetCollections.json"; QFile file(filePath); if (file.open(QIODevice::ReadOnly)) { m_datasetsMap.clear(); QJsonDocument document = QJsonDocument::fromJson(file.readAll()); QJsonArray collections; if(document.isArray()) collections = document.array(); else { qDebug()<< "The DatasetCollections.json file is invalid"; return; } //Restore every collection's metadata file for (int collectionIndex = 0; collectionIndex < collections.size(); collectionIndex++) { const QString currentCollection = collections[collectionIndex].toString(); QFile backupCollection(m_jsonDir + currentCollection + "_backup.json"); if(backupCollection.exists()) { QFile collectionFile(m_jsonDir + currentCollection + ".json"); collectionFile.remove(); if(!backupCollection.rename(m_jsonDir + currentCollection + ".json")) { qDebug() << " Couldn't create backup because " << backupCollection.errorString(); downloadCollectionFile(currentCollection + ".json"); } } } } //process the restored files and update the widget accordingly loadDatasetCategoriesFromJson(); } } /** * @brief Clears the content of the directory in which the download of metadata files was done. */ void ImportDatasetWidget::clearCache() { QMessageBox::StandardButton reply; reply = QMessageBox::question(this, "Clear cache", "Are you sure to remove every downloaded dataset?", QMessageBox::Yes|QMessageBox::No); if(reply == QMessageBox::Yes) { QDir dir(m_jsonDir); if(dir.exists()) { for(const auto& entry : dir.entryList()) { //delete every file that isn't potentially a metadata file if(!(entry.endsWith(QLatin1String(".json")) || entry.startsWith(QLatin1Char('.')))) { QFile deleteFile (m_jsonDir + entry); if(deleteFile.exists()) { deleteFile.remove(); } } } } else { qDebug("Couldn't clear cache, containing folder doesn't exist!"); } highlightLocalMetadataFiles(); } } /** * @brief Highlights the name of the locally available metadata files in lwDatasets. */ void ImportDatasetWidget::highlightLocalMetadataFiles() { QDir dir(m_jsonDir); for(int i = 0 ; i < ui.lwDatasets->count(); ++i) { QListWidgetItem* const currentItem = ui.lwDatasets->item(i); bool found = false; for(QString entry : dir.entryList()) { if(entry.startsWith(currentItem->text()) && !entry.endsWith(".json")) { found = true; break; } } if(found) currentItem->setBackgroundColor(Qt::yellow); else currentItem->setBackgroundColor(Qt::white); } } /** * @brief TODO: uploads the metadata file that contains the categories to store.kde.org -- Library doesn't work for indefinite time. */ void ImportDatasetWidget::uploadCategoryFile() { /*KNS3::UploadDialog dialog("labplot2_datasets.knsrc", this); QFile file(m_jsonDir + "DatasetCategories.json"); qDebug() << "file " << m_jsonDir + "DatasetCategories.json "<< file.exists(); qDebug() << "file can be opened: " << file.open(QIODevice::ReadOnly) << " " << file.errorString(); file.close(); QUrl payloadFile ="file:" + m_jsonDir + "DatasetCategories.json"; QFile file2(payloadFile.toLocalFile()); qDebug() << "Local file: " << payloadFile.toLocalFile(); if (!file2.open(QIODevice::ReadOnly)) { qDebug() << i18n("File not found: %1 ", payloadFile.url()); } else { qDebug() << i18n("File found: %1 ", payloadFile.url()); } file2.close(); dialog.setUploadFile("file:" + m_jsonDir + "DatasetCategories.json"); qDebug("Upload file set!"); dialog.setUploadName("Dataset Categories"); qDebug() << "Upload name set: "; dialog.exec();*/ } /** * @brief TODO: uploads the metadata file of a dataset to store.kde.org -- Library doesn't work for indefinite time. */ void ImportDatasetWidget::uploadDatasetFile(const QString& filePath) { + Q_UNUSED(filePath); /*KNS3::UploadDialog dialog("labplot2_datasets.knsrc", this); QFile file(filePath); qDebug() << filePath + " " << file.exists(); qDebug() << "file can be opened: " << file.open(QIODevice::ReadOnly) << " " << file.errorString(); file.close(); QUrl payloadFile ="file:" + filePath; QFile file2(payloadFile.toLocalFile()); qDebug() << "Local file: " << payloadFile.toLocalFile(); if (!file2.open(QIODevice::ReadOnly)) { qDebug() << i18n("File not found: %1 ", payloadFile.url()); } else { qDebug() << i18n("File found: %1 ", payloadFile.url()); } file2.close(); dialog.setUploadFile("file:" + filePath); qDebug("Upload file set!"); dialog.setUploadName("Dataset Categories"); qDebug() << "Upload name set: "; dialog.exec();*/ } /** * @brief Returns the structure containing the categories, subcategories and datasets. * @return the structure containing the categories, subcategories and datasets */ const QMap< QString, QMap>>>& ImportDatasetWidget::getDatasetsMap() { return m_datasetsMap; } /** * @brief Sets the currently selected collection * @param category the name of the collection */ void ImportDatasetWidget::setCollection(const QString& collection) { ui.cbCollections->setCurrentText(collection + " (" + QString(m_datasetModel->datasetCount(collection)) + ")"); } /** * @brief Sets the currently selected category * @param category the name of the category */ void ImportDatasetWidget::setCategory(const QString &category) { for(int i = 0; i < ui.twCategories->topLevelItemCount(); i++) { if (ui.twCategories->topLevelItem(i)->text(0).compare(category) == 0) { listDatasetsForSubcategory(ui.twCategories->topLevelItem(i)); break; } } } /** * @brief Sets the currently selected subcategory * @param subcategory the name of the subcategory */ void ImportDatasetWidget::setSubcategory(const QString &subcategory) { for(int i = 0; i < ui.twCategories->topLevelItemCount(); i++) { if (ui.twCategories->topLevelItem(i)->text(0).compare(m_selectedCategory) == 0) { QTreeWidgetItem* categoryItem = ui.twCategories->topLevelItem(i); for(int j = 0; j childCount(); j++) { if(categoryItem->child(j)->text(0).compare(subcategory) == 0) { listDatasetsForSubcategory(categoryItem->child(j)); break; } } break; } } } /** * @brief Sets the currently selected dataset * @param the currently selected dataset */ void ImportDatasetWidget::setDataset(const QString &datasetName) { for(int i = 0; i < ui.lwDatasets->count() ; i++) { if(ui.lwDatasets->item(i)->text().compare(datasetName) == 0) { ui.lwDatasets->item(i)->setSelected(true); break; } } } /** * @brief Updates the details of the currently selected dataset */ void ImportDatasetWidget::updateDetails() { if(!getSelectedDataset().isEmpty()) { QJsonObject datasetObject = loadDatasetObject(); ui.lFullName->setText(datasetObject.value("name").toString()); ui.lDescription->setText(datasetObject.value("description").toString()); } else { ui.lFullName->setText("-"); ui.lDescription->setText("-"); } } /** * @brief Hides or displays the details of the currently selected dataset * @param show boolean value determining to show or not the details. */ void ImportDatasetWidget::showDetails(bool show) { ui.saDetails->setEnabled(show); ui.saDetails->setVisible(show); if(show) updateDetails(); } /** * @brief Returns the directory in which the metadata json files are locating. */ const QString ImportDatasetWidget::getJsonDir() { return m_jsonDir; } diff --git a/src/kdefrontend/main.qml b/src/kdefrontend/main.qml index 2bfe91901..9dfe7e2d2 100644 --- a/src/kdefrontend/main.qml +++ b/src/kdefrontend/main.qml @@ -1,1925 +1,1992 @@ import QtQuick.Window 2.12 import QtQuick 2.6 import QtQuick.Controls 2.4 import QtQuick.Scene2D 2.9 import QtQuick.Controls.Universal 2.0 import QtQuick.Extras 1.4 import QtQuick.Layouts 1.3 import QtWebView 1.1 import QtWebEngine 1.8 //import labplot.datasetmodel 1.0 Rectangle { id: mainWindow width: 1920 height: 1080 property int spacing: 10 visible: true property string currentCategory: '' property string currentSubcategory: '' property string currentDataset: '' property string initialUrl : "https://labplot.kde.org/2019/04/19/labplot-2-6-released/" property alias mainWindow: mainWindow signal recentProjectClicked(url path) signal datasetClicked(string category, string subcategory, string dataset) signal openDataset() signal openExampleProject(string name) function restoreOriginalLayout() { console.log("Restore widget dimensions") recentProjectsFrame.widthRate = (mainWindow.width / 5 - 4*mainWindow.spacing)/ mainWindow.width recentProjectsFrame.heightRate = (mainWindow.height / 4 - 4*mainWindow.spacing)/ mainWindow.height exampleProjects.widthRate = (3 * mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width exampleProjects.heightRate =(mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height newsSection.widthRate = (mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width newsSection.heightRate = (mainWindow.height- 4*mainWindow.spacing) / mainWindow.height helpFrame.widthRate = (mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width helpFrame.heightRate = (mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height datasetFrame.widthRate = (3 * mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width datasetFrame.heightRate = (mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height releaseSection.widthRate = (4 * mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width releaseSection.heightRate = (2*mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height } function saveWidgetDimensions() { console.log("Save welcome screen widget dimensions") + + if(recentProjectsFrame.fullScreen) + recentProjectsFrame.minimize() + + if(exampleProjects.fullScreen) + exampleProjects.minimize() + + if(newsSection.fullScreen) + newsSection.minimize() + + if(helpFrame.fullScreen) + helpFrame.minimize() + + if(datasetFrame.fullScreen) + datasetFrame.minimize() + + if(releaseSection.fullScreen) + releaseSection.minimize() + helper.setHeightScale(recentProjectsFrame.sectionName, recentProjectsFrame.heightRate) helper.setWidthScale(recentProjectsFrame.sectionName, recentProjectsFrame.widthRate) helper.setHeightScale(exampleProjects.sectionName, exampleProjects.heightRate) helper.setWidthScale(exampleProjects.sectionName, exampleProjects.widthRate) helper.setHeightScale(newsSection.sectionName, newsSection.heightRate) helper.setWidthScale(newsSection.sectionName, newsSection.widthRate) helper.setHeightScale(helpFrame.sectionName, helpFrame.heightRate) helper.setWidthScale(helpFrame.sectionName, helpFrame.widthRate) helper.setHeightScale(datasetFrame.sectionName, datasetFrame.heightRate) helper.setWidthScale(datasetFrame.sectionName, datasetFrame.widthRate) helper.setHeightScale(releaseSection.sectionName, releaseSection.heightRate) helper.setWidthScale(releaseSection.sectionName, releaseSection.widthRate) } function hideTiles() { recentProjectsFrame.visible = false recentProjectsFrame.z = 0 exampleProjects.visible = false exampleProjects.z = 0 newsSection.visible = false newsSection.z = 0 helpFrame.visible = false helpFrame.z = 0 datasetFrame.visible = false datasetFrame.z = 0 releaseSection.visible = false releaseSection.z = 0 } function showTiles() { recentProjectsFrame.visible = true recentProjectsFrame.z = 0 exampleProjects.visible = true exampleProjects.z = 0 newsSection.visible = true newsSection.z = 0 helpFrame.visible = true helpFrame.z = 0 datasetFrame.visible = true datasetFrame.z = 0 releaseSection.visible = true releaseSection.z = 0 } Connections { target: helper onDatasetFound:{ datasetTitle.text = helper.datasetName() datasetDescription.text = helper.datasetDescription() datasetRows.text = helper.datasetRows() datasetColumns.text = helper.datasetColumns() } onDatasetNotFound:{ datasetTitle.text = "-" datasetDescription.text = "-" datasetRows.text = "-" datasetColumns.text = "-"; } onShowFirstDataset:{ datasetClicked(mainWindow.currentCategory, mainWindow.currentSubcategory, mainWindow.currentDataset) } } Frame { id: recentProjectsFrame property string sectionName: "recentProjectsFrame" property double widthRate : helper.getWidthScale(sectionName) === -1 ? (mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width : helper.getWidthScale(sectionName) property double heightRate : helper.getHeightScale(sectionName) === -1 ? (mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height : helper.getHeightScale(sectionName) width: mainWindow.width * widthRate height: mainWindow.height * heightRate anchors.top: parent.top anchors.topMargin: mainWindow.spacing anchors.left: parent.left anchors.leftMargin: mainWindow.spacing visible: true opacity: 1 padding: 5 property bool fullScreen: false property double prevWidth: 0 property double prevHeight: 0 Component.onCompleted: { if(helper.getWidthScale(sectionName) === -1 || helper.getHeightScale(sectionName) === -1) mainWindow.restoreOriginalLayout() } function maximize() { hideTiles() recentProjectsFrame.prevWidth = recentProjectsFrame.widthRate recentProjectsFrame.prevHeight = recentProjectsFrame.heightRate recentProjectsFrame.visible = true recentProjectsFrame.z = 1 recentProjectsFrame.anchors.fill = undefined recentProjectsFrame.anchors.right = undefined recentProjectsFrame.anchors.bottom = undefined recentProjectsFrame.anchors.centerIn = undefined recentProjectsFrame.anchors.top = undefined recentProjectsFrame.anchors.left = undefined recentProjectsFrame.widthRate = 1 recentProjectsFrame.heightRate = 1 recentProjectsFrame.anchors.fill = mainWindow } function minimize() { recentProjectsFrame.anchors.fill = undefined recentProjectsFrame.anchors.right = undefined recentProjectsFrame.anchors.bottom = undefined recentProjectsFrame.anchors.centerIn = undefined recentProjectsFrame.anchors.top = undefined recentProjectsFrame.anchors.left = undefined recentProjectsFrame.anchors.top = mainWindow.top recentProjectsFrame.anchors.topMargin = mainWindow.spacing recentProjectsFrame.anchors.left = mainWindow.left recentProjectsFrame.anchors.leftMargin = mainWindow.spacing recentProjectsFrame.widthRate = recentProjectsFrame.prevWidth recentProjectsFrame.heightRate = recentProjectsFrame.prevHeight showTiles(); } Rectangle { width: 3 height: parent.height color: "gray" anchors.left: parent.right anchors.rightMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.XAxis;} onMouseXChanged: { if(drag.active){ recentProjectsFrame.widthRate = (recentProjectsFrame.width + mouseX) / mainWindow.width exampleProjects.widthRate = (exampleProjects.width - mouseX) / mainWindow.width if(recentProjectsFrame.width < 150){ recentProjectsFrame.widthRate = 150 / mainWindow.width exampleProjects.widthRate = (mainWindow.width - newsSection.width - 150 - 4*mainWindow.spacing) / mainWindow.width } if(exampleProjects.width < 300) { exampleProjects.widthRate = 300 / mainWindow.width recentProjectsFrame.widthRate = (mainWindow.width - newsSection.width - 300 - 4*mainWindow.spacing) / mainWindow.width } } } } } Rectangle { height: 3 width : parent.width color: "gray" anchors.top: parent.bottom anchors.bottomMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.YAxis } onMouseYChanged: { if(drag.active){ recentProjectsFrame.heightRate = (recentProjectsFrame.height + mouseY) / mainWindow.height exampleProjects.heightRate = (exampleProjects.height + mouseY) / mainWindow.height helpFrame.heightRate = (helpFrame.height - mouseY) / mainWindow.height datasetFrame.heightRate = (datasetFrame.height - mouseY) / mainWindow.height if(recentProjectsFrame.height < 100 || exampleProjects.height < 100) { recentProjectsFrame.heightRate = 100 / mainWindow.height exampleProjects.heightRate = 100 / mainWindow.height helpFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height datasetFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height } if(helpFrame.height < 100 || datasetFrame.height < 100) { helpFrame.heightRate = 100 / mainWindow.height datasetFrame.heightRate = 100 / mainWindow.height recentProjectsFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height exampleProjects.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height } } } } } ColumnLayout { anchors.fill: parent spacing: 20 clip: true RowLayout { Layout.fillWidth: true Layout.minimumHeight: Math.min(parent.height*0.2, 100) Layout.preferredHeight: Math.min(parent.height*0.2, 100) Image { Layout.preferredHeight: recentProjectsFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumHeight: recentProjectsFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.preferredWidth: recentProjectsFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumWidth: recentProjectsFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.alignment: Qt.AlignVCenter source: recentProjectsFrame.fullScreen ? helper.getMinIcon() : helper.getMaxIcon() sourceSize.width: recentProjectsFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) sourceSize.height: recentProjectsFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) MouseArea { anchors.fill: parent onClicked: { if(!recentProjectsFrame.fullScreen) { recentProjectsFrame.maximize() } else { recentProjectsFrame.minimize() } recentProjectsFrame.fullScreen = !recentProjectsFrame.fullScreen } } } Label { color: "#000000" text: qsTr("Recent Projects") styleColor: "#979191" opacity: 1 visible: true font.underline: false font.italic: false font.bold: false verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.pointSize: recentProjectsFrame.fullScreen ? 60 : 24 minimumPointSize: 10 fontSizeMode: Text.Fit Layout.fillWidth: true Layout.fillHeight: true wrapMode: Text.WordWrap } } RecentProjects { id: recentProjectsList model:recentProjects Layout.fillHeight: true Layout.fillWidth: true Layout.minimumHeight: parent.height*0.8 Layout.preferredHeight: parent.height*0.8 clip: true } } } Frame { id: exampleProjects property string sectionName: "exampleProjects" property double widthRate : helper.getWidthScale(sectionName) === -1 ? (3 * mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width : helper.getWidthScale(sectionName) property double heightRate : helper.getHeightScale(sectionName) === -1 ? (mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height : helper.getHeightScale(sectionName) width: mainWindow.width * widthRate height: mainWindow.height * heightRate anchors.top: parent.top anchors.topMargin: mainWindow.spacing anchors.left: recentProjectsFrame.right anchors.leftMargin: mainWindow.spacing anchors.right: newsSection.left anchors.rightMargin: mainWindow.spacing visible: true clip: true opacity: 1 padding: 5 property bool fullScreen: false property double prevWidth: 0 property double prevHeight: 0 Component.onCompleted: { if(helper.getWidthScale(sectionName) === -1 || helper.getHeightScale(sectionName) === -1) mainWindow.restoreOriginalLayout() } function maximize() { hideTiles() exampleProjects.prevWidth = exampleProjects.widthRate exampleProjects.prevHeight = exampleProjects.heightRate exampleProjects.visible = true exampleProjects.z = 1 exampleProjects.anchors.fill = undefined exampleProjects.anchors.right = undefined exampleProjects.anchors.bottom = undefined exampleProjects.anchors.centerIn = undefined exampleProjects.anchors.top = undefined exampleProjects.anchors.left = undefined exampleProjects.widthRate = 1 exampleProjects.heightRate = 1 exampleProjects.anchors.fill = mainWindow } function minimize() { exampleProjects.anchors.fill = undefined exampleProjects.anchors.right = undefined exampleProjects.anchors.bottom = undefined exampleProjects.anchors.centerIn = undefined exampleProjects.anchors.top = undefined exampleProjects.anchors.left = undefined exampleProjects.anchors.top = mainWindow.top exampleProjects.anchors.topMargin = mainWindow.spacing exampleProjects.anchors.left = recentProjectsFrame.right exampleProjects.anchors.leftMargin = mainWindow.spacing exampleProjects.anchors.right = newsSection.left exampleProjects.anchors.rightMargin = mainWindow.spacing exampleProjects.widthRate = exampleProjects.prevWidth exampleProjects.heightRate = exampleProjects.prevHeight showTiles(); } Rectangle { width: 3 height: parent.height color: "gray" anchors.left: parent.right anchors.rightMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.XAxis } onMouseXChanged: { if(drag.active){ newsSection.widthRate = (newsSection.width - mouseX) / mainWindow.width exampleProjects.widthRate = (exampleProjects.width + mouseX) / mainWindow.width datasetFrame.widthRate = (datasetFrame.width + mouseX) / mainWindow.width releaseSection.widthRate = (releaseSection.width + mouseX) / mainWindow.width if(exampleProjects.width < 300 || datasetFrame.width < 300){ newsSection.widthRate = (mainWindow.width - Math.max(recentProjectsFrame.width, helpFrame.width) - 300 - 4*mainWindow.spacing) / mainWindow.width exampleProjects.widthRate = (mainWindow.width - newsSection.width - recentProjectsFrame.width - 4*mainWindow.spacing) / mainWindow.width datasetFrame.widthRate = (mainWindow.width - newsSection.width - helpFrame.width - 4*mainWindow.spacing) / mainWindow.width releaseSection.widthRate = (Math.max(recentProjectsFrame.width, helpFrame.width) + mainWindow.spacing + 300) / mainWindow.width } if(newsSection.width < 150) { newsSection.widthRate = 150 / mainWindow.width exampleProjects.widthRate = (mainWindow.width - recentProjectsFrame.width - 150 - 4*mainWindow.spacing) / mainWindow.width datasetFrame.widthRate =(mainWindow.width - helpFrame.width - 150 - 4*mainWindow.spacing) / mainWindow.width releaseSection.widthRate = (mainWindow.width - newsSection.width - 3*mainWindow.spacing) / mainWindow.width } } } } } Rectangle { height: 3 width : parent.width color: "gray" anchors.top: parent.bottom anchors.bottomMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.YAxis } onMouseYChanged: { if(drag.active){ recentProjectsFrame.heightRate = (recentProjectsFrame.height + mouseY) / mainWindow.height exampleProjects.heightRate = (exampleProjects.height + mouseY) / mainWindow.height helpFrame.heightRate = (helpFrame.height - mouseY) / mainWindow.height datasetFrame.heightRate = (datasetFrame.height - mouseY) / mainWindow.height if(recentProjectsFrame.height < 100 || exampleProjects.height < 100) { recentProjectsFrame.heightRate = 100 / mainWindow.height exampleProjects.heightRate = 100/ mainWindow.height helpFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height datasetFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height } if(helpFrame.height < 100 || datasetFrame.height < 100) { helpFrame.heightRate = 100 / mainWindow.height datasetFrame.heightRate = 100 / mainWindow.height recentProjectsFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height exampleProjects.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing)/ mainWindow.height } } } } } Rectangle { width: 3 height: parent.height color: "gray" anchors.right: parent.left anchors.leftMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.XAxis } onMouseXChanged: { if(drag.active){ exampleProjects.widthRate = (exampleProjects.width - mouseX)/ mainWindow.width recentProjectsFrame.widthRate = (recentProjectsFrame.width + mouseX) / mainWindow.width if(recentProjectsFrame.width < 150){ recentProjectsFrame.widthRate = 150 / mainWindow.width exampleProjects.widthRate = (mainWindow.width - newsSection.width - 150 - 4*mainWindow.spacing) / mainWindow.width } if(exampleProjects.width < 300) { exampleProjects.widthRate = 300/ mainWindow.width recentProjectsFrame.widthRate = (mainWindow.width - newsSection.width - 300 - 4*mainWindow.spacing) / mainWindow.width } } } } } ColumnLayout { anchors.fill: parent clip: true spacing: 5 RowLayout { Layout.fillWidth: true Layout.minimumHeight: Math.min((parent.height - 25 - 2*parent.spacing)*0.2, 100) Layout.preferredHeight: Math.min((parent.height - 25 - 2*parent.spacing)*0.2, 100) Image { Layout.preferredHeight: exampleProjects.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumHeight: exampleProjects.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.preferredWidth: exampleProjects.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumWidth: exampleProjects.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.alignment: Qt.AlignVCenter source: exampleProjects.fullScreen ? helper.getMinIcon() : helper.getMaxIcon() sourceSize.width: exampleProjects.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) sourceSize.height: exampleProjects.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) MouseArea { anchors.fill: parent onClicked: { if(!exampleProjects.fullScreen) { exampleProjects.maximize() } else { exampleProjects.minimize() } exampleProjects.fullScreen = !exampleProjects.fullScreen } } } Label { text: qsTr("Examples") styleColor: "#d41919" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.pointSize: exampleProjects.fullScreen ? 60 : 24 minimumPointSize: 10 fontSizeMode: Text.Fit Layout.fillWidth: true Layout.fillHeight: true wrapMode: Text.WordWrap } } TextField { id: searchText placeholderText: "Search among example projects" Layout.fillWidth: true; onTextChanged: {exampleGrid.model = helper.searchExampleProjects(searchText.text)} height: 25 Layout.minimumHeight: 25 Layout.preferredHeight: 25 } ExampleGrid { id: exampleGrid Layout.fillHeight: true Layout.fillWidth: true clip:true Layout.minimumHeight: Math.max((parent.height - 25 - 2*parent.spacing)*0.8, parent.height - 25 - 100 - 2*parent.spacing) Layout.preferredHeight: Math.max((parent.height - 25 - 2*parent.spacing)*0.8, parent.height - 25 - 100 - 2*parent.spacing) } } } Frame { id: newsSection property string sectionName: "newsSection" property double widthRate : helper.getWidthScale(sectionName) === -1 ? (mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width : helper.getWidthScale(sectionName) property double heightRate : helper.getHeightScale(sectionName) === -1 ? (mainWindow.height- 4*mainWindow.spacing) / mainWindow.height : helper.getHeightScale(sectionName) width: mainWindow.width * widthRate height: mainWindow.height * heightRate anchors.bottom: parent.bottom anchors.bottomMargin: mainWindow.spacing anchors.right: parent.right anchors.rightMargin: mainWindow.spacing anchors.top: parent.top anchors.topMargin: mainWindow.spacing visible: true opacity: 1 padding: 5 clip: true property bool fullScreen: false property double prevWidth: 0 property double prevHeight: 0 Component.onCompleted: { if(helper.getWidthScale(sectionName) === -1 || helper.getHeightScale(sectionName) === -1) mainWindow.restoreOriginalLayout() } + function maximize() { + hideTiles() + newsSection.prevWidth = newsSection.widthRate + newsSection.prevHeight = newsSection.heightRate + newsSection.visible = true + newsSection.z = 1 + newsSection.anchors.fill = undefined + newsSection.anchors.right = undefined + newsSection.anchors.bottom = undefined + newsSection.anchors.centerIn = undefined + newsSection.anchors.top = undefined + newsSection.anchors.left = undefined + newsSection.widthRate = 1 + newsSection.heightRate = 1 + + newsSection.anchors.fill = mainWindow + } + + function minimize() { + newsSection.anchors.fill = undefined + newsSection.anchors.right = undefined + newsSection.anchors.bottom = undefined + newsSection.anchors.centerIn = undefined + newsSection.anchors.top = undefined + newsSection.anchors.left = undefined + + newsSection.anchors.top = mainWindow.top + newsSection.anchors.topMargin = mainWindow.spacing + newsSection.anchors.right = mainWindow.right + newsSection.anchors.rightMargin = mainWindow.spacing + newsSection.anchors.bottom = mainWindow.bottom + newsSection.anchors.bottomMargin = mainWindow.spacing + newsSection.widthRate = newsSection.prevWidth + newsSection.heightRate = newsSection.prevHeight + + showTiles(); + } + Rectangle { width: 3 height: parent.height color: "gray" anchors.right: parent.left anchors.leftMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.XAxis } onMouseXChanged: { if(drag.active){ newsSection.widthRate = (newsSection.width - mouseX) / mainWindow.width exampleProjects.widthRate = (exampleProjects.width + mouseX) / mainWindow.width datasetFrame.widthRate = (datasetFrame.width + mouseX) / mainWindow.width releaseSection.widthRate = (releaseSection.width + mouseX) / mainWindow.width if(exampleProjects.width < 300 || datasetFrame.width < 300){ newsSection.widthRate = (mainWindow.width - Math.max(recentProjectsFrame.width, helpFrame.width) - 300 - 4*mainWindow.spacing) / mainWindow.width exampleProjects.widthRate = (mainWindow.width - newsSection.width - recentProjectsFrame.width - 4*mainWindow.spacing)/ mainWindow.width datasetFrame.widthRate = (mainWindow.width - newsSection.width - helpFrame.width - 4*mainWindow.spacing) / mainWindow.width releaseSection.widthRate = (Math.max(recentProjectsFrame.width, helpFrame.width) + mainWindow.spacing + 300) / mainWindow.width } if(newsSection.width < 150) { newsSection.widthRate = 150 / mainWindow.width exampleProjects.widthRate = (mainWindow.width - recentProjectsFrame.width - 150 - 4*mainWindow.spacing) / mainWindow.width datasetFrame.widthRate = (mainWindow.width - helpFrame.width - 150 - 4*mainWindow.spacing) / mainWindow.width releaseSection.widthRate = (mainWindow.width - newsSection.width - 3*mainWindow.spacing) / mainWindow.width } } } } } ColumnLayout { anchors.fill: parent RowLayout { Layout.fillWidth: true Layout.minimumHeight: Math.min(parent.height*0.2, 100) Layout.preferredHeight: Math.min(parent.height*0.2, 100) Image { Layout.preferredHeight: newsSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumHeight: newsSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.preferredWidth: newsSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumWidth:newsSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.alignment: Qt.AlignVCenter source: newsSection.fullScreen ? helper.getMinIcon() : helper.getMaxIcon() sourceSize.width: newsSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) sourceSize.height: newsSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) MouseArea { anchors.fill: parent onClicked: { if(!newsSection.fullScreen) { - hideTiles() - newsSection.prevWidth = newsSection.widthRate - newsSection.prevHeight = newsSection.heightRate - newsSection.visible = true - newsSection.z = 1 - newsSection.anchors.fill = undefined - newsSection.anchors.right = undefined - newsSection.anchors.bottom = undefined - newsSection.anchors.centerIn = undefined - newsSection.anchors.top = undefined - newsSection.anchors.left = undefined - - - newsSection.widthRate = 1 - newsSection.heightRate = 1 - - newsSection.anchors.fill = mainWindow + newsSection.maximize() } else { - newsSection.anchors.fill = undefined - newsSection.anchors.right = undefined - newsSection.anchors.bottom = undefined - newsSection.anchors.centerIn = undefined - newsSection.anchors.top = undefined - newsSection.anchors.left = undefined - - newsSection.anchors.top = mainWindow.top - newsSection.anchors.topMargin = mainWindow.spacing - newsSection.anchors.right = mainWindow.right - newsSection.anchors.rightMargin = mainWindow.spacing - newsSection.anchors.bottom = mainWindow.bottom - newsSection.anchors.bottomMargin = mainWindow.spacing - newsSection.widthRate = newsSection.prevWidth - newsSection.heightRate = newsSection.prevHeight - - showTiles(); + newsSection.minimize() } newsSection.fullScreen = !newsSection.fullScreen } } } Label { id: label2 text: qsTr("News") verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.pointSize: newsSection.fullScreen ? 60 : 24 minimumPointSize: 10 fontSizeMode: Text.Fit Layout.fillWidth: true Layout.fillHeight: true wrapMode: Text.WordWrap } } RssNews{ id:newsFeed Layout.fillHeight: true Layout.minimumHeight: Math.min(parent.height * 0.8, parent.height - 100) } } } Frame { id: helpFrame property string sectionName: "helpFrame" property double widthRate : helper.getWidthScale(sectionName) === -1 ? (mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width : helper.getWidthScale(sectionName) property double heightRate : helper.getHeightScale(sectionName) === -1 ? (mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height : helper.getHeightScale(sectionName) width: mainWindow.width * widthRate height: mainWindow.height * heightRate anchors.top: recentProjectsFrame.bottom anchors.topMargin: mainWindow.spacing anchors.left: parent.left anchors.leftMargin: mainWindow.spacing anchors.bottom: releaseSection.top anchors.bottomMargin: mainWindow.spacing visible: true opacity: 1 padding: 5 clip: true property bool fullScreen: false property double prevWidth: 0 property double prevHeight: 0 Component.onCompleted: { if(helper.getWidthScale(sectionName) === -1 || helper.getHeightScale(sectionName) === -1) mainWindow.restoreOriginalLayout() } + function maximize() { + hideTiles() + helpFrame.prevWidth = helpFrame.widthRate + helpFrame.prevHeight = helpFrame.heightRate + helpFrame.visible = true + helpFrame.z = 1 + helpFrame.anchors.fill = undefined + helpFrame.anchors.right = undefined + helpFrame.anchors.bottom = undefined + helpFrame.anchors.centerIn = undefined + helpFrame.anchors.top = undefined + helpFrame.anchors.left = undefined + + helpFrame.heightRate = 1 + helpFrame.widthRate = 1 + helpFrame.anchors.fill = mainWindow + } + + function minimize(){ + helpFrame.anchors.fill = undefined + helpFrame.anchors.right = undefined + helpFrame.anchors.bottom = undefined + helpFrame.anchors.centerIn = undefined + helpFrame.anchors.top = undefined + helpFrame.anchors.left = undefined + + helpFrame.anchors.top = recentProjectsFrame.bottom + helpFrame.anchors.topMargin = mainWindow.spacing + helpFrame.anchors.left = mainWindow.left + helpFrame.anchors.leftMargin = mainWindow.spacing + helpFrame.anchors.bottom = releaseSection.top + helpFrame.anchors.bottomMargin = mainWindow.spacing + helpFrame.widthRate = helpFrame.prevWidth + helpFrame.heightRate = helpFrame.prevHeight + + showTiles(); + } + Rectangle { width: 3 height: parent.height color: "gray" anchors.left: parent.right anchors.rightMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.XAxis } onMouseXChanged: { if(drag.active){ helpFrame.widthRate = (helpFrame.width + mouseX) / mainWindow.width datasetFrame.widthRate = (datasetFrame.width - mouseX) / mainWindow.width if(helpFrame.width < 150){ helpFrame.widthRate = 150 / mainWindow.width datasetFrame.widthRate = (mainWindow.width - newsSection.width - 150 - 4*mainWindow.spacing) / mainWindow.width } if(datasetFrame.width < 150) { datasetFrame.widthRate = 150 / mainWindow.width helpFrame.widthRate = (mainWindow.width - newsSection.width - 150 - 4*mainWindow.spacing) / mainWindow.width } } } } } Rectangle { height: 3 width : parent.width color: "gray" anchors.top: parent.bottom anchors.bottomMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.YAxis } onMouseYChanged: { if(drag.active){ helpFrame.heightRate = (helpFrame.height + mouseY) / mainWindow.height datasetFrame.heightRate = (datasetFrame.height + mouseY) / mainWindow.height releaseSection.heightRate = (releaseSection.height - mouseY) / mainWindow.height if(releaseSection.height < 100) { releaseSection.heightRate = 100 / mainWindow.height helpFrame.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height datasetFrame.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height } if(helpFrame.height < 100 || datasetFrame.height < 100) { helpFrame.heightRate = 100 / mainWindow.height datasetFrame.heightRate = 100 / mainWindow.height releaseSection.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height } } } } } Rectangle { height: 3 width : parent.width color: "gray" anchors.bottom: parent.top anchors.bottomMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.YAxis } onMouseYChanged: { if(drag.active){ recentProjectsFrame.heightRate = (recentProjectsFrame.height + mouseY) / mainWindow.height exampleProjects.heightRate =(exampleProjects.height + mouseY) / mainWindow.height helpFrame.heightRate = (helpFrame.height - mouseY) / mainWindow.height datasetFrame.heightRate = (datasetFrame.height - mouseY) / mainWindow.height if(recentProjectsFrame.height < 100 || exampleProjects.height < 100) { recentProjectsFrame.heightRate = 100 / mainWindow.height exampleProjects.heightRate = 100/ mainWindow.height helpFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height datasetFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height } if(helpFrame.height < 100 || datasetFrame.height < 100) { helpFrame.heightRate = 100 / mainWindow.height datasetFrame.heightRate = 100 / mainWindow.height recentProjectsFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height exampleProjects.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height } } } } } ColumnLayout { anchors.fill: parent spacing: 20 clip: true RowLayout { Layout.fillWidth: true Layout.minimumHeight: Math.min((parent.height - parent.spacing) *0.2, 100) Layout.preferredHeight: Math.min((parent.height - parent.spacing) *0.2, 100) Image { Layout.preferredHeight: helpFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumHeight: helpFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.preferredWidth: helpFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumWidth: helpFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.alignment: Qt.AlignVCenter source: helpFrame.fullScreen ? helper.getMinIcon() : helper.getMaxIcon() sourceSize.width: helpFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) sourceSize.height: helpFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) MouseArea { anchors.fill: parent onClicked: { if(!helpFrame.fullScreen) { - hideTiles() - helpFrame.prevWidth = helpFrame.widthRate - helpFrame.prevHeight = helpFrame.heightRate - helpFrame.visible = true - helpFrame.z = 1 - helpFrame.anchors.fill = undefined - helpFrame.anchors.right = undefined - helpFrame.anchors.bottom = undefined - helpFrame.anchors.centerIn = undefined - helpFrame.anchors.top = undefined - helpFrame.anchors.left = undefined - - helpFrame.heightRate = 1 - helpFrame.widthRate = 1 - helpFrame.anchors.fill = mainWindow + helpFrame.maximize() } else { - helpFrame.anchors.fill = undefined - helpFrame.anchors.right = undefined - helpFrame.anchors.bottom = undefined - helpFrame.anchors.centerIn = undefined - helpFrame.anchors.top = undefined - helpFrame.anchors.left = undefined - - helpFrame.anchors.top = recentProjectsFrame.bottom - helpFrame.anchors.topMargin = mainWindow.spacing - helpFrame.anchors.left = mainWindow.left - helpFrame.anchors.leftMargin = mainWindow.spacing - helpFrame.anchors.bottom = releaseSection.top - helpFrame.anchors.bottomMargin = mainWindow.spacing - helpFrame.widthRate = helpFrame.prevWidth - helpFrame.heightRate = helpFrame.prevHeight - - showTiles(); + helpFrame.minimize() } helpFrame.fullScreen = !helpFrame.fullScreen } } } Label { text: qsTr("Help") verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.pointSize: helpFrame.fullScreen ? 60 : 24 minimumPointSize: 10 fontSizeMode: Text.Fit Layout.fillWidth: true Layout.fillHeight: true wrapMode: Text.WordWrap } } HelpList { id: helpList width: parent.width Layout.minimumHeight: Math.max((parent.height - parent.spacing) *0.8, parent.height - parent.spacing - 100) Layout.fillHeight: true Layout.fillWidth: true clip: true } } } Frame { id: datasetFrame property string sectionName: "datasetFrame" property double widthRate : helper.getWidthScale(sectionName) === -1 ? (3 * mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width : helper.getWidthScale(sectionName) property double heightRate : helper.getHeightScale(sectionName) === -1 ? (mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height : helper.getHeightScale(sectionName) width: mainWindow.width * widthRate height: mainWindow.height * heightRate anchors.top: exampleProjects.bottom anchors.topMargin: mainWindow.spacing anchors.left: helpFrame.right anchors.leftMargin: mainWindow.spacing anchors.right: newsSection.left anchors.rightMargin: mainWindow.spacing anchors.bottom: releaseSection.top anchors.bottomMargin: mainWindow.spacing visible: true opacity: 1 padding: 5 clip: true function maximize() { hideTiles() datasetFrame.prevWidth = datasetFrame.widthRate datasetFrame.prevHeight = datasetFrame.heightRate datasetFrame.visible = true datasetFrame.z = 1 datasetFrame.anchors.fill = undefined datasetFrame.anchors.right = undefined datasetFrame.anchors.bottom = undefined datasetFrame.anchors.centerIn = undefined datasetFrame.anchors.top = undefined datasetFrame.anchors.left = undefined datasetFrame.widthRate = 1 datasetFrame.heightRate = 1 datasetFrame.anchors.fill = mainWindow } function minimize() { datasetFrame.anchors.fill = undefined datasetFrame.anchors.right = undefined datasetFrame.anchors.bottom = undefined datasetFrame.anchors.centerIn = undefined datasetFrame.anchors.top = undefined datasetFrame.anchors.left = undefined datasetFrame.anchors.top = exampleProjects.bottom datasetFrame.anchors.topMargin = mainWindow.spacing datasetFrame.anchors.left = helpFrame.right datasetFrame.anchors.leftMargin = mainWindow.spacing datasetFrame.anchors.bottom = releaseSection.top datasetFrame.anchors.bottomMargin = mainWindow.spacing datasetFrame.anchors.right = newsSection.left datasetFrame.anchors.rightMargin = mainWindow.spacing datasetFrame.widthRate = datasetFrame.prevWidth datasetFrame.heightRate = datasetFrame.prevHeight showTiles(); } property bool fullScreen: false property double prevWidth: 0 property double prevHeight: 0 Component.onCompleted: { if(helper.getWidthScale(sectionName) === -1 || helper.getHeightScale(sectionName) === -1) mainWindow.restoreOriginalLayout() } Rectangle { width: 3 height: parent.height color: "gray" anchors.left: parent.right anchors.rightMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.XAxis } onMouseXChanged: { if(drag.active){ newsSection.widthRate = (newsSection.width - mouseX) / mainWindow.width exampleProjects.widthRate = (exampleProjects.width + mouseX) / mainWindow.width datasetFrame.widthRate = (datasetFrame.width + mouseX) / mainWindow.width releaseSection.widthRate = (releaseSection.width + mouseX) / mainWindow.width if(exampleProjects.width < 300 || datasetFrame.width < 300){ newsSection.widthRate = (mainWindow.width - Math.max(recentProjectsFrame.width, helpFrame.width) - 300 - 4*mainWindow.spacing) / mainWindow.width exampleProjects.widthRate = (mainWindow.width - newsSection.width - recentProjectsFrame.width - 4*mainWindow.spacing)/ mainWindow.width datasetFrame.widthRate = (mainWindow.width - newsSection.width - helpFrame.width - 4*mainWindow.spacing) / mainWindow.width releaseSection.widthRate = (Math.max(recentProjectsFrame.width, helpFrame.width) + mainWindow.spacing + 300) / mainWindow.width } if(newsSection.width < 150) { newsSection.widthRate = 150 / mainWindow.width exampleProjects.widthRate = (mainWindow.width - recentProjectsFrame.width - 150 - 4*mainWindow.spacing)/ mainWindow.width datasetFrame.widthRate = (mainWindow.width - helpFrame.width - 150 - 4*mainWindow.spacing) / mainWindow.width releaseSection.widthRate = (mainWindow.width - newsSection.width - 3*mainWindow.spacing) / mainWindow.width } } } } } Rectangle { height: 3 width : parent.width color: "gray" anchors.top: parent.bottom anchors.bottomMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.YAxis } onMouseYChanged: { if(drag.active){ helpFrame.heightRate = (helpFrame.height + mouseY) / mainWindow.height datasetFrame.heightRate = (datasetFrame.height + mouseY) / mainWindow.height releaseSection.heightRate = (releaseSection.height - mouseY) / mainWindow.height if(releaseSection.height < 100) { releaseSection.heightRate = 100 / mainWindow.height helpFrame.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height datasetFrame.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height } if(helpFrame.height < 100 || datasetFrame.height < 100) { helpFrame.heightRate = 100 / mainWindow.height datasetFrame.heightRate = 100 / mainWindow.height releaseSection.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height } } } } } Rectangle { height: 3 width : parent.width color: "gray" anchors.bottom: parent.top anchors.bottomMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.YAxis } onMouseYChanged: { if(drag.active){ recentProjectsFrame.heightRate = (recentProjectsFrame.height + mouseY) / mainWindow.height exampleProjects.heightRate = (exampleProjects.height + mouseY) / mainWindow.height helpFrame.heightRate = (helpFrame.height - mouseY) / mainWindow.height datasetFrame.heightRate = (datasetFrame.height - mouseY) / mainWindow.height if(recentProjectsFrame.height < 100 || exampleProjects.height < 100) { recentProjectsFrame.heightRate = 100 / mainWindow.height exampleProjects.heightRate = 100 / mainWindow.height helpFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height datasetFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height } if(helpFrame.height < 100 || datasetFrame.height < 100) { helpFrame.heightRate = 100 / mainWindow.height datasetFrame.heightRate = 100 / mainWindow.height recentProjectsFrame.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height exampleProjects.heightRate = (mainWindow.height - releaseSection.height - 100 - 4*mainWindow.spacing) / mainWindow.height } } } } } Rectangle { width: 3 height: parent.height color: "gray" anchors.right: parent.left anchors.leftMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.XAxis } onMouseXChanged: { if(drag.active){ helpFrame.widthRate = (helpFrame.width + mouseX) / mainWindow.width datasetFrame.widthRate = (datasetFrame.width - mouseX) / mainWindow.width if(helpFrame.width < 150){ helpFrame.widthRate = 150 / mainWindow.width datasetFrame.widthRate = (mainWindow.width - newsSection.width - 150 - 4*mainWindow.spacing) / mainWindow.width } if(datasetFrame.width < 150) { datasetFrame.widthRate = 150 / mainWindow.width helpFrame.widthRate = (mainWindow.width - newsSection.width - 150 - 4*mainWindow.spacing) / mainWindow.width } } } } } ColumnLayout { anchors.fill: parent clip: true spacing: 20 RowLayout { Layout.fillWidth: true Layout.minimumHeight: Math.min((parent.height - parent.spacing) *0.2, 100) Layout.preferredHeight: Math.min((parent.height - parent.spacing) *0.2, 100) Image { Layout.preferredHeight: datasetFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumHeight: datasetFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.preferredWidth: datasetFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumWidth: datasetFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.alignment: Qt.AlignVCenter source: datasetFrame.fullScreen ? helper.getMinIcon() : helper.getMaxIcon() sourceSize.width: datasetFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) sourceSize.height: datasetFrame.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) MouseArea { anchors.fill: parent onClicked: { if(!datasetFrame.fullScreen) { datasetFrame.maximize() } else { datasetFrame.minimize() } datasetFrame.fullScreen = !datasetFrame.fullScreen } } } Label { text: qsTr("Start exploring data") verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.pointSize: datasetFrame.fullScreen ? 60 : 24 minimumPointSize: 10 fontSizeMode: Text.Fit Layout.fillWidth: true Layout.fillHeight: true wrapMode: Text.WordWrap } } RowLayout { id: datasetSectionRow Layout.fillHeight: true Layout.minimumHeight: Math.max((parent.height - parent.spacing) *0.8, parent.height - parent.spacing - 100) Layout.fillWidth: true Layout.preferredWidth: parent.width Layout.minimumWidth: parent.width spacing: 10 clip: true property int separatorWidth: 5 ListView { id: categoryList Layout.preferredWidth: (parent.width - 3 * datasetSectionRow.separatorWidth - 6*datasetSectionRow.spacing) * 0.15 Layout.minimumWidth: (parent.width - 3 * datasetSectionRow.separatorWidth - 6*datasetSectionRow.spacing) * 0.15 spacing: 10 Layout.fillHeight: true property int textWidth: 100 clip: true ScrollBar.vertical: ScrollBar { } model: datasetModel.allCategories() delegate:Rectangle { width: parent.width height: 25 id: categoryDelegate property string categoryName : modelData property bool selected: ListView.isCurrentItem RowLayout { id: categoryRow spacing: 10 anchors.fill: parent Rectangle { id: categoryBullet Layout.alignment: Qt.AlignVCenter width: 5 height: 5 color: "#7a7d82" } Label { height: parent.height width: parent.width - 5 - categoryRow.spacing Layout.minimumWidth: parent.width - 5 - categoryRow.spacing Layout.preferredWidth: parent.width - 5 - categoryRow.spacing Layout.fillHeight: true id: categoryLabel verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter text: categoryDelegate.categoryName font.bold: true wrapMode: Text.WordWrap font.pixelSize: 18 minimumPixelSize: 1 fontSizeMode: Text.Fit color: selected ? "#d69f00" : "#000000" scale: selected ? 1.15 : 1.0 Behavior on color { ColorAnimation { duration: 150 } } Behavior on scale { PropertyAnimation { duration: 300 } } Component.onCompleted: { if(index == 0) { mainWindow.currentCategory = categoryDelegate.categoryName categoryDelegate.ListView.view.currentIndex = index } if(categoryList.textWidth < paintedWidth + categoryBullet.width + categoryRow.spacing) categoryList.textWidth = paintedWidth + categoryBullet.width + categoryRow.spacing } } } MouseArea { anchors.fill: parent onClicked: { categoryDelegate.ListView.view.currentIndex = index if (mainWindow.currentCategory != categoryName) mainWindow.currentCategory = categoryName if(categoryList.textWidth < categoryLabel.paintedWidth + categoryBullet.width + categoryRow.spacing) categoryList.textWidth = categoryLabel.paintedWidth + categoryBullet.width + categoryRow.spacing } } } } Rectangle { Layout.fillHeight: true width: 5 color: "grey" } ListView { id: subcategoryList spacing: 10 Layout.fillHeight: true Layout.preferredWidth: (parent.width - 3 * datasetSectionRow.separatorWidth - 6*datasetSectionRow.spacing) * 0.15 Layout.minimumWidth: (parent.width - 3 * datasetSectionRow.separatorWidth - 6*datasetSectionRow.spacing) * 0.15 ScrollBar.vertical: ScrollBar{} clip: true property int textWidth: 100 model: datasetModel.allSubcategories(mainWindow.currentCategory) delegate: Rectangle { width: parent.width height: 25 id: subcategoryDelegate property string subcategoryName : modelData property bool selected: ListView.isCurrentItem RowLayout { id: subcategoryRow spacing: 10 anchors.fill: parent Rectangle { id: subcategoryBullet Layout.alignment: Qt.AlignVCenter width: 5 height: 5 color: "#7a7d82" } Label { height: parent.height width: parent.width - 5 - subcategoryRow.spacing Layout.minimumWidth: parent.width - 5 - subcategoryRow.spacing Layout.preferredWidth: parent.width - 5 - subcategoryRow.spacing Layout.fillHeight: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter text: subcategoryDelegate.subcategoryName wrapMode: Text.WordWrap font.bold: true font.pixelSize: 18 minimumPixelSize: 1 fontSizeMode: Text.Fit color: selected ? "#d69f00" : "#000000" scale: selected ? 1.15 : 1.0 Behavior on color { ColorAnimation { duration: 150 } } Behavior on scale { PropertyAnimation { duration: 300 } } Component.onCompleted: { if(index == 0) { mainWindow.currentSubcategory = subcategoryDelegate.subcategoryName subcategoryDelegate.ListView.view.currentIndex = index } if(subcategoryList.textWidth < paintedWidth + subcategoryBullet.width + subcategoryRow.spacing) { subcategoryList.textWidth = paintedWidth + subcategoryBullet.width + subcategoryRow.spacing } } } } MouseArea { anchors.fill: parent onClicked: { console.log("Subcategory name: " + subcategoryDelegate.subcategoryName + "Clicked") subcategoryDelegate.ListView.view.currentIndex = index if (mainWindow.currentSubcategory != subcategoryName) mainWindow.currentSubcategory = subcategoryName } } } } Rectangle { Layout.fillHeight: true width: 5 color: "grey" } GridView { id: datasetGrid Layout.fillHeight: true Layout.preferredWidth: (parent.width - 3 * datasetSectionRow.separatorWidth - 6*datasetSectionRow.spacing) * 0.4 Layout.minimumWidth: (parent.width - 3 * datasetSectionRow.separatorWidth - 6*datasetSectionRow.spacing) * 0.4 cellWidth: width/4 cellHeight: 40 clip: true model: datasetModel.allDatasets(mainWindow.currentCategory, mainWindow.currentSubcategory) delegate: Rectangle { id: datasetDelegate property string datasetName : modelData property bool selected: (index == datasetGrid.currentIndex) width: (datasetGrid.width - 30) / 4 height: textHeight property int textWidth: 200 property int textHeight: 40 RowLayout { id: datasetRow spacing: 10 anchors.fill: parent Rectangle { id: datasetBullet width: 5 height: 5 color: "#7a7d82" } Label { id: datasetText height: parent.height width: parent.width - 5 - datasetRow.spacing Layout.minimumWidth: parent.width - 5 - datasetRow.spacing Layout.preferredWidth: parent.width - 5 - datasetRow.spacing Layout.fillHeight: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter text: datasetDelegate.datasetName wrapMode: Text.WordWrap font.bold: true font.pixelSize: 18 minimumPixelSize: 1 fontSizeMode: Text.Fit color: selected ? "#d69f00" : "#000000" scale: selected ? 1.15 : 1.0 Behavior on color { ColorAnimation { duration: 150 } } Behavior on scale { PropertyAnimation { duration: 300 } } Component.onCompleted: { datasetDelegate.textHeight = paintedHeight datasetDelegate.textWidth = paintedWidth + datasetBullet.width + datasetRow.spacing if(index == 0) { datasetGrid.currentIndex = index mainWindow.currentDataset = datasetDelegate.datasetName mainWindow.datasetClicked(mainWindow.currentCategory, mainWindow.currentSubcategory, datasetDelegate.datasetName) } } } } MouseArea { anchors.fill: parent onClicked: { if(datasetFrame.fullScreen) datasetFrame.minimize() datasetGrid.currentIndex = index console.log("Dataset name: " + datasetDelegate.datasetName + "Clicked") mainWindow.currentDataset = datasetDelegate.datasetName mainWindow.datasetClicked(mainWindow.currentCategory, mainWindow.currentSubcategory, datasetDelegate.datasetName) } } } } Rectangle { Layout.fillHeight: true width: 5 color: "grey" } ScrollView { id: scrollView Layout.fillHeight: true Layout.preferredWidth: (parent.width - 3 * datasetSectionRow.separatorWidth - 6*datasetSectionRow.spacing) * 0.3 Layout.minimumWidth: (parent.width - 3 * datasetSectionRow.separatorWidth - 6*datasetSectionRow.spacing) * 0.3 contentHeight: datasetDescriptionColumn.height clip: true ColumnLayout { id: datasetDescriptionColumn Layout.minimumWidth: scrollView.width Layout.preferredWidth: scrollView.width width: scrollView.width spacing: 10 Row { width: datasetDescriptionColumn.width spacing: 5 Text { id: datasetTitleLabel text: "Full name: " font.pixelSize: 14 font.bold: true wrapMode: Text.WordWrap } Text { id: datasetTitle //Layout.fillWidth: true width: datasetDescriptionColumn.width - datasetTitleLabel.paintedWidth text: "-" wrapMode: Text.WordWrap font.pixelSize: 14 } } Row { width: parent.width height: Math.max(datasetDescription.textHeight, datasetDescriptionLabel.paintedHeight) spacing: 5 Text { id: datasetDescriptionLabel text: "Description: " font.pixelSize: 14 font.bold: true wrapMode: Text.WordWrap } Text { id: datasetDescription property double textHeight: paintedHeight text: "" width: datasetDescriptionColumn.width - datasetDescriptionLabel.paintedWidth Layout.preferredWidth: datasetDescriptionColumn.width - datasetDescriptionLabel.paintedWidth Layout.minimumWidth: datasetDescriptionColumn.width - datasetDescriptionLabel.paintedWidth wrapMode: Text.WordWrap font.pixelSize: 12 } } Row { width: parent.width spacing: 5 Text { id: datasetColumnsLabel text: "Columns: " font.pixelSize: 14 font.bold: true wrapMode: Text.WordWrap } Text { id: datasetColumns text: "-" width: datasetDescriptionColumn.width - datasetColumnsLabel.paintedWidth wrapMode: Text.WordWrap font.pixelSize: 14 } } Row { width: parent.width spacing: 5 Text { id: datasetRowsLabel text: "Rows: " font.pixelSize: 14 font.bold: true wrapMode: Text.WordWrap } Text { id: datasetRows text: "-" width: datasetDescriptionColumn.width - datasetRowsLabel.paintedWidth wrapMode: Text.WordWrap font.pixelSize: 14 } } Rectangle { width: datasetButtonText.paintedWidth + 10 height: datasetButtonText.paintedHeight + 10 Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom color:'#dfe3ee' Text { id: datasetButtonText text: "Open dataset" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 14 font.bold: true wrapMode: Text.WordWrap } MouseArea { anchors.fill: parent onClicked: { mainWindow.openDataset() } } } } } } } } Frame { id: releaseSection property string sectionName: "releaseSection" property double widthRate : helper.getWidthScale(sectionName) === -1 ? (4 * mainWindow.width / 5 - 4*mainWindow.spacing) / mainWindow.width : helper.getWidthScale(sectionName) property double heightRate : helper.getHeightScale(sectionName) === -1 ? (2*mainWindow.height / 4 - 4*mainWindow.spacing) / mainWindow.height : helper.getHeightScale(sectionName) width: mainWindow.width * widthRate height: mainWindow.height * heightRate anchors.left: parent.left anchors.leftMargin: mainWindow.spacing anchors.right: newsSection.left anchors.rightMargin: mainWindow.spacing anchors.bottom: parent.bottom anchors.bottomMargin: mainWindow.spacing visible: true opacity: 1 padding: 5 clip: true property bool fullScreen: false property double prevWidth: 0 property double prevHeight: 0 + function maximize() { + hideTiles() + releaseSection.prevWidth = releaseSection.widthRate + releaseSection.prevHeight = releaseSection.heightRate + releaseSection.visible = true + releaseSection.z = 1 + releaseSection.anchors.fill = undefined + releaseSection.anchors.right = undefined + releaseSection.anchors.bottom = undefined + releaseSection.anchors.centerIn = undefined + releaseSection.anchors.top = undefined + releaseSection.anchors.left = undefined + + releaseSection.widthRate = 1 + releaseSection.heightRate = 1 + releaseSection.anchors.fill = mainWindow + } + + function minimize() { + releaseSection.anchors.fill = undefined + releaseSection.anchors.right = undefined + releaseSection.anchors.bottom = undefined + releaseSection.anchors.centerIn = undefined + releaseSection.anchors.top = undefined + releaseSection.anchors.left = undefined + + releaseSection.anchors.left = mainWindow.left + releaseSection.anchors.leftMargin = mainWindow.spacing + releaseSection.anchors.bottom = mainWindow.bottom + releaseSection.anchors.bottomMargin = mainWindow.spacing + releaseSection.anchors.right = newsSection.left + releaseSection.anchors.rightMargin = mainWindow.spacing + releaseSection.widthRate = releaseSection.prevWidth + releaseSection.heightRate = releaseSection.prevHeight + + showTiles(); + } + + function updateIcons() { + if(releaseWebView.canGoBack) + backIcon.opacity = 1 + else + backIcon.opacity = 0.5 + + if(releaseWebView.canGoForward) + forwardIcon.opacity = 1 + else + forwardIcon.opacity = 0.5 + } + Component.onCompleted: { if(helper.getWidthScale(sectionName) === -1 || helper.getHeightScale(sectionName) === -1) mainWindow.restoreOriginalLayout() } Rectangle { width: 3 height: parent.height color: "gray" anchors.left: parent.right anchors.rightMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.XAxis } onMouseXChanged: { if(drag.active){ newsSection.widthRate = (newsSection.width - mouseX) / mainWindow.width exampleProjects.widthRate = (exampleProjects.width + mouseX) / mainWindow.width datasetFrame.widthRate = (datasetFrame.width + mouseX) / mainWindow.width releaseSection.widthRate = (releaseSection.width + mouseX) / mainWindow.width if(exampleProjects.width < 300 || datasetFrame.width < 300){ newsSection.widthRate = (mainWindow.width - Math.max(recentProjectsFrame.width, helpFrame.width) - 300 - 4*mainWindow.spacing) / mainWindow.width exampleProjects.widthRate = (mainWindow.width - newsSection.width - recentProjectsFrame.width - 4*mainWindow.spacing) / mainWindow.width datasetFrame.widthRate = (mainWindow.width - newsSection.width - helpFrame.width - 4*mainWindow.spacing) / mainWindow.width releaseSection.widthRate = (Math.max(recentProjectsFrame.width, helpFrame.width) + mainWindow.spacing + 300) / mainWindow.width } if(newsSection.width < 150) { newsSection.width = 150 / mainWindow.width exampleProjects.widthRate = (mainWindow.width - recentProjectsFrame.width - 150 - 4*mainWindow.spacing) / mainWindow.width datasetFrame.widthRate = (mainWindow.width - helpFrame.width - 150 - 4*mainWindow.spacing) / mainWindow.width releaseSection.widthRate = (mainWindow.width - newsSection.width - 3*mainWindow.spacing) / mainWindow.width } } } } } Rectangle { height: 3 width : parent.width color: "gray" anchors.bottom: parent.top anchors.bottomMargin: 0 opacity: 0 MouseArea { anchors.fill: parent hoverEnabled: true onEntered: {parent.opacity = 1} onExited: { if(!drag.active && !pressed) parent.opacity = 0 } onPressed:parent.opacity = 1 onPressAndHold:parent.opacity = 1 onReleased: parent.opacity = 0 drag{ target: parent; axis: Drag.YAxis } onMouseYChanged: { if(drag.active){ helpFrame.heightRate = (helpFrame.height + mouseY) / mainWindow.height datasetFrame.heightRate = (datasetFrame.height + mouseY) / mainWindow.height releaseSection.heightRate = (releaseSection.height - mouseY) / mainWindow.height if(releaseSection.height < 100) { releaseSection.heightRate = 100 / mainWindow.height helpFrame.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height datasetFrame.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height } if(helpFrame.height < 100 || datasetFrame.height < 100) { helpFrame.heightRate = 100 / mainWindow.height datasetFrame.heightRate = 100 / mainWindow.height releaseSection.heightRate = (mainWindow.height - recentProjectsFrame.height - 100 - 4*mainWindow.spacing) / mainWindow.height } } } } } ColumnLayout { anchors.fill: parent clip: true spacing: 10 RowLayout { Layout.fillWidth: true Layout.minimumHeight: Math.min((parent.height - parent.spacing) *0.2, 100) Layout.preferredHeight: Math.min((parent.height - parent.spacing) *0.2, 100) Image { Layout.preferredHeight: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumHeight: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.preferredWidth: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.minimumWidth: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) Layout.alignment: Qt.AlignVCenter source: releaseSection.fullScreen ? helper.getMinIcon() : helper.getMaxIcon() sourceSize.width: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) sourceSize.height: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 25) : Math.min(Math.min(parent.height, parent.width) * 0.5, 15) MouseArea { anchors.fill: parent onClicked: { if(!releaseSection.fullScreen) { - hideTiles() - releaseSection.prevWidth = releaseSection.widthRate - releaseSection.prevHeight = releaseSection.heightRate - releaseSection.visible = true - releaseSection.z = 1 - releaseSection.anchors.fill = undefined - releaseSection.anchors.right = undefined - releaseSection.anchors.bottom = undefined - releaseSection.anchors.centerIn = undefined - releaseSection.anchors.top = undefined - releaseSection.anchors.left = undefined - - releaseSection.widthRate = 1 - releaseSection.heightRate = 1 - releaseSection.anchors.fill = mainWindow + releaseSection.maximize() } else { - releaseSection.anchors.fill = undefined - releaseSection.anchors.right = undefined - releaseSection.anchors.bottom = undefined - releaseSection.anchors.centerIn = undefined - releaseSection.anchors.top = undefined - releaseSection.anchors.left = undefined - - releaseSection.anchors.left = mainWindow.left - releaseSection.anchors.leftMargin = mainWindow.spacing - releaseSection.anchors.bottom = mainWindow.bottom - releaseSection.anchors.bottomMargin = mainWindow.spacing - releaseSection.anchors.right = newsSection.left - releaseSection.anchors.rightMargin = mainWindow.spacing - releaseSection.widthRate = releaseSection.prevWidth - releaseSection.heightRate = releaseSection.prevHeight - - showTiles(); + releaseSection.minimize() } releaseSection.fullScreen = !releaseSection.fullScreen } } } Image { + id: backIcon Layout.preferredHeight: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) Layout.minimumHeight: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) Layout.preferredWidth: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) Layout.minimumWidth: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) Layout.alignment: Qt.AlignVCenter source: helper.getBackIcon() sourceSize.width: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) sourceSize.height: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) MouseArea { anchors.fill: parent onClicked: { releaseWebView.goBack() } } } Image { + id: forwardIcon Layout.preferredHeight: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) Layout.minimumHeight: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) Layout.preferredWidth: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) Layout.minimumWidth: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) Layout.alignment: Qt.AlignVCenter source: helper.getForwardIcon() sourceSize.width: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) sourceSize.height: releaseSection.fullScreen ?Math.min(Math.min(parent.height, parent.width) * 0.5, 35) : Math.min(Math.min(parent.height, parent.width) * 0.5, 25) MouseArea { anchors.fill: parent onClicked: { releaseWebView.goForward() } } } Label { text: qsTr("What's new in this release") verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter font.pointSize:releaseSection.fullScreen ? 60 : 24 minimumPointSize: 10 fontSizeMode: Text.Fit Layout.fillWidth: true Layout.fillHeight: true wrapMode: Text.WordWrap } } WebView { id: releaseWebView Layout.fillHeight: true Layout.minimumHeight: Math.max((parent.height - parent.spacing) *0.8, parent.height - parent.spacing - 100) Layout.preferredHeight: Math.max((parent.height - parent.spacing) *0.8, parent.height - parent.spacing - 100) Layout.fillWidth: true url: initialUrl + + Component.onCompleted: { + releaseSection.updateIcons() + } + + onCanGoBackChanged: { + releaseSection.updateIcons() + } + + onCanGoForwardChanged: { + releaseSection.updateIcons() + } } } } }