File indexing completed on 2024-10-13 04:54:45
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