File indexing completed on 2024-04-14 05:24:35

0001 /*
0002     SPDX-FileCopyrightText: 2020 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "tablayoutshandler.h"
0007 
0008 //! local
0009 #include <coretypes.h>
0010 #include "ui_settingsdialog.h"
0011 #include "settingsdialog.h"
0012 #include "layoutscontroller.h"
0013 #include "layoutsmodel.h"
0014 #include "layoutstableview.h"
0015 #include "../universalsettings.h"
0016 #include "../detailsdialog/detailsdialog.h"
0017 #include "../exporttemplatedialog/exporttemplatedialog.h"
0018 #include "../viewsdialog/viewsdialog.h"
0019 #include "../../apptypes.h"
0020 #include "../../lattecorona.h"
0021 #include "../../layout/centrallayout.h"
0022 #include "../../layouts/importer.h"
0023 #include "../../layouts/manager.h"
0024 #include "../../layouts/storage.h"
0025 #include "../../templates/templatesmanager.h"
0026 #include "../../tools/commontools.h"
0027 
0028 //! Qt
0029 #include <QDBusInterface>
0030 #include <QFileDialog>
0031 #include <QFileInfo>
0032 #include <QMimeData>
0033 
0034 //! KDE
0035 #include <KWindowSystem>
0036 #include <KLocalizedString>
0037 #include <KActivities/Controller>
0038 #include <KIO/OpenFileManagerWindowJob>
0039 #include <KNewStuff3/KNS3/DownloadDialog>
0040 
0041 
0042 namespace Latte {
0043 namespace Settings {
0044 namespace Handler {
0045 
0046 TabLayouts::TabLayouts(Settings::Dialog::SettingsDialog *parent)
0047     : Generic(parent),
0048       m_parentDialog(parent),
0049       m_corona(m_parentDialog->corona()),
0050       m_ui(m_parentDialog->ui()),
0051       m_storage(KConfigGroup(KSharedConfig::openConfig(),"LatteSettingsDialog").group("TabLayouts"))
0052 {
0053     //! load first the layouts view column widths
0054     loadConfig();
0055     m_layoutsController = new Settings::Controller::Layouts(this);
0056 
0057     //! create menu and assign actions before initializing the user interface
0058     initLayoutMenu();
0059     initUi();
0060 }
0061 
0062 TabLayouts::~TabLayouts()
0063 {
0064     saveConfig();
0065 }
0066 
0067 void TabLayouts::initUi()
0068 {
0069     m_inMemoryButtons = new QButtonGroup(this);
0070     m_inMemoryButtons->addButton(m_ui->singleToolBtn, MemoryUsage::SingleLayout);
0071     m_inMemoryButtons->addButton(m_ui->multipleToolBtn, MemoryUsage::MultipleLayouts);
0072     m_inMemoryButtons->setExclusive(true);
0073 
0074     bool inMultiple{m_corona->layoutsManager()->memoryUsage() == MemoryUsage::MultipleLayouts};
0075 
0076     if (inMultiple) {
0077         m_ui->multipleToolBtn->setChecked(true);
0078     } else {
0079         m_ui->singleToolBtn->setChecked(true);
0080     }
0081 
0082     connect(m_ui->layoutsView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &Generic::dataChanged);
0083 
0084     connect(m_layoutsController, &Settings::Controller::Layouts::dataChanged, this, &Generic::dataChanged);
0085 
0086     connect(this, &Settings::Handler::TabLayouts::dataChanged, this, &TabLayouts::updatePerLayoutButtonsState);
0087     connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, &TabLayouts::updatePerLayoutButtonsState);
0088 
0089     connect(m_inMemoryButtons, static_cast<void(QButtonGroup::*)(int, bool)>(&QButtonGroup::buttonToggled),
0090             [ = ](int id, bool checked) {
0091 
0092         if (checked) {
0093             m_layoutsController->setInMultipleMode(id == MemoryUsage::MultipleLayouts);
0094 
0095             if (id == MemoryUsage::MultipleLayouts) {
0096                 m_layoutsController->sortByColumn(Model::Layouts::ACTIVITYCOLUMN, Qt::AscendingOrder);
0097             } else {
0098                 m_layoutsController->sortByColumn(Model::Layouts::NAMECOLUMN, Qt::AscendingOrder);
0099             }
0100         }
0101     });
0102 
0103     connect(m_ui->tabWidget, &QTabWidget::currentChanged, this, &TabLayouts::currentPageChanged);
0104     connect(this, &TabLayouts::currentPageChanged, this, &TabLayouts::onCurrentPageChanged);
0105 
0106     updatePerLayoutButtonsState();
0107 }
0108 
0109 void TabLayouts::initLayoutMenu()
0110 {
0111     if (!m_layoutMenu) {
0112         m_layoutMenu = new QMenu(i18n("Layout"), m_parentDialog->appMenuBar());
0113         m_parentDialog->appMenuBar()->insertMenu(m_parentDialog->helpMenu()->menuAction(), m_layoutMenu);
0114     }
0115 
0116     m_switchLayoutAction = m_layoutMenu->addAction(i18nc("switch layout","Switch"));
0117     m_switchLayoutAction->setToolTip(i18n("Switch to selected layout"));
0118     m_switchLayoutAction->setIcon(QIcon::fromTheme("user-identity"));
0119     m_switchLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Tab));
0120     connectActionWithButton(m_ui->switchButton, m_switchLayoutAction);
0121     connect(m_switchLayoutAction, &QAction::triggered, this, &TabLayouts::switchLayout);
0122 
0123     m_activitiesManagerAction = m_layoutMenu->addAction(i18n("&Activities"));
0124     m_activitiesManagerAction->setToolTip(i18n("Show Plasma Activities manager"));
0125     m_activitiesManagerAction->setIcon(QIcon::fromTheme("activities"));
0126     m_activitiesManagerAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_A));
0127     connectActionWithButton(m_ui->activitiesButton, m_activitiesManagerAction);
0128     connect(m_activitiesManagerAction, &QAction::triggered, this, &TabLayouts::toggleActivitiesManager);
0129 
0130     m_layoutMenu->addSeparator();
0131 
0132     m_newLayoutAction = m_layoutMenu->addAction(i18nc("new layout", "&New"));
0133     m_newLayoutAction->setToolTip(i18n("New layout"));
0134     m_newLayoutAction->setIcon(QIcon::fromTheme("add"));
0135     m_newLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
0136     connectActionWithButton(m_ui->newButton, m_newLayoutAction);
0137     connect(m_newLayoutAction, &QAction::triggered, m_ui->newButton, &QPushButton::showMenu);
0138 
0139     initLayoutTemplatesSubMenu();
0140     m_newLayoutAction->setMenu(m_layoutTemplatesSubMenu);
0141     m_ui->newButton->setMenu(m_layoutTemplatesSubMenu);
0142 
0143     connect(m_corona->templatesManager(), &Latte::Templates::Manager::layoutTemplatesChanged, this, &TabLayouts::initLayoutTemplatesSubMenu);
0144 
0145     m_duplicateLayoutAction = m_layoutMenu->addAction(i18nc("duplicate layout", "&Duplicate"));
0146     m_duplicateLayoutAction->setToolTip(i18n("Duplicate selected layout"));
0147     m_duplicateLayoutAction->setIcon(QIcon::fromTheme("edit-copy"));
0148     m_duplicateLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));
0149     connectActionWithButton(m_ui->duplicateButton, m_duplicateLayoutAction);
0150     connect(m_duplicateLayoutAction, &QAction::triggered, this, &TabLayouts::duplicateLayout);
0151 
0152     m_removeLayoutAction = m_layoutMenu->addAction(i18nc("remove layout", "Remove"));
0153     m_removeLayoutAction->setToolTip(i18n("Remove selected layout"));
0154     m_removeLayoutAction->setIcon(QIcon::fromTheme("delete"));
0155     m_removeLayoutAction->setShortcut(QKeySequence(Qt::Key_Delete));
0156     connectActionWithButton(m_ui->removeButton, m_removeLayoutAction);
0157     connect(m_removeLayoutAction, &QAction::triggered, this, &TabLayouts::removeLayout);
0158     m_ui->removeButton->addAction(m_removeLayoutAction); //this is needed in order to be triggered properly
0159 
0160     m_layoutMenu->addSeparator();
0161 
0162     m_enabledLayoutAction = m_layoutMenu->addAction(i18n("Ena&bled"));
0163     m_enabledLayoutAction->setToolTip(i18n("Assign in activities in order to be activated through Plasma Activities"));
0164     m_enabledLayoutAction->setIcon(QIcon::fromTheme("edit-link"));
0165     m_enabledLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
0166     m_enabledLayoutAction->setCheckable(true);
0167     connectActionWithButton(m_ui->enabledButton, m_enabledLayoutAction);
0168     connect(m_enabledLayoutAction, &QAction::triggered, this, &TabLayouts::toggleEnabledLayout);
0169 
0170     m_readOnlyLayoutAction = m_layoutMenu->addAction(i18nc("read only layout", "&Read Only"));
0171     m_readOnlyLayoutAction->setToolTip(i18n("Make selected layout read-only"));
0172     m_readOnlyLayoutAction->setIcon(QIcon::fromTheme("object-locked"));
0173     m_readOnlyLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
0174     m_readOnlyLayoutAction->setCheckable(true);
0175     connectActionWithButton(m_ui->readOnlyButton, m_readOnlyLayoutAction);
0176     connect(m_readOnlyLayoutAction, &QAction::triggered, this, &TabLayouts::lockLayout);
0177 
0178     m_viewsAction = m_layoutMenu->addAction(i18nc("layout docks / panels", "Docks, &Panels..."));
0179     m_viewsAction->setToolTip(i18n("Show selected layouts docks and panels"));
0180     m_viewsAction->setIcon(QIcon::fromTheme("window"));
0181     m_viewsAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
0182     connectActionWithButton(m_ui->viewsBtn, m_viewsAction);
0183     connect(m_viewsAction, &QAction::triggered, this, &TabLayouts::showViewsDialog);
0184 
0185     m_detailsAction = m_layoutMenu->addAction(i18nc("layout details", "De&tails..."));
0186     m_detailsAction->setToolTip(i18n("Show selected layout details"));
0187     m_detailsAction->setIcon(QIcon::fromTheme("view-list-details"));
0188     m_detailsAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_T));
0189     connectActionWithButton(m_ui->detailsButton, m_detailsAction);
0190     connect(m_detailsAction, &QAction::triggered, this, &TabLayouts::showDetailsDialog);
0191 
0192     m_layoutMenu->addSeparator();
0193 
0194 
0195     //! Import
0196     m_importLayoutAction = m_layoutMenu->addAction(i18nc("import layout", "&Import"));
0197     m_importLayoutAction->setToolTip(i18n("Import layout from various resources"));
0198     m_importLayoutAction->setIcon(QIcon::fromTheme("document-import"));
0199     m_importLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I));
0200     connectActionWithButton(m_ui->importButton, m_importLayoutAction);
0201     connect(m_importLayoutAction, &QAction::triggered, m_ui->importButton, &QPushButton::showMenu);
0202 
0203     initImportLayoutSubMenu();
0204     m_importLayoutAction->setMenu(m_layoutImportSubMenu);
0205     m_ui->importButton->setMenu(m_layoutImportSubMenu);
0206 
0207     //! Export
0208     m_exportLayoutAction = m_layoutMenu->addAction(i18nc("export layout", "&Export"));
0209     m_exportLayoutAction->setToolTip(i18n("Export selected layout at your system"));
0210     m_exportLayoutAction->setIcon(QIcon::fromTheme("document-export"));
0211     m_exportLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E));
0212     connectActionWithButton(m_ui->exportButton, m_exportLayoutAction);
0213     connect(m_exportLayoutAction, &QAction::triggered, m_ui->exportButton, &QPushButton::showMenu);
0214 
0215     initExportLayoutSubMenu();
0216     m_exportLayoutAction->setMenu(m_layoutExportSubMenu);
0217     m_ui->exportButton->setMenu(m_layoutExportSubMenu);
0218 }
0219 
0220 void TabLayouts::initImportLayoutSubMenu()
0221 {
0222     if (!m_layoutImportSubMenu) {
0223         m_layoutImportSubMenu = new QMenu(m_layoutMenu);
0224         m_layoutImportSubMenu->setMinimumWidth(m_ui->importButton->width() * 2);
0225     } else {
0226         m_layoutImportSubMenu->clear();
0227     }
0228 
0229     QAction *importLayoutAction = m_layoutImportSubMenu->addAction(i18nc("import layout", "&Import From Local File..."));
0230     importLayoutAction->setIcon(QIcon::fromTheme("document-import"));
0231     importLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
0232     connect(importLayoutAction, &QAction::triggered, this, &TabLayouts::importLayout);
0233 
0234     QAction *downloadLayoutAction = m_layoutImportSubMenu->addAction(i18nc("download layout", "Import From K&DE Online Store..."));
0235     downloadLayoutAction->setIcon(QIcon::fromTheme("get-hot-new-stuff"));
0236     downloadLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D));
0237     connect(downloadLayoutAction, &QAction::triggered, this, &TabLayouts::downloadLayout);
0238 }
0239 
0240 void TabLayouts::initExportLayoutSubMenu()
0241 {
0242     if (!m_layoutExportSubMenu) {
0243         m_layoutExportSubMenu = new QMenu(m_layoutMenu);
0244         m_layoutExportSubMenu->setMinimumWidth(m_ui->exportButton->width() * 2);
0245     } else {
0246         m_layoutExportSubMenu->clear();
0247     }
0248 
0249     QAction *exportForBackup = m_layoutExportSubMenu->addAction(i18nc("export for backup","&Export For Backup..."));
0250     exportForBackup->setIcon(QIcon::fromTheme("document-export"));
0251     exportForBackup->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT  + Qt::Key_E));
0252     connect(exportForBackup, &QAction::triggered, this, &TabLayouts::exportLayoutForBackup);
0253 
0254     QAction *exportAsTemplate = m_layoutExportSubMenu->addAction(i18nc("export as template","Export As &Template..."));
0255     exportAsTemplate->setIcon(QIcon::fromTheme("document-export"));
0256     exportAsTemplate->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT  + Qt::Key_T));
0257     connect(exportAsTemplate, &QAction::triggered, this, &TabLayouts::exportLayoutAsTemplate);
0258 }
0259 
0260 void TabLayouts::initLayoutTemplatesSubMenu()
0261 {
0262     if (!m_layoutTemplatesSubMenu) {
0263         m_layoutTemplatesSubMenu = new QMenu(m_layoutMenu);
0264         m_layoutTemplatesSubMenu->setMinimumWidth(m_ui->newButton->width() * 2);
0265     } else {
0266         m_layoutTemplatesSubMenu->clear();
0267     }
0268 
0269     /*Add Layout Templates for New Action*/
0270     Data::LayoutsTable templates = m_corona->templatesManager()->layoutTemplates();
0271 
0272     bool customtemplateseparatoradded{false};
0273 
0274     for (int i=0; i<templates.rowCount(); ++i) {
0275         if (!customtemplateseparatoradded && !templates[i].isSystemTemplate()) {
0276             m_layoutTemplatesSubMenu->addSeparator();
0277             customtemplateseparatoradded = true;
0278         }
0279 
0280         QAction *newlayout = m_layoutTemplatesSubMenu->addAction(templates[i].name);
0281         newlayout->setIcon(QIcon::fromTheme("document-new"));
0282         QString templatename = templates[i].name;
0283 
0284         connect(newlayout, &QAction::triggered, this, [&, templatename]() {
0285             newLayout(templatename);
0286         });
0287     }
0288 
0289     if (templates.rowCount() > 0) {
0290         QAction *openTemplatesDirectory = m_layoutTemplatesSubMenu->addAction(i18n("Templates..."));
0291         openTemplatesDirectory->setToolTip(i18n("Open templates directory"));
0292         openTemplatesDirectory->setIcon(QIcon::fromTheme("edit"));
0293 
0294         connect(openTemplatesDirectory, &QAction::triggered, this, [&]() {
0295             KIO::highlightInFileManager({QString(Latte::configPath() + "/latte/templates/Dock.layout.latte")});
0296         });
0297     }
0298 }
0299 
0300 Latte::Corona *TabLayouts::corona() const
0301 {
0302     return m_corona;
0303 }
0304 
0305 Settings::Dialog::SettingsDialog *TabLayouts::dialog() const
0306 {
0307     return m_parentDialog;
0308 }
0309 
0310 Ui::SettingsDialog *TabLayouts::ui() const
0311 {
0312     return m_ui;
0313 }
0314 
0315 Controller::Layouts *TabLayouts::layoutsController() const
0316 {
0317     return m_layoutsController;
0318 }
0319 
0320 bool TabLayouts::hasChangedData() const
0321 {
0322     return m_layoutsController->hasChangedData();
0323 }
0324 
0325 bool TabLayouts::inDefaultValues() const
0326 {
0327     return true;
0328 }
0329 
0330 bool TabLayouts::isViewsDialogVisible() const
0331 {
0332     return m_isViewsDialogVisible;
0333 }
0334 
0335 void TabLayouts::reset()
0336 {
0337     m_layoutsController->reset();
0338 
0339     if (m_layoutsController->inMultipleMode()) {
0340         m_ui->multipleToolBtn->setChecked(true);
0341     } else {
0342         m_ui->singleToolBtn->setChecked(true);
0343     }
0344 }
0345 
0346 void TabLayouts::resetDefaults()
0347 {
0348     //do nothing because there are no defaults
0349 }
0350 
0351 void TabLayouts::save()
0352 {
0353     m_layoutsController->save();
0354 }
0355 
0356 void TabLayouts::switchLayout()
0357 {
0358     if (!isCurrentTab() || !m_switchLayoutAction->isEnabled()) {
0359         return;
0360     }
0361 
0362     Latte::Data::Layout selectedLayoutCurrent = m_layoutsController->selectedLayoutCurrentData();
0363     Latte::Data::Layout selectedLayoutOriginal = m_layoutsController->selectedLayoutOriginalData();
0364     selectedLayoutOriginal = selectedLayoutOriginal.isEmpty() ? selectedLayoutCurrent : selectedLayoutOriginal;
0365 
0366     if (m_layoutsController->layoutsAreChanged()) {
0367         showInlineMessage(i18nc("settings:not permitted switching layout","You need to <b>apply</b> your changes first to switch layout afterwards..."),
0368                           KMessageWidget::Warning);
0369         return;
0370     }
0371 
0372     m_layoutsController->setOriginalInMultipleMode(false);
0373     m_corona->layoutsManager()->switchToLayout(selectedLayoutOriginal.name, MemoryUsage::SingleLayout);
0374 
0375     updatePerLayoutButtonsState();
0376 }
0377 
0378 void TabLayouts::toggleActivitiesManager()
0379 {
0380     QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.plasmashell"),
0381                                                           QStringLiteral("/PlasmaShell"),
0382                                                           QStringLiteral("org.kde.PlasmaShell"),
0383                                                           QStringLiteral("toggleActivityManager"));
0384 
0385     QDBusConnection::sessionBus().call(message, QDBus::NoBlock);
0386 }
0387 
0388 void TabLayouts::toggleEnabledLayout()
0389 {
0390     qDebug() << Q_FUNC_INFO;
0391 
0392     if (!isCurrentTab() || !m_layoutsController->inMultipleMode()) {
0393         return;
0394     }
0395 
0396     m_layoutsController->toggleEnabledForSelected();
0397 
0398     updatePerLayoutButtonsState();
0399 }
0400 
0401 void TabLayouts::updatePerLayoutButtonsState()
0402 {
0403     //! UI Elements that need to be shown/hidden
0404     setTwinProperty(m_switchLayoutAction, TWINVISIBLE, !m_layoutsController->inMultipleMode());
0405     setTwinProperty(m_activitiesManagerAction, TWINVISIBLE, m_layoutsController->inMultipleMode());
0406     setTwinProperty(m_enabledLayoutAction, TWINVISIBLE, m_layoutsController->inMultipleMode());
0407 
0408     if (!m_layoutsController->hasSelectedLayout()) {
0409         setTwinProperty(m_enabledLayoutAction, TWINENABLED, false);
0410         return;
0411     }
0412 
0413     Latte::Data::Layout selectedLayout = m_layoutsController->selectedLayoutCurrentData();
0414 
0415     //! Switch Button
0416     setTwinProperty(m_switchLayoutAction, TWINENABLED, true);
0417 
0418     //! Enabled Button
0419     setTwinProperty(m_enabledLayoutAction, TWINENABLED, true);
0420     setTwinProperty(m_enabledLayoutAction, TWINCHECKED, !selectedLayout.activities.isEmpty());
0421 
0422     //! Layout Read-Only Button
0423     setTwinProperty(m_readOnlyLayoutAction, TWINCHECKED, selectedLayout.isLocked);
0424 
0425     //! Details Button
0426     setTwinProperty(m_detailsAction, TWINENABLED, true);
0427 }
0428 
0429 void TabLayouts::newLayout(const QString &templateName)
0430 {
0431     qDebug() << Q_FUNC_INFO;
0432 
0433     if (!isCurrentTab() || !m_newLayoutAction->isEnabled()) {
0434         return;
0435     }
0436 
0437     //! retrieve Default layout template
0438     Data::Layout tdata = m_corona->templatesManager()->layoutTemplateForName(templateName);
0439 
0440     if (!tdata.isNull()) {
0441         Data::Layout newlayout = m_layoutsController->addLayoutForFile(tdata.id, tdata.name, true);
0442 
0443         if (newlayout.errors == 0 && newlayout.warnings == 0) {
0444             showInlineMessage(i18nc("settings:layout added successfully","Layout <b>%1</b> added successfully...", newlayout.name),
0445                               KMessageWidget::Positive);
0446         }
0447     }
0448 }
0449 
0450 void TabLayouts::duplicateLayout()
0451 {
0452     qDebug() << Q_FUNC_INFO;
0453 
0454     if (!isCurrentTab() || !m_duplicateLayoutAction->isEnabled()) {
0455         return;
0456     }
0457 
0458     m_layoutsController->duplicateSelectedLayout();
0459 }
0460 
0461 void TabLayouts::downloadLayout()
0462 {
0463     qDebug() << Q_FUNC_INFO;
0464 
0465     if (!isCurrentTab()) {
0466         return;
0467     }
0468 
0469     KNS3::DownloadDialog dialog(QStringLiteral("latte-layouts.knsrc"), m_parentDialog);
0470     dialog.resize(m_parentDialog->downloadWindowSize());
0471     dialog.exec();
0472 
0473     if (!dialog.changedEntries().isEmpty() && !dialog.installedEntries().isEmpty()) {
0474         for (const auto &entry : dialog.installedEntries()) {
0475             for (const auto &entryFile : entry.installedFiles()) {
0476                 Latte::Layouts::Importer::LatteFileVersion version = Latte::Layouts::Importer::fileVersion(entryFile);
0477 
0478                 if (version == Latte::Layouts::Importer::LayoutVersion2) {
0479                     Latte::Data::Layout downloaded = m_layoutsController->addLayoutForFile(entryFile);
0480                     showInlineMessage(i18nc("settings:layout downloaded successfully","Layout <b>%1</b> downloaded successfully...", downloaded.name),
0481                                       KMessageWidget::Positive);
0482                     break;
0483                 }
0484             }
0485         }
0486     }
0487 
0488     m_parentDialog->setDownloadWindowSize(dialog.size());
0489 }
0490 
0491 void TabLayouts::removeLayout()
0492 {
0493     qDebug() << Q_FUNC_INFO;
0494 
0495     if (!isCurrentTab() || !m_removeLayoutAction->isEnabled()) {
0496         return;
0497     }
0498 
0499     if (!m_layoutsController->hasSelectedLayout()) {
0500         return;
0501     }
0502 
0503     Latte::Data::Layout selectedLayout = m_layoutsController->selectedLayoutCurrentData();
0504 
0505     if (selectedLayout.isActive) {
0506         showInlineMessage(i18nc("settings: active layout remove","<b>Active</b> layouts can not be removed..."),
0507                           KMessageWidget::Error);
0508         return;
0509     }
0510 
0511     if (selectedLayout.isLocked) {
0512         showInlineMessage(i18nc("settings: locked layout remove","Locked layouts can not be removed..."),
0513                           KMessageWidget::Error);
0514         return;
0515     }
0516 
0517     m_layoutsController->removeSelected();
0518 }
0519 
0520 void TabLayouts::lockLayout()
0521 {
0522     qDebug() << Q_FUNC_INFO;
0523 
0524     if (!isCurrentTab() || !m_readOnlyLayoutAction->isEnabled()) {
0525         return;
0526     }
0527 
0528     m_layoutsController->toggleLockedForSelected();
0529 
0530     updatePerLayoutButtonsState();
0531 }
0532 
0533 void TabLayouts::importLayout()
0534 {
0535     qDebug() << Q_FUNC_INFO;
0536 
0537     if (!isCurrentTab() || !m_importLayoutAction->isEnabled()) {
0538         return;
0539     }
0540 
0541     QFileDialog *importFileDialog = new QFileDialog(m_parentDialog, i18nc("import layout", "Import Layout"), QDir::homePath(), QStringLiteral("layout.latte"));
0542 
0543     importFileDialog->setWindowIcon(QIcon::fromTheme("document-import"));
0544     importFileDialog->setLabelText(QFileDialog::Accept, i18nc("import layout","Import"));
0545     importFileDialog->setFileMode(QFileDialog::AnyFile);
0546     importFileDialog->setAcceptMode(QFileDialog::AcceptOpen);
0547     importFileDialog->setDefaultSuffix("layout.latte");
0548 
0549     QStringList filters;
0550     filters << QString(i18nc("import latte layout", "Latte Dock Layout file v0.2") + "(*.layout.latte)")
0551             << QString(i18nc("import older latte layout", "Latte Dock Layout file v0.1") + "(*.latterc)");
0552     importFileDialog->setNameFilters(filters);
0553 
0554     connect(importFileDialog, &QFileDialog::finished, importFileDialog, &QFileDialog::deleteLater);
0555 
0556     connect(importFileDialog, &QFileDialog::fileSelected, this, [&](const QString & file) {
0557         Latte::Layouts::Importer::LatteFileVersion version = Latte::Layouts::Importer::fileVersion(file);
0558         qDebug() << "VERSION :::: " << version;
0559 
0560         if (version == Latte::Layouts::Importer::LayoutVersion2) {
0561             Latte::Data::Layout importedlayout = m_layoutsController->addLayoutForFile(file);
0562             showInlineMessage(i18nc("settings:layout imported successfully","Layout <b>%1</b> imported successfully...", importedlayout.name),
0563                               KMessageWidget::Positive);
0564         } else if (version == Latte::Layouts::Importer::ConfigVersion1) {
0565             if (!m_layoutsController->importLayoutsFromV1ConfigFile(file)) {
0566                 showInlineMessage(i18nc("settings:deprecated layouts import failed","Import layouts from deprecated version <b>failed</b>..."),
0567                                   KMessageWidget::Error,
0568                                   true);
0569             }
0570         }
0571     });
0572 
0573     importFileDialog->open();
0574 }
0575 
0576 void TabLayouts::exportLayoutAsTemplate()
0577 {
0578     qDebug() << Q_FUNC_INFO;
0579 
0580     if (!isCurrentTab() || !m_exportLayoutAction->isEnabled()) {
0581         return;
0582     }
0583 
0584     if (!m_layoutsController->hasSelectedLayout()) {
0585         return;
0586     }
0587 
0588     Data::Layout o_layout = m_layoutsController->selectedLayoutOriginalData();
0589     Data::Layout c_layout = m_layoutsController->selectedLayoutCurrentData();
0590 
0591     Data::Layout exp_layout = o_layout;
0592     exp_layout.name = c_layout.name;
0593 
0594     CentralLayout *central =  m_layoutsController->centralLayout(c_layout.id);
0595 
0596     if (central->isActive()) {
0597         central->syncToLayoutFile();
0598     }
0599 
0600     Dialog::ExportTemplateDialog *exportDlg = new Dialog::ExportTemplateDialog(m_parentDialog, exp_layout);
0601     exportDlg->exec();
0602 }
0603 
0604 void TabLayouts::exportLayoutForBackup()
0605 {
0606     qDebug() << Q_FUNC_INFO;
0607 
0608     if (!isCurrentTab() || !m_exportLayoutAction->isEnabled()) {
0609         return;
0610     }
0611 
0612     if (!m_layoutsController->hasSelectedLayout()) {
0613         return;
0614     }
0615 
0616     Latte::Data::Layout selectedLayout = m_layoutsController->selectedLayoutCurrentData();
0617 
0618     //! Update ALL active original layouts before exporting,
0619     m_corona->layoutsManager()->synchronizer()->syncActiveLayoutsToOriginalFiles();
0620     m_corona->universalSettings()->syncSettings();
0621 
0622     QFileDialog *exportFileDialog = new QFileDialog(m_parentDialog, i18n("Export Layout For Backup"), QDir::homePath(), QStringLiteral("layout.latte"));
0623 
0624     exportFileDialog->setLabelText(QFileDialog::Accept, i18nc("export layout","Export"));
0625     exportFileDialog->setFileMode(QFileDialog::AnyFile);
0626     exportFileDialog->setAcceptMode(QFileDialog::AcceptSave);
0627     exportFileDialog->setDefaultSuffix("layout.latte");
0628 
0629     QStringList filters;
0630     QString filter1(i18nc("export layout", "Latte Dock Layout file v0.2") + "(*.layout.latte)");
0631 
0632     filters << filter1;
0633 
0634     exportFileDialog->setNameFilters(filters);
0635 
0636     connect(exportFileDialog, &QFileDialog::finished, exportFileDialog, &QFileDialog::deleteLater);
0637 
0638     connect(exportFileDialog, &QFileDialog::fileSelected, this, [ &, selectedLayout](const QString & file) {
0639         auto showExportLayoutError = [this](const Latte::Data::Layout &layout) {
0640             showInlineMessage(i18nc("settings:layout export fail","Layout <b>%1</b> export <b>failed</b>...", layout.name),
0641                               KMessageWidget::Error,
0642                               true);
0643         };
0644 
0645         if (QFile::exists(file) && !QFile::remove(file)) {
0646             showExportLayoutError(selectedLayout);
0647             return;
0648         }
0649 
0650         if (file.endsWith(".layout.latte")) {
0651             if (!QFile(selectedLayout.id).copy(file)) {
0652                 showExportLayoutError(selectedLayout);
0653                 return;
0654             }
0655 
0656             QFileInfo newFileInfo(file);
0657 
0658             if (newFileInfo.exists() && !newFileInfo.isWritable()) {
0659                 QFile(file).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther);
0660             }
0661 
0662             // cleanup clones from exported file
0663             Latte::Layouts::Storage::self()->removeAllClonedViews(file);
0664 
0665             CentralLayout layoutS(this, file);
0666             layoutS.setActivities(QStringList());
0667             layoutS.clearLastUsedActivity();
0668 
0669             QAction *openUrlAction = new QAction(i18n("Open Location..."), this);
0670             openUrlAction->setData(file);
0671             QList<QAction *> actions;
0672             actions << openUrlAction;
0673 
0674             connect(openUrlAction, &QAction::triggered, this, [&, openUrlAction]() {
0675                 QString file = openUrlAction->data().toString();
0676 
0677                 if (!file.isEmpty()) {
0678                     KIO::highlightInFileManager({file});
0679                 }
0680             });
0681 
0682             showInlineMessage(i18nc("settings:layout export success","Layout <b>%1</b> export succeeded...", selectedLayout.name),
0683                               KMessageWidget::Positive,
0684                               false,
0685                               actions);
0686         } else if (file.endsWith(".latterc")) {
0687             auto showExportConfigurationError = [this]() {
0688                 showInlineMessage(i18n("Full configuration export <b>failed</b>..."),
0689                                   KMessageWidget::Error,
0690                                   true);
0691             };
0692 
0693             if (m_corona->layoutsManager()->importer()->exportFullConfiguration(file)) {
0694                 QAction *openUrlAction = new QAction(i18n("Open Location..."), this);
0695                 openUrlAction->setIcon(QIcon::fromTheme("document-open"));
0696                 openUrlAction->setData(file);
0697                 QList<QAction *> actions;
0698                 actions << openUrlAction;
0699 
0700                 connect(openUrlAction, &QAction::triggered, this, [&, openUrlAction]() {
0701                     QString file = openUrlAction->data().toString();
0702 
0703                     if (!file.isEmpty()) {
0704                         KIO::highlightInFileManager({file});
0705                     }
0706                 });
0707 
0708                 showInlineMessage(i18n("Full configuration export succeeded..."),
0709                                   KMessageWidget::Positive,
0710                                   false,
0711                                   actions);
0712             } else {
0713                 showExportConfigurationError();
0714             }
0715         }
0716     });
0717 
0718     exportFileDialog->open();
0719     exportFileDialog->selectFile(selectedLayout.name + ".layout.latte");
0720 }
0721 
0722 void TabLayouts::showDetailsDialog()
0723 {
0724     qDebug() << Q_FUNC_INFO;
0725 
0726     if (!isCurrentTab() || !m_detailsAction->isEnabled()) {
0727         return;
0728     }
0729 
0730     if (!m_layoutsController->hasSelectedLayout()) {
0731         return;
0732     }
0733 
0734     Latte::Data::Layout selectedLayout = m_layoutsController->selectedLayoutCurrentData();
0735     auto detailsDlg = new Settings::Dialog::DetailsDialog(m_parentDialog, m_layoutsController);
0736 
0737     detailsDlg->exec();
0738 }
0739 
0740 void TabLayouts::showViewsDialog()
0741 {
0742     qDebug() << Q_FUNC_INFO;
0743 
0744     if (!isCurrentTab() || !m_viewsAction->isEnabled()) {
0745         return;
0746     }
0747 
0748     if (!m_layoutsController->hasSelectedLayout()) {
0749         return;
0750     }
0751 
0752     Latte::Data::Layout selectedLayout = m_layoutsController->selectedLayoutCurrentData();
0753     auto viewsDlg = new Settings::Dialog::ViewsDialog(m_parentDialog, m_layoutsController);
0754 
0755     m_isViewsDialogVisible = true;
0756     viewsDlg->exec();
0757     m_isViewsDialogVisible = false;
0758 }
0759 
0760 void TabLayouts::onLayoutFilesDropped(const QStringList &paths)
0761 {
0762     QStringList layoutNames;
0763 
0764     for (int i=0; i<paths.count(); ++i) {
0765         if (paths[i].endsWith(".layout.latte")) {
0766             Latte::Data::Layout importedlayout = m_layoutsController->addLayoutForFile(paths[i]);
0767             layoutNames << importedlayout.name;
0768         }
0769     }
0770 
0771     if(layoutNames.count() > 0) {
0772         showInlineMessage(i18ncp("settings:layout imported successfully",
0773                                  "Layout <b>%2</b> imported successfully...",
0774                                  "Layouts <b>%2</b> imported successfully...",
0775                                  layoutNames.count(),
0776                                  layoutNames.join(", ")),
0777                 KMessageWidget::Positive);
0778     }
0779 }
0780 
0781 void TabLayouts::onRawLayoutDropped(const QString &rawLayout)
0782 {
0783     Latte::Data::Layout importedlayout = m_layoutsController->addLayoutByText(rawLayout);
0784     showInlineMessage(i18nc("settings:layout imported successfully","Layout <b>%1</b> imported successfully...", importedlayout.name),
0785                       KMessageWidget::Positive);
0786 }
0787 
0788 bool TabLayouts::isCurrentTab() const
0789 {
0790     return (m_parentDialog->currentPage() == Dialog::LayoutPage);
0791 }
0792 
0793 bool TabLayouts::isHoveringLayoutsTable(const QPoint &pos)
0794 {
0795     QPoint topLeft = m_ui->layoutsView->mapTo(m_parentDialog, QPoint(0,0));
0796     QRect geometry = m_ui->layoutsView->rect();
0797     geometry.moveTopLeft(topLeft);
0798 
0799     return geometry.contains(pos);
0800 }
0801 
0802 
0803 void TabLayouts::onCurrentPageChanged()
0804 {
0805     //int page = m_dialog->currentPage();
0806     Dialog::ConfigurationPage cPage= m_parentDialog->currentPage();// static_cast<Dialog::ConfigurationPage>(page);
0807 
0808     if (cPage == Dialog::LayoutPage) {
0809         m_layoutMenu->setEnabled(true);
0810         m_layoutMenu->menuAction()->setVisible(true);
0811 
0812     } else {
0813         m_layoutMenu->menuAction()->setVisible(false);
0814         m_layoutMenu->setEnabled(false);
0815     }
0816 }
0817 
0818 void TabLayouts::onDragEnterEvent(QDragEnterEvent *event)
0819 {
0820     if (!isHoveringLayoutsTable(event->pos())) {
0821         return;
0822     }
0823 
0824     event->acceptProposedAction();
0825     m_ui->layoutsView->dragEntered(event);
0826 }
0827 
0828 void TabLayouts::onDragLeaveEvent(QDragLeaveEvent *event)
0829 {
0830     m_ui->layoutsView->dragLeft();
0831 }
0832 
0833 void TabLayouts::onDragMoveEvent(QDragMoveEvent *event)
0834 {
0835     if (!isHoveringLayoutsTable(event->pos())) {
0836         event->ignore();
0837         m_ui->layoutsView->dragLeft();
0838         return;
0839     }
0840 
0841     event->acceptProposedAction();
0842 }
0843 
0844 void TabLayouts::onDropEvent(QDropEvent *event)
0845 {
0846     if (!isHoveringLayoutsTable(event->pos())) {
0847         event->ignore();
0848         m_ui->layoutsView->dragLeft();
0849         return;
0850     }
0851 
0852     if (event->mimeData()->hasUrls()) {
0853         QList<QUrl> urlList = event->mimeData()->urls();
0854 
0855         QStringList paths;
0856 
0857         for (int i = 0; i < qMin(urlList.size(), 20); ++i) {
0858             QString layoutPath = urlList[i].path();
0859 
0860             if (layoutPath.endsWith(".layout.latte")) {
0861                 paths << layoutPath;
0862             }
0863         }
0864 
0865         if (paths.count() > 0) {
0866             onLayoutFilesDropped(paths);
0867         }
0868 
0869         m_ui->layoutsView->dragLeft();
0870     } else if (event->mimeData()->hasText()){
0871         if(!event->mimeData()->text().isEmpty()){
0872             onRawLayoutDropped(event->mimeData()->text());
0873         } else if(!event->mimeData()->data("text/plain").isEmpty()) {
0874             onRawLayoutDropped(event->mimeData()->data("text/plain"));
0875         } else {
0876             qDebug() << "Data from drag could not be retrieved!";
0877         }
0878         m_ui->layoutsView->dragLeft();
0879     }
0880 }
0881 
0882 
0883 void TabLayouts::loadConfig()
0884 {
0885     //load settings
0886 }
0887 
0888 void TabLayouts::saveConfig()
0889 {
0890     //save settings
0891 }
0892 
0893 }
0894 }
0895 }
0896