File indexing completed on 2024-04-21 16:17:12
0001 /* 0002 * Copyright 2017 Smith AR <audoban@openmailbox.org> 0003 * Michail Vourlakos <mvourlakos@gmail.com> 0004 * 0005 * This file is part of Latte-Dock 0006 * 0007 * Latte-Dock is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU General Public License as 0009 * published by the Free Software Foundation; either version 2 of 0010 * the License, or (at your option) any later version. 0011 * 0012 * Latte-Dock is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0015 * GNU General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU General Public License 0018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0019 * 0020 */ 0021 0022 #include "settingsdialog.h" 0023 0024 // local 0025 #include "universalsettings.h" 0026 #include "ui_settingsdialog.h" 0027 #include "../lattecorona.h" 0028 #include "../screenpool.h" 0029 #include "../layout/genericlayout.h" 0030 #include "../layout/centrallayout.h" 0031 #include "../layout/sharedlayout.h" 0032 #include "../layouts/importer.h" 0033 #include "../layouts/manager.h" 0034 #include "../layouts/synchronizer.h" 0035 #include "../liblatte2/types.h" 0036 #include "../plasma/extended/theme.h" 0037 #include "delegates/activitiesdelegate.h" 0038 #include "delegates/checkboxdelegate.h" 0039 #include "delegates/colorcmbboxdelegate.h" 0040 #include "delegates/layoutnamedelegate.h" 0041 #include "delegates/shareddelegate.h" 0042 0043 // Qt 0044 #include <QButtonGroup> 0045 #include <QColorDialog> 0046 #include <QDesktopServices> 0047 #include <QDir> 0048 #include <QFileDialog> 0049 #include <QHeaderView> 0050 #include <QMenuBar> 0051 #include <QMessageBox> 0052 #include <QProcess> 0053 #include <QStandardItem> 0054 #include <QStandardItemModel> 0055 #include <QTemporaryDir> 0056 0057 // KDE 0058 #include <KActivities/Controller> 0059 #include <KArchive/KTar> 0060 #include <KArchive/KArchiveEntry> 0061 #include <KArchive/KArchiveDirectory> 0062 #include <KLocalizedString> 0063 #include <KNotification> 0064 #include <KWindowSystem> 0065 #include <KNewStuff3/KNS3/DownloadDialog> 0066 0067 namespace Latte { 0068 0069 const int IDCOLUMN = 0; 0070 const int HIDDENTEXTCOLUMN = 1; 0071 const int COLORCOLUMN = 2; 0072 const int NAMECOLUMN = 3; 0073 const int MENUCOLUMN = 4; 0074 const int BORDERSCOLUMN = 5; 0075 const int ACTIVITYCOLUMN = 6; 0076 const int SHAREDCOLUMN = 7; 0077 0078 const int SCREENTRACKERDEFAULTVALUE = 2500; 0079 const int OUTLINEDEFAULTWIDTH = 1; 0080 0081 const QChar CheckMark{0x2714}; 0082 0083 SettingsDialog::SettingsDialog(QWidget *parent, Latte::Corona *corona) 0084 : QDialog(parent), 0085 ui(new Ui::SettingsDialog), 0086 m_corona(corona) 0087 { 0088 ui->setupUi(this); 0089 0090 setAttribute(Qt::WA_DeleteOnClose, true); 0091 setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); 0092 resize(m_corona->universalSettings()->layoutsWindowSize()); 0093 0094 connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked 0095 , this, &SettingsDialog::apply); 0096 connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked 0097 , this, &SettingsDialog::restoreDefaults); 0098 0099 m_model = new QStandardItemModel(m_corona->layoutsManager()->layouts().count(), 6, this); 0100 0101 ui->layoutsView->setModel(m_model); 0102 ui->layoutsView->horizontalHeader()->setStretchLastSection(true); 0103 ui->layoutsView->verticalHeader()->setVisible(false); 0104 0105 connect(m_corona->layoutsManager(), &Layouts::Manager::currentLayoutNameChanged, this, &SettingsDialog::layoutsChanged); 0106 connect(m_corona->layoutsManager(), &Layouts::Manager::centralLayoutsChanged, this, &SettingsDialog::layoutsChanged); 0107 0108 QString iconsPath(m_corona->kPackage().path() + "../../plasmoids/org.kde.latte.containment/contents/icons/"); 0109 0110 //!find the available colors 0111 QDir layoutDir(iconsPath); 0112 QStringList filter; 0113 filter.append(QString("*print.jpg")); 0114 QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); 0115 QStringList colors; 0116 0117 for (auto &file : files) { 0118 int colorEnd = file.lastIndexOf("print.jpg"); 0119 QString color = file.remove(colorEnd, 9); 0120 colors.append(color); 0121 } 0122 0123 ui->layoutsView->setItemDelegateForColumn(NAMECOLUMN, new LayoutNameDelegate(this)); 0124 ui->layoutsView->setItemDelegateForColumn(COLORCOLUMN, new ColorCmbBoxDelegate(this, iconsPath, colors)); 0125 ui->layoutsView->setItemDelegateForColumn(MENUCOLUMN, new CheckBoxDelegate(this)); 0126 ui->layoutsView->setItemDelegateForColumn(BORDERSCOLUMN, new CheckBoxDelegate(this)); 0127 ui->layoutsView->setItemDelegateForColumn(ACTIVITYCOLUMN, new ActivitiesDelegate(this)); 0128 ui->layoutsView->setItemDelegateForColumn(SHAREDCOLUMN, new SharedDelegate(this)); 0129 0130 m_inMemoryButtons = new QButtonGroup(this); 0131 m_inMemoryButtons->addButton(ui->singleToolBtn, Latte::Types::SingleLayout); 0132 m_inMemoryButtons->addButton(ui->multipleToolBtn, Latte::Types::MultipleLayouts); 0133 m_inMemoryButtons->setExclusive(true); 0134 0135 if (KWindowSystem::isPlatformWayland()) { 0136 m_inMemoryButtons->button(Latte::Types::MultipleLayouts)->setEnabled(false); 0137 } 0138 0139 m_mouseSensitivityButtons = new QButtonGroup(this); 0140 m_mouseSensitivityButtons->addButton(ui->lowSensitivityBtn, Latte::Types::LowSensitivity); 0141 m_mouseSensitivityButtons->addButton(ui->mediumSensitivityBtn, Latte::Types::MediumSensitivity); 0142 m_mouseSensitivityButtons->addButton(ui->highSensitivityBtn, Latte::Types::HighSensitivity); 0143 m_mouseSensitivityButtons->setExclusive(true); 0144 0145 ui->screenTrackerSpinBox->setValue(m_corona->universalSettings()->screenTrackerInterval()); 0146 ui->outlineSpinBox->setValue(m_corona->themeExtended()->outlineWidth()); 0147 0148 //! About Menu 0149 QMenuBar *menuBar = new QMenuBar(this); 0150 // QMenuBar *rightAlignedMenuBar = new QMenuBar(menuBar); 0151 0152 layout()->setMenuBar(menuBar); 0153 //menuBar->setCornerWidget(rightAlignedMenuBar); 0154 0155 QMenu *fileMenu = new QMenu(i18n("File"), menuBar); 0156 menuBar->addMenu(fileMenu); 0157 0158 QMenu *layoutMenu = new QMenu(i18n("Layout"), menuBar); 0159 menuBar->addMenu(layoutMenu); 0160 0161 //! Help menu 0162 m_helpMenu = new KHelpMenu(menuBar); 0163 menuBar->addMenu(m_helpMenu->menu()); 0164 //rightAlignedMenuBar->addMenu(helpMenu); 0165 0166 //! hide help menu actions that are not used 0167 m_helpMenu->action(KHelpMenu::menuHelpContents)->setVisible(false); 0168 m_helpMenu->action(KHelpMenu::menuWhatsThis)->setVisible(false); 0169 0170 0171 QAction *screensAction = fileMenu->addAction(i18n("Sc&reens...")); 0172 screensAction->setIcon(QIcon::fromTheme("document-properties")); 0173 screensAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R)); 0174 0175 QAction *quitAction = fileMenu->addAction(i18n("&Quit Latte")); 0176 quitAction->setIcon(QIcon::fromTheme("application-exit")); 0177 quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); 0178 0179 m_editLayoutAction = layoutMenu->addAction(i18nc("edit layout","&Edit...")); 0180 m_editLayoutAction->setIcon(QIcon::fromTheme("document-edit")); 0181 m_editLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E)); 0182 m_editLayoutAction->setToolTip("You can edit layout file when layout is not active or locked"); 0183 0184 QAction *infoLayoutAction = layoutMenu->addAction(i18nc("layout information","&Information...")); 0185 infoLayoutAction->setIcon(QIcon::fromTheme("document-properties")); 0186 infoLayoutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_I)); 0187 0188 //! RTL support for labels in preferences 0189 if (qApp->layoutDirection() == Qt::RightToLeft) { 0190 ui->behaviorLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); 0191 ui->mouseSensetivityLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); 0192 ui->delayLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); 0193 } 0194 0195 loadSettings(); 0196 0197 //! SIGNALS 0198 0199 connect(m_model, &QStandardItemModel::itemChanged, this, &SettingsDialog::itemChanged); 0200 connect(ui->layoutsView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, [&]() { 0201 updatePerLayoutButtonsState(); 0202 updateApplyButtonsState(); 0203 }); 0204 0205 connect(m_inMemoryButtons, static_cast<void(QButtonGroup::*)(int, bool)>(&QButtonGroup::buttonToggled), 0206 [ = ](int id, bool checked) { 0207 updateApplyButtonsState(); 0208 updateSharedLayoutsStates(); 0209 updateSharedLayoutsUiElements(); 0210 }); 0211 0212 connect(m_mouseSensitivityButtons, static_cast<void(QButtonGroup::*)(int, bool)>(&QButtonGroup::buttonToggled), 0213 [ = ](int id, bool checked) { 0214 updateApplyButtonsState(); 0215 }); 0216 0217 connect(ui->screenTrackerSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), [ = ](int i) { 0218 updateApplyButtonsState(); 0219 }); 0220 0221 connect(ui->outlineSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), [ = ](int i) { 0222 updateApplyButtonsState(); 0223 }); 0224 0225 connect(ui->autostartChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); 0226 connect(ui->badges3DStyleChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); 0227 connect(ui->metaPressChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); 0228 connect(ui->metaPressHoldChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); 0229 connect(ui->infoWindowChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); 0230 connect(ui->tabWidget, &QTabWidget::currentChanged, this, &SettingsDialog::updateApplyButtonsState); 0231 0232 connect(ui->noBordersForMaximizedChkBox, &QCheckBox::stateChanged, this, [&]() { 0233 bool noBordersForMaximized = ui->noBordersForMaximizedChkBox->isChecked(); 0234 0235 if (noBordersForMaximized) { 0236 ui->layoutsView->setColumnHidden(BORDERSCOLUMN, false); 0237 } else { 0238 ui->layoutsView->setColumnHidden(BORDERSCOLUMN, true); 0239 } 0240 0241 updateApplyButtonsState(); 0242 }); 0243 0244 connect(quitAction, &QAction::triggered, this, [&]() { 0245 close(); 0246 m_corona->closeApplication(); 0247 }); 0248 0249 connect(m_editLayoutAction, &QAction::triggered, this, [&]() { 0250 QString file = idForRow(ui->layoutsView->currentIndex().row()); 0251 0252 if (!file.isEmpty()) { 0253 QProcess::startDetached("kwrite \"" + file + "\""); 0254 } 0255 }); 0256 0257 connect(infoLayoutAction, &QAction::triggered, this, &SettingsDialog::showLayoutInformation); 0258 connect(screensAction, &QAction::triggered, this, &SettingsDialog::showScreensInformation); 0259 0260 //! update all layouts view when runningActivities changed. This way we update immediately 0261 //! the running Activities in Activities checkboxes which are shown as bold 0262 connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, 0263 this, [&]() { 0264 ui->layoutsView->update(); 0265 }); 0266 0267 blockDeleteOnActivityStopped(); 0268 } 0269 0270 SettingsDialog::~SettingsDialog() 0271 { 0272 qDebug() << Q_FUNC_INFO; 0273 0274 qDeleteAll(m_layouts); 0275 0276 if (m_model) { 0277 delete m_model; 0278 } 0279 0280 if (m_corona && m_corona->universalSettings()) { 0281 m_corona->universalSettings()->setLayoutsWindowSize(size()); 0282 0283 QStringList columnWidths; 0284 columnWidths << QString::number(ui->layoutsView->columnWidth(COLORCOLUMN)); 0285 columnWidths << QString::number(ui->layoutsView->columnWidth(NAMECOLUMN)); 0286 columnWidths << QString::number(ui->layoutsView->columnWidth(MENUCOLUMN)); 0287 columnWidths << QString::number(ui->layoutsView->columnWidth(BORDERSCOLUMN)); 0288 0289 Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast<Latte::Types::LayoutsMemoryUsage>(m_inMemoryButtons->checkedId()); 0290 0291 if (inMemoryOption == Latte::Types::MultipleLayouts) { 0292 columnWidths << QString::number(ui->layoutsView->columnWidth(ACTIVITYCOLUMN)); 0293 } else { 0294 //! In Single Mode, keed recorded value for ACTIVITYCOLUMN 0295 QStringList currentWidths = m_corona->universalSettings()->layoutsColumnWidths(); 0296 if (currentWidths.count()>=5) { 0297 columnWidths << currentWidths[4]; 0298 } 0299 } 0300 0301 m_corona->universalSettings()->setLayoutsColumnWidths(columnWidths); 0302 } 0303 0304 m_inMemoryButtons->deleteLater(); 0305 m_mouseSensitivityButtons->deleteLater(); 0306 0307 for (const auto &tempDir : m_tempDirectories) { 0308 QDir tDir(tempDir); 0309 0310 if (tDir.exists() && tempDir.startsWith("/tmp/")) { 0311 tDir.removeRecursively(); 0312 } 0313 } 0314 } 0315 0316 void SettingsDialog::blockDeleteOnActivityStopped() 0317 { 0318 connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, 0319 this, [&]() { 0320 m_blockDeleteOnReject = true; 0321 m_activityClosedTimer.start(); 0322 }); 0323 0324 m_activityClosedTimer.setSingleShot(true); 0325 m_activityClosedTimer.setInterval(500); 0326 connect(&m_activityClosedTimer, &QTimer::timeout, this, [&]() { 0327 m_blockDeleteOnReject = false; 0328 }); 0329 } 0330 0331 QStringList SettingsDialog::activities() 0332 { 0333 return m_corona->layoutsManager()->synchronizer()->activities(); 0334 } 0335 0336 QStringList SettingsDialog::availableActivities() 0337 { 0338 return m_availableActivities; 0339 } 0340 0341 QStringList SettingsDialog::availableSharesFor(int row) 0342 { 0343 QStringList availables; 0344 QStringList regs; 0345 0346 for (int i = 0; i < m_model->rowCount(); ++i) { 0347 QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); 0348 QStringList shares = m_model->data(m_model->index(i, SHAREDCOLUMN), Qt::UserRole).toStringList(); 0349 0350 if (i != row) { 0351 if (shares.isEmpty()) { 0352 availables << id; 0353 } else { 0354 regs << shares; 0355 } 0356 } 0357 } 0358 0359 for (const auto r : regs) { 0360 availables.removeAll(r); 0361 } 0362 0363 return availables; 0364 } 0365 0366 void SettingsDialog::toggleCurrentPage() 0367 { 0368 if (ui->tabWidget->currentIndex() == 0) { 0369 ui->tabWidget->setCurrentIndex(1); 0370 } else { 0371 ui->tabWidget->setCurrentIndex(0); 0372 } 0373 } 0374 0375 void SettingsDialog::on_newButton_clicked() 0376 { 0377 qDebug() << Q_FUNC_INFO; 0378 0379 //! find Default preset path 0380 for (const auto &preset : m_corona->layoutsManager()->presetsPaths()) { 0381 QString presetName = CentralLayout::layoutName(preset); 0382 0383 if (presetName == "Default") { 0384 QByteArray presetNameChars = presetName.toUtf8(); 0385 const char *prset_str = presetNameChars.data(); 0386 presetName = uniqueLayoutName(i18n(prset_str)); 0387 0388 addLayoutForFile(preset, presetName, true, false); 0389 break; 0390 } 0391 } 0392 } 0393 0394 void SettingsDialog::on_copyButton_clicked() 0395 { 0396 qDebug() << Q_FUNC_INFO; 0397 0398 int row = ui->layoutsView->currentIndex().row(); 0399 0400 if (row < 0) { 0401 return; 0402 } 0403 0404 //! Update original layout before copying if this layout is active 0405 if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 0406 QString lName = (m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole)).toString(); 0407 0408 Layout::GenericLayout *generic = m_corona->layoutsManager()->synchronizer()->layout(lName); 0409 if (generic) { 0410 generic->syncToLayoutFile(); 0411 } 0412 } 0413 0414 QString tempDir = uniqueTempDirectory(); 0415 0416 QString id = m_model->data(m_model->index(row, IDCOLUMN), Qt::DisplayRole).toString(); 0417 QString color = m_model->data(m_model->index(row, COLORCOLUMN), Qt::BackgroundRole).toString(); 0418 QString textColor = m_model->data(m_model->index(row, COLORCOLUMN), Qt::UserRole).toString(); 0419 QString layoutName = uniqueLayoutName(m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole).toString()); 0420 bool menu = m_model->data(m_model->index(row, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; 0421 bool disabledBorders = m_model->data(m_model->index(row, BORDERSCOLUMN), Qt::DisplayRole).toString() == CheckMark; 0422 0423 QString copiedId = tempDir + "/" + layoutName + ".layout.latte"; 0424 QFile(id).copy(copiedId); 0425 0426 QFileInfo newFileInfo(copiedId); 0427 0428 if (newFileInfo.exists() && !newFileInfo.isWritable()) { 0429 QFile(copiedId).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); 0430 } 0431 0432 CentralLayout *settings = new CentralLayout(this, copiedId); 0433 m_layouts[copiedId] = settings; 0434 0435 insertLayoutInfoAtRow(row + 1, copiedId, color, textColor, layoutName, menu, disabledBorders, QStringList(), false); 0436 0437 ui->layoutsView->selectRow(row + 1); 0438 } 0439 0440 void SettingsDialog::on_downloadButton_clicked() 0441 { 0442 qDebug() << Q_FUNC_INFO; 0443 0444 KNS3::DownloadDialog dialog(QStringLiteral("latte-layouts.knsrc"), this); 0445 dialog.resize(m_corona->universalSettings()->downloadWindowSize()); 0446 dialog.exec(); 0447 0448 bool layoutAdded{false}; 0449 0450 if (!dialog.changedEntries().isEmpty() || !dialog.installedEntries().isEmpty()) { 0451 for (const auto &entry : dialog.installedEntries()) { 0452 for (const auto &entryFile : entry.installedFiles()) { 0453 Layouts::Importer::LatteFileVersion version = Layouts::Importer::fileVersion(entryFile); 0454 0455 if (version == Layouts::Importer::LayoutVersion2) { 0456 layoutAdded = true; 0457 addLayoutForFile(entryFile); 0458 break; 0459 } 0460 } 0461 } 0462 } 0463 0464 m_corona->universalSettings()->setDownloadWindowSize(dialog.size()); 0465 0466 if (layoutAdded) { 0467 apply(); 0468 } 0469 } 0470 0471 void SettingsDialog::on_removeButton_clicked() 0472 { 0473 qDebug() << Q_FUNC_INFO; 0474 0475 int row = ui->layoutsView->currentIndex().row(); 0476 0477 if (row < 0) { 0478 return; 0479 } 0480 0481 QString layoutName = m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole).toString(); 0482 0483 if (m_corona->layoutsManager()->synchronizer()->centralLayout(layoutName)) { 0484 return; 0485 } 0486 0487 m_model->removeRow(row); 0488 0489 updateApplyButtonsState(); 0490 0491 row = qMax(row - 1, 0); 0492 0493 ui->layoutsView->selectRow(row); 0494 } 0495 0496 void SettingsDialog::on_lockedButton_clicked() 0497 { 0498 qDebug() << Q_FUNC_INFO; 0499 0500 int row = ui->layoutsView->currentIndex().row(); 0501 0502 if (row < 0) { 0503 return; 0504 } 0505 0506 bool lockedModel = m_model->data(m_model->index(row, NAMECOLUMN), Qt::UserRole).toBool(); 0507 0508 m_model->setData(m_model->index(row, NAMECOLUMN), QVariant(!lockedModel), Qt::UserRole); 0509 0510 updatePerLayoutButtonsState(); 0511 updateApplyButtonsState(); 0512 } 0513 0514 void SettingsDialog::on_sharedButton_clicked() 0515 { 0516 qDebug() << Q_FUNC_INFO; 0517 0518 int row = ui->layoutsView->currentIndex().row(); 0519 0520 if (row < 0) { 0521 return; 0522 } 0523 0524 if (isShared(row)) { 0525 m_model->setData(m_model->index(row, SHAREDCOLUMN), QStringList(), Qt::UserRole); 0526 } else { 0527 bool assigned{false}; 0528 QStringList assignedList; 0529 0530 QStringList availableShares = availableSharesFor(row); 0531 0532 for (const auto &id : availableShares) { 0533 QString name = nameForId(id); 0534 if (m_corona->layoutsManager()->synchronizer()->layout(name)) { 0535 assignedList << id; 0536 m_model->setData(m_model->index(row, SHAREDCOLUMN), assignedList, Qt::UserRole); 0537 assigned = true; 0538 break; 0539 } 0540 } 0541 0542 if (!assigned && availableShares.count()>0) { 0543 assignedList << availableShares[0]; 0544 m_model->setData(m_model->index(row, SHAREDCOLUMN), assignedList, Qt::UserRole); 0545 assigned = true; 0546 } 0547 } 0548 0549 updatePerLayoutButtonsState(); 0550 updateApplyButtonsState(); 0551 } 0552 0553 void SettingsDialog::on_importButton_clicked() 0554 { 0555 qDebug() << Q_FUNC_INFO; 0556 0557 0558 QFileDialog *fileDialog = new QFileDialog(this, i18nc("import layout/configuration", "Import Layout/Configuration") 0559 , QDir::homePath() 0560 , QStringLiteral("layout.latte")); 0561 0562 fileDialog->setFileMode(QFileDialog::AnyFile); 0563 fileDialog->setAcceptMode(QFileDialog::AcceptOpen); 0564 fileDialog->setDefaultSuffix("layout.latte"); 0565 0566 QStringList filters; 0567 filters << QString(i18nc("import latte layout", "Latte Dock Layout file v0.2") + "(*.layout.latte)") 0568 << QString(i18nc("import latte layouts/configuration", "Latte Dock Full Configuration file (v0.1, v0.2)") + "(*.latterc)"); 0569 fileDialog->setNameFilters(filters); 0570 0571 connect(fileDialog, &QFileDialog::finished 0572 , fileDialog, &QFileDialog::deleteLater); 0573 0574 connect(fileDialog, &QFileDialog::fileSelected 0575 , this, [&](const QString & file) { 0576 Layouts::Importer::LatteFileVersion version = Layouts::Importer::fileVersion(file); 0577 qDebug() << "VERSION :::: " << version; 0578 0579 if (version == Layouts::Importer::LayoutVersion2) { 0580 addLayoutForFile(file); 0581 } else if (version == Layouts::Importer::ConfigVersion1) { 0582 auto msg = new QMessageBox(this); 0583 msg->setIcon(QMessageBox::Warning); 0584 msg->setWindowTitle(i18n("Import: Configuration file version v0.1")); 0585 msg->setText( 0586 i18n("You are going to import an old version <b>v0.1</b> configuration file.<br><b>Be careful</b>, importing the entire configuration <b>will erase all</b> your current configuration!!!<br><br> <i>Alternative, you can <b>import safely</b> from this file<br><b>only the contained layouts...</b></i>")); 0587 msg->setStandardButtons(QMessageBox::Cancel); 0588 0589 QPushButton *fullBtn = new QPushButton(msg); 0590 QPushButton *layoutsBtn = new QPushButton(msg); 0591 fullBtn->setText(i18nc("import full configuration", "Full Configuration")); 0592 fullBtn->setIcon(QIcon::fromTheme("settings")); 0593 layoutsBtn->setText(i18nc("import only the layouts", "Only Layouts")); 0594 layoutsBtn->setIcon(QIcon::fromTheme("user-identity")); 0595 0596 msg->addButton(fullBtn, QMessageBox::AcceptRole); 0597 msg->addButton(layoutsBtn, QMessageBox::AcceptRole); 0598 0599 msg->setDefaultButton(layoutsBtn); 0600 0601 connect(msg, &QMessageBox::finished, msg, &QMessageBox::deleteLater); 0602 0603 msg->open(); 0604 0605 connect(layoutsBtn, &QPushButton::clicked 0606 , this, [ &, file](bool check) { 0607 importLayoutsFromV1ConfigFile(file); 0608 }); 0609 0610 connect(fullBtn, &QPushButton::clicked 0611 , this, [ &, file](bool check) { 0612 //!NOTE: Restart latte for import the new configuration 0613 QProcess::startDetached(qGuiApp->applicationFilePath() + " --import-full \"" + file + "\""); 0614 qGuiApp->exit(); 0615 }); 0616 } else if (version == Layouts::Importer::ConfigVersion2) { 0617 auto msg = new QMessageBox(this); 0618 msg->setIcon(QMessageBox::Warning); 0619 msg->setWindowTitle(i18n("Import: Configuration file version v0.2")); 0620 msg->setText( 0621 i18n("You are going to import a <b>v0.2</b> configuration file.<br><b>Be careful</b>, importing <b>will erase all</b> your current configuration!!!<br><br><i>Would you like to proceed?</i>")); 0622 msg->setStandardButtons(QMessageBox::Yes | QMessageBox::No); 0623 msg->setDefaultButton(QMessageBox::No); 0624 0625 connect(msg, &QMessageBox::finished, this, [ &, msg, file](int result) { 0626 if (result == QMessageBox::Yes) { 0627 //!NOTE: Restart latte for import the new configuration 0628 msg->deleteLater(); 0629 QProcess::startDetached(qGuiApp->applicationFilePath() + " --import-full \"" + file + "\""); 0630 qGuiApp->exit(); 0631 } 0632 }); 0633 0634 msg->open(); 0635 } 0636 }); 0637 0638 fileDialog->open(); 0639 } 0640 0641 bool SettingsDialog::importLayoutsFromV1ConfigFile(QString file) 0642 { 0643 KTar archive(file, QStringLiteral("application/x-tar")); 0644 archive.open(QIODevice::ReadOnly); 0645 0646 //! if the file isnt a tar archive 0647 if (archive.isOpen()) { 0648 QDir tempDir{uniqueTempDirectory()}; 0649 0650 const auto archiveRootDir = archive.directory(); 0651 0652 for (const auto &name : archiveRootDir->entries()) { 0653 auto fileEntry = archiveRootDir->file(name); 0654 fileEntry->copyTo(tempDir.absolutePath()); 0655 } 0656 0657 QString name = Layouts::Importer::nameOfConfigFile(file); 0658 0659 QString applets(tempDir.absolutePath() + "/" + "lattedock-appletsrc"); 0660 0661 if (QFile(applets).exists()) { 0662 if (m_corona->layoutsManager()->importer()->importOldLayout(applets, name, false, tempDir.absolutePath())) { 0663 addLayoutForFile(tempDir.absolutePath() + "/" + name + ".layout.latte", name, false); 0664 } 0665 0666 QString alternativeName = name + "-" + i18nc("layout", "Alternative"); 0667 0668 if (m_corona->layoutsManager()->importer()->importOldLayout(applets, alternativeName, false, tempDir.absolutePath())) { 0669 addLayoutForFile(tempDir.absolutePath() + "/" + alternativeName + ".layout.latte", alternativeName, false); 0670 } 0671 } 0672 0673 return true; 0674 } 0675 0676 return false; 0677 } 0678 0679 0680 void SettingsDialog::on_exportButton_clicked() 0681 { 0682 int row = ui->layoutsView->currentIndex().row(); 0683 0684 if (row < 0) { 0685 return; 0686 } 0687 0688 QString layoutExported = m_model->data(m_model->index(row, IDCOLUMN), Qt::DisplayRole).toString(); 0689 0690 //! Update ALL active original layouts before exporting, 0691 //! this is needed because the export method can export also the full configuration 0692 qDebug() << Q_FUNC_INFO; 0693 0694 m_corona->layoutsManager()->synchronizer()->syncActiveLayoutsToOriginalFiles(); 0695 0696 QFileDialog *fileDialog = new QFileDialog(this, i18nc("export layout/configuration", "Export Layout/Configuration") 0697 , QDir::homePath(), QStringLiteral("layout.latte")); 0698 0699 fileDialog->setFileMode(QFileDialog::AnyFile); 0700 fileDialog->setAcceptMode(QFileDialog::AcceptSave); 0701 fileDialog->setDefaultSuffix("layout.latte"); 0702 0703 QStringList filters; 0704 QString filter1(i18nc("export layout", "Latte Dock Layout file v0.2") + "(*.layout.latte)"); 0705 QString filter2(i18nc("export full configuration", "Latte Dock Full Configuration file v0.2") + "(*.latterc)"); 0706 0707 filters << filter1 0708 << filter2; 0709 0710 fileDialog->setNameFilters(filters); 0711 0712 connect(fileDialog, &QFileDialog::finished 0713 , fileDialog, &QFileDialog::deleteLater); 0714 0715 connect(fileDialog, &QFileDialog::fileSelected 0716 , this, [ &, layoutExported](const QString & file) { 0717 auto showNotificationError = []() { 0718 auto notification = new KNotification("export-fail", KNotification::CloseOnTimeout); 0719 notification->setText(i18nc("export layout", "Failed to export layout")); 0720 notification->sendEvent(); 0721 }; 0722 0723 if (QFile::exists(file) && !QFile::remove(file)) { 0724 showNotificationError(); 0725 return; 0726 } 0727 0728 if (file.endsWith(".layout.latte")) { 0729 if (!QFile(layoutExported).copy(file)) { 0730 showNotificationError(); 0731 return; 0732 } 0733 0734 QFileInfo newFileInfo(file); 0735 0736 if (newFileInfo.exists() && !newFileInfo.isWritable()) { 0737 QFile(file).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); 0738 } 0739 0740 CentralLayout layoutS(this, file); 0741 layoutS.setActivities(QStringList()); 0742 layoutS.clearLastUsedActivity(); 0743 0744 //NOTE: The pointer is automatically deleted when the event is closed 0745 auto notification = new KNotification("export-done", KNotification::CloseOnTimeout); 0746 notification->setActions({i18nc("export layout", "Open location")}); 0747 notification->setText(i18nc("export layout", "Layout exported successfully")); 0748 0749 connect(notification, &KNotification::action1Activated 0750 , this, [file]() { 0751 QDesktopServices::openUrl({QFileInfo(file).canonicalPath()}); 0752 }); 0753 0754 notification->sendEvent(); 0755 } else if (file.endsWith(".latterc")) { 0756 auto showNotificationError = []() { 0757 auto notification = new KNotification("export-fail", KNotification::CloseOnTimeout); 0758 notification->setText(i18nc("import/export config", "Failed to export configuration")); 0759 notification->sendEvent(); 0760 }; 0761 0762 if (m_corona->layoutsManager()->importer()->exportFullConfiguration(file)) { 0763 0764 auto notification = new KNotification("export-done", KNotification::CloseOnTimeout); 0765 notification->setActions({i18nc("import/export config", "Open location")}); 0766 notification->setText(i18nc("import/export config", "Full Configuration exported successfully")); 0767 0768 connect(notification, &KNotification::action1Activated 0769 , this, [file]() { 0770 QDesktopServices::openUrl({QFileInfo(file).canonicalPath()}); 0771 }); 0772 0773 notification->sendEvent(); 0774 } else { 0775 showNotificationError(); 0776 } 0777 } 0778 }); 0779 0780 0781 fileDialog->open(); 0782 } 0783 0784 void SettingsDialog::requestImagesDialog(int row) 0785 { 0786 QStringList mimeTypeFilters; 0787 mimeTypeFilters << "image/jpeg" // will show "JPEG image (*.jpeg *.jpg) 0788 << "image/png"; // will show "PNG image (*.png)" 0789 0790 QFileDialog dialog(this); 0791 dialog.setMimeTypeFilters(mimeTypeFilters); 0792 0793 QString background = m_model->data(m_model->index(row, COLORCOLUMN), Qt::BackgroundRole).toString(); 0794 0795 if (background.startsWith("/") && QFileInfo(background).exists()) { 0796 dialog.setDirectory(QFileInfo(background).absolutePath()); 0797 dialog.selectFile(background); 0798 } 0799 0800 if (dialog.exec()) { 0801 QStringList files = dialog.selectedFiles(); 0802 0803 if (files.count() > 0) { 0804 m_model->setData(m_model->index(row, COLORCOLUMN), files[0], Qt::BackgroundRole); 0805 } 0806 } 0807 } 0808 0809 void SettingsDialog::requestColorsDialog(int row) 0810 { 0811 QColorDialog dialog(this); 0812 QString textColor = m_model->data(m_model->index(row, COLORCOLUMN), Qt::UserRole).toString(); 0813 dialog.setCurrentColor(QColor(textColor)); 0814 0815 if (dialog.exec()) { 0816 qDebug() << dialog.selectedColor().name(); 0817 m_model->setData(m_model->index(row, COLORCOLUMN), dialog.selectedColor().name(), Qt::UserRole); 0818 } 0819 } 0820 0821 0822 void SettingsDialog::accept() 0823 { 0824 qDebug() << Q_FUNC_INFO; 0825 0826 if (saveAllChanges()) { 0827 deleteLater(); 0828 } 0829 } 0830 0831 void SettingsDialog::reject() 0832 { 0833 qDebug() << Q_FUNC_INFO; 0834 0835 if (!m_blockDeleteOnReject) { 0836 deleteLater(); 0837 } 0838 } 0839 0840 void SettingsDialog::apply() 0841 { 0842 qDebug() << Q_FUNC_INFO; 0843 saveAllChanges(); 0844 0845 o_settings = currentSettings(); 0846 o_settingsLayouts = currentLayoutsSettings(); 0847 0848 updateApplyButtonsState(); 0849 updatePerLayoutButtonsState(); 0850 } 0851 0852 void SettingsDialog::restoreDefaults() 0853 { 0854 qDebug() << Q_FUNC_INFO; 0855 0856 if (ui->tabWidget->currentIndex() == 0) { 0857 //! Default layouts missing from layouts list 0858 for (const auto &preset : m_corona->layoutsManager()->presetsPaths()) { 0859 QString presetName = CentralLayout::layoutName(preset); 0860 QByteArray presetNameChars = presetName.toUtf8(); 0861 const char *prset_str = presetNameChars.data(); 0862 presetName = i18n(prset_str); 0863 0864 if (!nameExistsInModel(presetName)) { 0865 addLayoutForFile(preset, presetName); 0866 } 0867 } 0868 } else if (ui->tabWidget->currentIndex() == 1) { 0869 //! Defaults for general Latte settings 0870 ui->autostartChkBox->setChecked(true); 0871 ui->badges3DStyleChkBox->setChecked(true); 0872 ui->infoWindowChkBox->setChecked(true); 0873 ui->metaPressChkBox->setChecked(false); 0874 ui->metaPressHoldChkBox->setChecked(true); 0875 ui->noBordersForMaximizedChkBox->setChecked(false); 0876 ui->highSensitivityBtn->setChecked(true); 0877 ui->screenTrackerSpinBox->setValue(SCREENTRACKERDEFAULTVALUE); 0878 ui->outlineSpinBox->setValue(OUTLINEDEFAULTWIDTH); 0879 } 0880 } 0881 0882 void SettingsDialog::addLayoutForFile(QString file, QString layoutName, bool newTempDirectory, bool showNotification) 0883 { 0884 if (layoutName.isEmpty()) { 0885 layoutName = CentralLayout::layoutName(file); 0886 } 0887 0888 QString copiedId; 0889 0890 if (newTempDirectory) { 0891 QString tempDir = uniqueTempDirectory(); 0892 copiedId = tempDir + "/" + layoutName + ".layout.latte"; 0893 QFile(file).copy(copiedId); 0894 } else { 0895 copiedId = file; 0896 } 0897 0898 QFileInfo newFileInfo(copiedId); 0899 0900 if (newFileInfo.exists() && !newFileInfo.isWritable()) { 0901 QFile(copiedId).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); 0902 } 0903 0904 if (m_layouts.contains(copiedId)) { 0905 CentralLayout *oldSettings = m_layouts.take(copiedId); 0906 delete oldSettings; 0907 } 0908 0909 CentralLayout *settings = new CentralLayout(this, copiedId); 0910 m_layouts[copiedId] = settings; 0911 0912 QString id = copiedId; 0913 QString color = settings->color(); 0914 QString textColor = settings->textColor(); 0915 QString background = settings->background(); 0916 bool menu = settings->showInMenu(); 0917 bool disabledBorders = settings->disableBordersForMaximizedWindows(); 0918 bool locked = !settings->isWritable(); 0919 0920 layoutName = uniqueLayoutName(layoutName); 0921 0922 int row = ascendingRowFor(layoutName); 0923 0924 if (background.isEmpty()) { 0925 insertLayoutInfoAtRow(row, copiedId, color, QString(), layoutName, menu, disabledBorders, QStringList(), locked); 0926 } else { 0927 insertLayoutInfoAtRow(row, copiedId, background, textColor, layoutName, menu, disabledBorders, QStringList(), locked); 0928 } 0929 0930 ui->layoutsView->selectRow(row); 0931 0932 if (showNotification) { 0933 //NOTE: The pointer is automatically deleted when the event is closed 0934 auto notification = new KNotification("import-done", KNotification::CloseOnTimeout); 0935 notification->setText(i18nc("import-done", "Layout: <b>%0</b> imported successfully<br>").arg(layoutName)); 0936 notification->sendEvent(); 0937 } 0938 } 0939 0940 void SettingsDialog::loadSettings() 0941 { 0942 m_initLayoutPaths.clear(); 0943 m_model->clear(); 0944 m_sharesMap.clear(); 0945 0946 int i = 0; 0947 QStringList brokenLayouts; 0948 0949 if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 0950 m_corona->layoutsManager()->synchronizer()->syncActiveLayoutsToOriginalFiles(); 0951 } 0952 0953 for (const auto layout : m_corona->layoutsManager()->layouts()) { 0954 QString layoutPath = QDir::homePath() + "/.config/latte/" + layout + ".layout.latte"; 0955 m_initLayoutPaths.append(layoutPath); 0956 0957 CentralLayout *central = new CentralLayout(this, layoutPath); 0958 m_layouts[layoutPath] = central; 0959 0960 QString background = central->background(); 0961 0962 //! add central layout properties 0963 if (background.isEmpty()) { 0964 insertLayoutInfoAtRow(i, layoutPath, central->color(), QString(), central->name(), 0965 central->showInMenu(), central->disableBordersForMaximizedWindows(), 0966 central->activities(), !central->isWritable()); 0967 } else { 0968 insertLayoutInfoAtRow(i, layoutPath, background, central->textColor(), central->name(), 0969 central->showInMenu(), central->disableBordersForMaximizedWindows(), 0970 central->activities(), !central->isWritable()); 0971 } 0972 0973 //! create initial SHARES maps 0974 QString shared = central->sharedLayoutName(); 0975 if (!shared.isEmpty()) { 0976 m_sharesMap[shared].append(layoutPath); 0977 } 0978 0979 qDebug() << "counter:" << i << " total:" << m_model->rowCount(); 0980 0981 i++; 0982 0983 if (central->name() == m_corona->layoutsManager()->currentLayoutName()) { 0984 ui->layoutsView->selectRow(i - 1); 0985 } 0986 0987 Layout::GenericLayout *generic = m_corona->layoutsManager()->synchronizer()->layout(central->name()); 0988 0989 if ((generic && generic->layoutIsBroken()) || (!generic && central->layoutIsBroken())) { 0990 brokenLayouts.append(central->name()); 0991 } 0992 } 0993 0994 //! update SHARES map keys in order to use the #settingsid(s) 0995 QStringList forremoval; 0996 0997 //! remove these records after updating 0998 for (QHash<const QString, QStringList>::iterator i=m_sharesMap.begin(); i!=m_sharesMap.end(); ++i) { 0999 forremoval << i.key(); 1000 } 1001 1002 //! update keys 1003 for (QHash<const QString, QStringList>::iterator i=m_sharesMap.begin(); i!=m_sharesMap.end(); ++i) { 1004 QString shareid = idForRow(rowForName(i.key())); 1005 m_sharesMap[shareid] = i.value(); 1006 } 1007 1008 //! remove deprecated keys 1009 for (const auto &key : forremoval) { 1010 m_sharesMap.remove(key); 1011 } 1012 1013 qDebug() << "SHARES MAP ::: " << m_sharesMap; 1014 1015 for (QHash<const QString, QStringList>::iterator i=m_sharesMap.begin(); i!=m_sharesMap.end(); ++i) { 1016 int sharedPos = rowForId(i.key()); 1017 1018 if (sharedPos >= 0) { 1019 m_model->setData(m_model->index(sharedPos, SHAREDCOLUMN), i.value(), Qt::UserRole); 1020 } 1021 } 1022 1023 recalculateAvailableActivities(); 1024 1025 m_model->setHorizontalHeaderItem(IDCOLUMN, new QStandardItem(QString("#path"))); 1026 m_model->setHorizontalHeaderItem(COLORCOLUMN, new QStandardItem(QIcon::fromTheme("games-config-background"), 1027 QString(i18nc("column for layout background", "Background")))); 1028 m_model->setHorizontalHeaderItem(NAMECOLUMN, new QStandardItem(QString(i18nc("column for layout name", "Name")))); 1029 m_model->setHorizontalHeaderItem(MENUCOLUMN, new QStandardItem(QString(i18nc("column for layout to show in menu", "In Menu")))); 1030 m_model->setHorizontalHeaderItem(BORDERSCOLUMN, new QStandardItem(QString(i18nc("column for layout to hide borders for maximized windows", "Borderless")))); 1031 m_model->setHorizontalHeaderItem(ACTIVITYCOLUMN, new QStandardItem(QIcon::fromTheme("preferences-activities"), 1032 QString(i18nc("column for layout to show which activities is assigned to", "Activities")))); 1033 m_model->setHorizontalHeaderItem(SHAREDCOLUMN, new QStandardItem(QIcon::fromTheme("document-share"), 1034 QString(i18nc("column for shared layout to show which layouts is assigned to", "Shared To")))); 1035 1036 //! this line should be commented for debugging layouts window functionality 1037 ui->layoutsView->setColumnHidden(IDCOLUMN, true); 1038 ui->layoutsView->setColumnHidden(HIDDENTEXTCOLUMN, true); 1039 1040 if (m_corona->universalSettings()->canDisableBorders()) { 1041 ui->layoutsView->setColumnHidden(BORDERSCOLUMN, false); 1042 } else { 1043 ui->layoutsView->setColumnHidden(BORDERSCOLUMN, true); 1044 } 1045 1046 ui->layoutsView->resizeColumnsToContents(); 1047 1048 QStringList columnWidths = m_corona->universalSettings()->layoutsColumnWidths(); 1049 1050 if (!columnWidths.isEmpty()) { 1051 for (int i=0; i<qMin(columnWidths.count(),4); ++i) { 1052 ui->layoutsView->setColumnWidth(COLORCOLUMN+i, columnWidths[i].toInt()); 1053 } 1054 } 1055 1056 if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) { 1057 ui->singleToolBtn->setChecked(true); 1058 } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 1059 ui->multipleToolBtn->setChecked(true); 1060 } 1061 1062 updatePerLayoutButtonsState(); 1063 updateSharedLayoutsStates(); 1064 1065 ui->autostartChkBox->setChecked(m_corona->universalSettings()->autostart()); 1066 ui->badges3DStyleChkBox->setChecked(m_corona->universalSettings()->badges3DStyle()); 1067 ui->infoWindowChkBox->setChecked(m_corona->universalSettings()->showInfoWindow()); 1068 ui->metaPressChkBox->setChecked(m_corona->universalSettings()->kwin_metaForwardedToLatte()); 1069 ui->metaPressHoldChkBox->setChecked(m_corona->universalSettings()->metaPressAndHoldEnabled()); 1070 ui->noBordersForMaximizedChkBox->setChecked(m_corona->universalSettings()->canDisableBorders()); 1071 1072 if (m_corona->universalSettings()->mouseSensitivity() == Types::LowSensitivity) { 1073 ui->lowSensitivityBtn->setChecked(true); 1074 } else if (m_corona->universalSettings()->mouseSensitivity() == Types::MediumSensitivity) { 1075 ui->mediumSensitivityBtn->setChecked(true); 1076 } else if (m_corona->universalSettings()->mouseSensitivity() == Types::HighSensitivity) { 1077 ui->highSensitivityBtn->setChecked(true); 1078 } 1079 1080 o_settings = currentSettings(); 1081 o_settingsLayouts = currentLayoutsSettings(); 1082 updateApplyButtonsState(); 1083 updateSharedLayoutsUiElements(); 1084 1085 //! there are broken layouts and the user must be informed! 1086 if (brokenLayouts.count() > 0) { 1087 auto msg = new QMessageBox(this); 1088 msg->setIcon(QMessageBox::Warning); 1089 msg->setWindowTitle(i18n("Layout Warning")); 1090 msg->setText(i18n("The layout(s) <b>%0</b> have <i>broken configuration</i>!!! Please <b>remove them</b> to improve the system stability...").arg(brokenLayouts.join(","))); 1091 msg->setStandardButtons(QMessageBox::Ok); 1092 1093 msg->open(); 1094 } 1095 } 1096 1097 QList<int> SettingsDialog::currentSettings() 1098 { 1099 QList<int> settings; 1100 settings << m_inMemoryButtons->checkedId(); 1101 settings << (int)ui->autostartChkBox->isChecked(); 1102 settings << (int)ui->badges3DStyleChkBox->isChecked(); 1103 settings << (int)ui->infoWindowChkBox->isChecked(); 1104 settings << (int)ui->metaPressChkBox->isChecked(); 1105 settings << (int)ui->metaPressHoldChkBox->isChecked(); 1106 settings << (int)ui->noBordersForMaximizedChkBox->isChecked(); 1107 settings << m_mouseSensitivityButtons->checkedId(); 1108 settings << ui->screenTrackerSpinBox->value(); 1109 settings << ui->outlineSpinBox->value(); 1110 settings << m_model->rowCount(); 1111 1112 return settings; 1113 } 1114 1115 QStringList SettingsDialog::currentLayoutsSettings() 1116 { 1117 QStringList layoutSettings; 1118 1119 for (int i = 0; i < m_model->rowCount(); ++i) { 1120 QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); 1121 QString color = m_model->data(m_model->index(i, COLORCOLUMN), Qt::BackgroundRole).toString(); 1122 QString textColor = m_model->data(m_model->index(i, COLORCOLUMN), Qt::UserRole).toString(); 1123 QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 1124 bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); 1125 bool menu = m_model->data(m_model->index(i, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; 1126 bool borders = m_model->data(m_model->index(i, BORDERSCOLUMN), Qt::DisplayRole).toString() == CheckMark; 1127 QStringList lActivities = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); 1128 QStringList shares = m_model->data(m_model->index(i, SHAREDCOLUMN), Qt::UserRole).toStringList(); 1129 1130 layoutSettings << id; 1131 layoutSettings << color; 1132 layoutSettings << textColor; 1133 layoutSettings << name; 1134 layoutSettings << QString::number((int)locked); 1135 layoutSettings << QString::number((int)menu); 1136 layoutSettings << QString::number((int)borders); 1137 layoutSettings << lActivities; 1138 layoutSettings << shares; 1139 } 1140 1141 return layoutSettings; 1142 } 1143 1144 1145 void SettingsDialog::insertLayoutInfoAtRow(int row, QString path, QString color, QString textColor, QString name, bool menu, 1146 bool disabledBorders, QStringList activities, bool locked) 1147 { 1148 QStandardItem *pathItem = new QStandardItem(path); 1149 1150 QStandardItem *hiddenTextItem = new QStandardItem(); 1151 1152 QStandardItem *colorItem = new QStandardItem(); 1153 colorItem->setSelectable(false); 1154 1155 QStandardItem *nameItem = new QStandardItem(name); 1156 nameItem->setTextAlignment(Qt::AlignCenter); 1157 1158 QStandardItem *menuItem = new QStandardItem(); 1159 menuItem->setEditable(false); 1160 menuItem->setSelectable(true); 1161 menuItem->setText(menu ? CheckMark : QString()); 1162 menuItem->setTextAlignment(Qt::AlignCenter); 1163 1164 QStandardItem *bordersItem = new QStandardItem(); 1165 bordersItem->setEditable(false); 1166 bordersItem->setSelectable(true); 1167 bordersItem->setText(disabledBorders ? CheckMark : QString()); 1168 bordersItem->setTextAlignment(Qt::AlignCenter); 1169 1170 QStandardItem *activitiesItem = new QStandardItem(activities.join(",")); 1171 1172 QStandardItem *sharesItem = new QStandardItem(); 1173 1174 QList<QStandardItem *> items; 1175 1176 items.append(pathItem); 1177 items.append(hiddenTextItem); 1178 items.append(colorItem); 1179 items.append(nameItem); 1180 items.append(menuItem); 1181 items.append(bordersItem); 1182 items.append(activitiesItem); 1183 items.append(sharesItem); 1184 1185 if (row > m_model->rowCount() - 1) { 1186 m_model->appendRow(items); 1187 row = m_model->rowCount() - 1; 1188 1189 qDebug() << "append row at:" << row << " rows:" << m_model->rowCount(); 1190 } else { 1191 m_model->insertRow(row, items); 1192 qDebug() << "insert row at:" << row << " rows:" << m_model->rowCount(); 1193 } 1194 1195 m_model->setData(m_model->index(row, IDCOLUMN), path, Qt::DisplayRole); 1196 m_model->setData(m_model->index(row, COLORCOLUMN), color, Qt::BackgroundRole); 1197 m_model->setData(m_model->index(row, COLORCOLUMN), textColor, Qt::UserRole); 1198 1199 QFont font; 1200 1201 if (m_corona->layoutsManager()->synchronizer()->layout(name)) { 1202 font.setBold(true); 1203 } else { 1204 font.setBold(false); 1205 } 1206 1207 if (path.startsWith("/tmp/")) { 1208 font.setItalic(true); 1209 } else { 1210 font.setItalic(false); 1211 } 1212 1213 m_model->setData(m_model->index(row, NAMECOLUMN), QVariant(name), Qt::DisplayRole); 1214 m_model->setData(m_model->index(row, NAMECOLUMN), font, Qt::FontRole); 1215 m_model->setData(m_model->index(row, NAMECOLUMN), QVariant(locked), Qt::UserRole); 1216 1217 m_model->setData(m_model->index(row, ACTIVITYCOLUMN), activities, Qt::UserRole); 1218 } 1219 1220 1221 void SettingsDialog::on_switchButton_clicked() 1222 { 1223 if (ui->buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) { 1224 //! thus there are changes in the settings 1225 1226 QString lName; 1227 QStringList lActivities; 1228 1229 if (m_inMemoryButtons->checkedId() == Latte::Types::MultipleLayouts) { 1230 lName = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole).toString(); 1231 lActivities = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), ACTIVITYCOLUMN), Qt::UserRole).toStringList(); 1232 } 1233 1234 apply(); 1235 1236 if (!lName.isEmpty() && !lActivities.isEmpty()) { 1237 //! an activities-assigned layout is chosen and at the same time we are moving 1238 //! to multiple layouts state 1239 m_corona->layoutsManager()->switchToLayout(lName); 1240 } 1241 } else { 1242 QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); 1243 1244 if (value.isValid()) { 1245 m_corona->layoutsManager()->switchToLayout(value.toString()); 1246 } else { 1247 qDebug() << "not valid layout"; 1248 } 1249 } 1250 1251 updatePerLayoutButtonsState(); 1252 } 1253 1254 void SettingsDialog::on_pauseButton_clicked() 1255 { 1256 ui->pauseButton->setEnabled(false); 1257 1258 QString id = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), IDCOLUMN), Qt::DisplayRole).toString(); 1259 CentralLayout *layout = m_layouts[id]; 1260 1261 if (layout) { 1262 m_corona->layoutsManager()->synchronizer()->pauseLayout(layout->name()); 1263 } 1264 } 1265 1266 void SettingsDialog::layoutsChanged() 1267 { 1268 for (int i = 0; i < m_model->rowCount(); ++i) { 1269 QModelIndex nameIndex = m_model->index(i, NAMECOLUMN); 1270 QVariant value = m_model->data(nameIndex); 1271 1272 if (value.isValid()) { 1273 QString name = value.toString(); 1274 QFont font; 1275 1276 if (m_corona->layoutsManager()->currentLayoutName() == name) { 1277 font.setBold(true); 1278 // ui->layoutsView->selectRow(i); 1279 } else { 1280 Layout::GenericLayout *layout = m_corona->layoutsManager()->synchronizer()->layout(name); 1281 1282 if (layout && (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts)) { 1283 font.setBold(true); 1284 } else { 1285 font.setBold(false); 1286 } 1287 } 1288 1289 m_model->setData(nameIndex, font, Qt::FontRole); 1290 } 1291 } 1292 } 1293 1294 void SettingsDialog::itemChanged(QStandardItem *item) 1295 { 1296 updatePerLayoutButtonsState(); 1297 1298 if (item->column() == ACTIVITYCOLUMN) { 1299 //! recalculate the available activities 1300 recalculateAvailableActivities(); 1301 } else if (item->column() == NAMECOLUMN) { 1302 int currentRow = ui->layoutsView->currentIndex().row(); 1303 1304 QString id = m_model->data(m_model->index(currentRow, IDCOLUMN), Qt::DisplayRole).toString(); 1305 QString name = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::DisplayRole).toString(); 1306 QFont font = qvariant_cast<QFont>(m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::FontRole)); 1307 1308 if (m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name())) { 1309 font.setBold(true); 1310 } else { 1311 font.setBold(false); 1312 } 1313 1314 if (m_layouts[id]->name() != name) { 1315 font.setItalic(true); 1316 } else { 1317 font.setItalic(false); 1318 } 1319 1320 m_model->setData(m_model->index(currentRow, NAMECOLUMN), font, Qt::FontRole); 1321 1322 } else if (item->column() == SHAREDCOLUMN) { 1323 updateSharedLayoutsStates(); 1324 } 1325 1326 updateApplyButtonsState(); 1327 } 1328 1329 void SettingsDialog::updateApplyButtonsState() 1330 { 1331 bool changed{false}; 1332 1333 //! Ok, Apply Buttons 1334 if ((o_settings != currentSettings()) 1335 || (o_settingsLayouts != currentLayoutsSettings())) { 1336 changed = true; 1337 } 1338 1339 if (changed) { 1340 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 1341 ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); 1342 } else { 1343 //ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); 1344 ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); 1345 } 1346 1347 //! RestoreDefaults Button 1348 if (ui->tabWidget->currentIndex() == 0) { 1349 //! Check Default layouts missing from layouts list 1350 1351 bool layoutMissing{false}; 1352 1353 for (const auto &preset : m_corona->layoutsManager()->presetsPaths()) { 1354 QString presetName = CentralLayout::layoutName(preset); 1355 QByteArray presetNameChars = presetName.toUtf8(); 1356 const char *prset_str = presetNameChars.data(); 1357 presetName = i18n(prset_str); 1358 1359 if (!nameExistsInModel(presetName)) { 1360 layoutMissing = true; 1361 break; 1362 } 1363 } 1364 1365 if (layoutMissing) { 1366 ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(true); 1367 } else { 1368 ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(false); 1369 } 1370 } else if (ui->tabWidget->currentIndex() == 1) { 1371 //! Defaults for general Latte settings 1372 1373 if (!ui->autostartChkBox->isChecked() 1374 || ui->badges3DStyleChkBox->isChecked() 1375 || ui->metaPressChkBox->isChecked() 1376 || !ui->metaPressHoldChkBox->isChecked() 1377 || !ui->infoWindowChkBox->isChecked() 1378 || ui->noBordersForMaximizedChkBox->isChecked() 1379 || !ui->highSensitivityBtn->isChecked() 1380 || ui->screenTrackerSpinBox->value() != SCREENTRACKERDEFAULTVALUE 1381 || ui->outlineSpinBox->value() != OUTLINEDEFAULTWIDTH ) { 1382 ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(true); 1383 } else { 1384 ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(false); 1385 } 1386 } 1387 } 1388 1389 void SettingsDialog::updatePerLayoutButtonsState() 1390 { 1391 int currentRow = ui->layoutsView->currentIndex().row(); 1392 1393 QString id = m_model->data(m_model->index(currentRow, IDCOLUMN), Qt::DisplayRole).toString(); 1394 QString nameInModel = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::DisplayRole).toString(); 1395 QString originalName = m_layouts.contains(id) ? m_layouts[id]->name() : ""; 1396 bool lockedInModel = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::UserRole).toBool(); 1397 bool sharedInModel = !m_model->data(m_model->index(currentRow, SHAREDCOLUMN), Qt::UserRole).toStringList().isEmpty(); 1398 bool editable = !isActive(originalName) && !lockedInModel; 1399 1400 //! Switch Button 1401 if (id.startsWith("/tmp/") || originalName != nameInModel) { 1402 ui->switchButton->setEnabled(false); 1403 } else { 1404 ui->switchButton->setEnabled(true); 1405 } 1406 1407 //! Pause Button 1408 if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) { 1409 ui->pauseButton->setVisible(false); 1410 } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 1411 ui->pauseButton->setVisible(true); 1412 1413 QStringList lActivities = m_model->data(m_model->index(currentRow, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); 1414 1415 Latte::CentralLayout *layout = m_layouts[id]; 1416 1417 if (!lActivities.isEmpty() && layout && m_corona->layoutsManager()->synchronizer()->centralLayout(layout->name())) { 1418 ui->pauseButton->setEnabled(true); 1419 } else { 1420 ui->pauseButton->setEnabled(false); 1421 } 1422 } 1423 1424 //! Remove Layout Button 1425 if (originalName != nameInModel 1426 || (originalName == m_corona->layoutsManager()->currentLayoutName()) 1427 || (m_corona->layoutsManager()->synchronizer()->centralLayout(originalName)) 1428 || lockedInModel) { 1429 ui->removeButton->setEnabled(false); 1430 } else { 1431 ui->removeButton->setEnabled(true); 1432 } 1433 1434 //! Layout Locked Button 1435 if (lockedInModel) { 1436 ui->lockedButton->setChecked(true); 1437 } else { 1438 ui->lockedButton->setChecked(false); 1439 } 1440 1441 //! Layout Shared Button 1442 if (sharedInModel) { 1443 ui->sharedButton->setChecked(true); 1444 } else { 1445 ui->sharedButton->setChecked(false); 1446 } 1447 1448 if (editable) { 1449 m_editLayoutAction->setEnabled(true); 1450 } else { 1451 m_editLayoutAction->setEnabled(false); 1452 } 1453 } 1454 1455 void SettingsDialog::updateSharedLayoutsStates() 1456 { 1457 bool inMultiple{inMultipleLayoutsLook()}; 1458 1459 for (int i = 0; i < m_model->rowCount(); ++i) { 1460 QStringList shares = m_model->data(m_model->index(i, SHAREDCOLUMN), Qt::UserRole).toStringList(); 1461 1462 if (shares.isEmpty() || !inMultiple) { 1463 QStandardItem *item = m_model->item(i, MENUCOLUMN); 1464 item->setEnabled(true); 1465 item = m_model->item(i, BORDERSCOLUMN); 1466 item->setEnabled(true); 1467 item = m_model->item(i, ACTIVITYCOLUMN); 1468 item->setEnabled(true); 1469 } else { 1470 QStandardItem *item = m_model->item(i, MENUCOLUMN); 1471 item->setEnabled(false); 1472 item = m_model->item(i, BORDERSCOLUMN); 1473 item->setEnabled(false); 1474 item = m_model->item(i, ACTIVITYCOLUMN); 1475 item->setEnabled(false); 1476 } 1477 1478 //! refresh LayoutName 1479 QStandardItem *nameItem = m_model->item(i, NAMECOLUMN); 1480 nameItem->setEnabled(false); 1481 nameItem->setEnabled(true); 1482 } 1483 } 1484 1485 void SettingsDialog::updateSharedLayoutsUiElements() 1486 { 1487 //! UI Elements that need to be enabled/disabled 1488 1489 Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast<Latte::Types::LayoutsMemoryUsage>(m_inMemoryButtons->checkedId()); 1490 if (inMemoryOption == Latte::Types::MultipleLayouts) { 1491 ui->layoutsView->setColumnHidden(SHAREDCOLUMN, false); 1492 ui->sharedButton->setVisible(true); 1493 1494 //! column widths 1495 QStringList cWidths = m_corona->universalSettings()->layoutsColumnWidths(); 1496 1497 if (cWidths.count()>=5) { 1498 ui->layoutsView->setColumnWidth(ACTIVITYCOLUMN, cWidths[4].toInt()); 1499 } 1500 } else { 1501 ui->layoutsView->setColumnHidden(SHAREDCOLUMN, true); 1502 ui->sharedButton->setVisible(false); 1503 } 1504 } 1505 1506 void SettingsDialog::recalculateAvailableActivities() 1507 { 1508 QStringList tempActivities = m_corona->layoutsManager()->synchronizer()->activities(); 1509 1510 for (int i = 0; i < m_model->rowCount(); ++i) { 1511 QStringList assigned = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); 1512 1513 for (const auto &activity : assigned) { 1514 if (tempActivities.contains(activity)) { 1515 tempActivities.removeAll(activity); 1516 } 1517 } 1518 } 1519 1520 m_availableActivities = tempActivities; 1521 } 1522 1523 bool SettingsDialog::dataAreAccepted() 1524 { 1525 for (int i = 0; i < m_model->rowCount(); ++i) { 1526 QString layout1 = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 1527 1528 for (int j = i + 1; j < m_model->rowCount(); ++j) { 1529 QString temp = m_model->data(m_model->index(j, NAMECOLUMN), Qt::DisplayRole).toString(); 1530 1531 //!same layout name exists again 1532 if (layout1 == temp) { 1533 auto msg = new QMessageBox(this); 1534 msg->setIcon(QMessageBox::Warning); 1535 msg->setWindowTitle(i18n("Layout Warning")); 1536 msg->setText(i18n("There are layouts with the same name, that is not permitted!!! Please update these names to re-apply the changes...")); 1537 msg->setStandardButtons(QMessageBox::Ok); 1538 1539 connect(msg, &QMessageBox::finished, this, [ &, i, j](int result) { 1540 QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect; 1541 QModelIndex indexBase = m_model->index(i, NAMECOLUMN); 1542 ui->layoutsView->selectionModel()->select(indexBase, flags); 1543 1544 QModelIndex indexOccurence = m_model->index(j, NAMECOLUMN); 1545 ui->layoutsView->edit(indexOccurence); 1546 }); 1547 1548 1549 msg->open(); 1550 1551 return false; 1552 } 1553 } 1554 } 1555 1556 return true; 1557 } 1558 1559 void SettingsDialog::showLayoutInformation() 1560 { 1561 int currentRow = ui->layoutsView->currentIndex().row(); 1562 1563 QString id = m_model->data(m_model->index(currentRow, IDCOLUMN), Qt::DisplayRole).toString(); 1564 QString name = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::DisplayRole).toString(); 1565 1566 Layout::GenericLayout *genericActive= m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name()); 1567 Layout::GenericLayout *generic = genericActive ? genericActive : m_layouts[id]; 1568 1569 auto msg = new QMessageBox(this); 1570 msg->setWindowTitle(name); 1571 msg->setText(generic->reportHtml(m_corona->screenPool())); 1572 1573 msg->open(); 1574 } 1575 1576 void SettingsDialog::showScreensInformation() 1577 { 1578 QList<int> assignedScreens; 1579 1580 for (int i = 0; i < m_model->rowCount(); ++i) { 1581 QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); 1582 QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 1583 1584 Layout::GenericLayout *genericActive= m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name()); 1585 Layout::GenericLayout *generic = genericActive ? genericActive : m_layouts[id]; 1586 1587 QList<int> vScreens = generic->viewsScreens(); 1588 1589 for (const int scrId : vScreens) { 1590 if (!assignedScreens.contains(scrId)) { 1591 assignedScreens << scrId; 1592 } 1593 } 1594 } 1595 1596 auto msg = new QMessageBox(this); 1597 msg->setWindowTitle(i18n("Screens Information")); 1598 msg->setText(m_corona->screenPool()->reportHtml(assignedScreens)); 1599 1600 msg->open(); 1601 } 1602 1603 bool SettingsDialog::saveAllChanges() 1604 { 1605 if (!dataAreAccepted()) { 1606 return false; 1607 } 1608 1609 //! Update universal settings 1610 Latte::Types::MouseSensitivity sensitivity = static_cast<Latte::Types::MouseSensitivity>(m_mouseSensitivityButtons->checkedId()); 1611 bool autostart = ui->autostartChkBox->isChecked(); 1612 bool badges3DStyle = ui->badges3DStyleChkBox->isChecked(); 1613 bool forwardMetaPress = ui->metaPressChkBox->isChecked(); 1614 bool metaPressAndHold = ui->metaPressHoldChkBox->isChecked(); 1615 bool showInfoWindow = ui->infoWindowChkBox->isChecked(); 1616 bool noBordersForMaximized = ui->noBordersForMaximizedChkBox->isChecked(); 1617 1618 m_corona->universalSettings()->setMouseSensitivity(sensitivity); 1619 m_corona->universalSettings()->setAutostart(autostart); 1620 m_corona->universalSettings()->setBadges3DStyle(badges3DStyle); 1621 m_corona->universalSettings()->kwin_forwardMetaToLatte(forwardMetaPress); 1622 m_corona->universalSettings()->setMetaPressAndHoldEnabled(metaPressAndHold); 1623 m_corona->universalSettings()->setShowInfoWindow(showInfoWindow); 1624 m_corona->universalSettings()->setCanDisableBorders(noBordersForMaximized); 1625 m_corona->universalSettings()->setScreenTrackerInterval(ui->screenTrackerSpinBox->value()); 1626 1627 m_corona->themeExtended()->setOutlineWidth(ui->outlineSpinBox->value()); 1628 1629 //! Update Layouts 1630 QStringList knownActivities = activities(); 1631 1632 QTemporaryDir layoutTempDir; 1633 1634 qDebug() << "Temporary Directory ::: " << layoutTempDir.path(); 1635 1636 QStringList fromRenamePaths; 1637 QStringList toRenamePaths; 1638 QStringList toRenameNames; 1639 1640 QString switchToLayout; 1641 1642 QHash<QString, Layout::GenericLayout *> activeLayoutsToRename; 1643 1644 //! remove layouts that have been removed from the user 1645 for (const auto &initLayout : m_initLayoutPaths) { 1646 if (!idExistsInModel(initLayout)) { 1647 QFile(initLayout).remove(); 1648 1649 if (m_layouts.contains(initLayout)) { 1650 CentralLayout *removedLayout = m_layouts.take(initLayout); 1651 delete removedLayout; 1652 } 1653 } 1654 } 1655 1656 for (int i = 0; i < m_model->rowCount(); ++i) { 1657 QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); 1658 QString color = m_model->data(m_model->index(i, COLORCOLUMN), Qt::BackgroundRole).toString(); 1659 QString textColor = m_model->data(m_model->index(i, COLORCOLUMN), Qt::UserRole).toString(); 1660 QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 1661 bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); 1662 bool menu = m_model->data(m_model->index(i, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; 1663 bool disabledBorders = m_model->data(m_model->index(i, BORDERSCOLUMN), Qt::DisplayRole).toString() == CheckMark; 1664 QStringList lActivities = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); 1665 1666 QStringList cleanedActivities; 1667 1668 //!update only activities that are valid 1669 for (const auto &activity : lActivities) { 1670 if (knownActivities.contains(activity)) { 1671 cleanedActivities.append(activity); 1672 } 1673 } 1674 1675 //qDebug() << i << ". " << id << " - " << color << " - " << name << " - " << menu << " - " << lActivities; 1676 //! update the generic parts of the layouts 1677 Layout::GenericLayout *genericActive= m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name()); 1678 Layout::GenericLayout *generic = genericActive ? genericActive : m_layouts[id]; 1679 1680 //! unlock read-only layout 1681 if (!generic->isWritable()) { 1682 generic->unlock(); 1683 } 1684 1685 if (color.startsWith("/")) { 1686 //it is image file in such case 1687 if (color != generic->background()) { 1688 generic->setBackground(color); 1689 } 1690 1691 if (generic->textColor() != textColor) { 1692 generic->setTextColor(textColor); 1693 } 1694 } else { 1695 if (color != generic->color()) { 1696 generic->setColor(color); 1697 generic->setBackground(QString()); 1698 generic->setTextColor(QString()); 1699 } 1700 } 1701 1702 //! update only the Central-specific layout parts 1703 CentralLayout *centralActive= m_corona->layoutsManager()->synchronizer()->centralLayout(m_layouts[id]->name()); 1704 CentralLayout *central = centralActive ? centralActive : m_layouts[id]; 1705 1706 if (central->showInMenu() != menu) { 1707 central->setShowInMenu(menu); 1708 } 1709 1710 if (central->disableBordersForMaximizedWindows() != disabledBorders) { 1711 central->setDisableBordersForMaximizedWindows(disabledBorders); 1712 } 1713 1714 if (central->activities() != cleanedActivities) { 1715 central->setActivities(cleanedActivities); 1716 } 1717 1718 //! If the layout name changed OR the layout path is a temporary one 1719 if (generic->name() != name || (id.startsWith("/tmp/"))) { 1720 //! If the layout is Active in MultipleLayouts 1721 if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts && generic->isActive()) { 1722 qDebug() << " Active Layout Should Be Renamed From : " << generic->name() << " TO :: " << name; 1723 activeLayoutsToRename[name] = generic; 1724 } 1725 1726 QString tempFile = layoutTempDir.path() + "/" + QString(generic->name() + ".layout.latte"); 1727 qDebug() << "new temp file ::: " << tempFile; 1728 1729 if ((m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) && (generic->name() == m_corona->layoutsManager()->currentLayoutName())) { 1730 switchToLayout = name; 1731 } 1732 1733 generic = m_layouts.take(id); 1734 delete generic; 1735 1736 QFile(id).rename(tempFile); 1737 1738 fromRenamePaths.append(id); 1739 toRenamePaths.append(tempFile); 1740 toRenameNames.append(name); 1741 } 1742 } 1743 1744 //! this is necessary in case two layouts have to swap names 1745 //! so we copy first the layouts in a temp directory and afterwards all 1746 //! together we move them in the official layout directory 1747 for (int i = 0; i < toRenamePaths.count(); ++i) { 1748 QString newFile = QDir::homePath() + "/.config/latte/" + toRenameNames[i] + ".layout.latte"; 1749 QFile(toRenamePaths[i]).rename(newFile); 1750 1751 CentralLayout *nLayout = new CentralLayout(this, newFile); 1752 m_layouts[newFile] = nLayout; 1753 1754 //! updating the #SETTINGSID in the model for the layout that was renamed 1755 for (int j = 0; j < m_model->rowCount(); ++j) { 1756 QString tId = m_model->data(m_model->index(j, IDCOLUMN), Qt::DisplayRole).toString(); 1757 1758 if (tId == fromRenamePaths[i]) { 1759 m_model->setData(m_model->index(j, IDCOLUMN), newFile, Qt::DisplayRole); 1760 m_initLayoutPaths.append(newFile); 1761 1762 QFont font = qvariant_cast<QFont>(m_model->data(m_model->index(j, NAMECOLUMN), Qt::FontRole)); 1763 1764 font.setItalic(false); 1765 m_model->setData(m_model->index(j, NAMECOLUMN), font, Qt::FontRole); 1766 } 1767 } 1768 } 1769 1770 QString orphanedLayout; 1771 1772 if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 1773 for (const auto &newLayoutName : activeLayoutsToRename.keys()) { 1774 Layout::GenericLayout *layout = activeLayoutsToRename[newLayoutName]; 1775 qDebug() << " Active Layout of Type: " << layout->type() << " Is Renamed From : " << activeLayoutsToRename[newLayoutName]->name() << " TO :: " << newLayoutName; 1776 layout->renameLayout(newLayoutName); 1777 1778 if (layout->type() == Layout::Type::Central) { 1779 CentralLayout *central = qobject_cast<CentralLayout *>(layout); 1780 1781 if (central->activities().isEmpty()) { 1782 //! that means it is an active layout for orphaned Activities 1783 orphanedLayout = newLayoutName; 1784 } 1785 } 1786 1787 //! broadcast the name change 1788 int row = rowForName(newLayoutName); 1789 QStandardItem *item = m_model->item(row, NAMECOLUMN); 1790 if (item) { 1791 emit itemChanged(item); 1792 } 1793 } 1794 } 1795 1796 //! lock layouts in the end when the user has chosen it 1797 for (int i = 0; i < m_model->rowCount(); ++i) { 1798 QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); 1799 QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 1800 bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); 1801 1802 Layout::GenericLayout *generic = m_corona->layoutsManager()->synchronizer()->layout(m_layouts[id]->name()); 1803 Layout::GenericLayout *layout = generic ? generic : m_layouts[id]; 1804 1805 if (layout && locked && layout->isWritable()) { 1806 layout->lock(); 1807 } 1808 } 1809 1810 //! update SharedLayouts that are Active 1811 syncActiveShares(); 1812 1813 //! reload layouts in layoutsmanager 1814 m_corona->layoutsManager()->synchronizer()->loadLayouts(); 1815 1816 //! send to layout manager in which layout to switch 1817 Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast<Latte::Types::LayoutsMemoryUsage>(m_inMemoryButtons->checkedId()); 1818 1819 if (m_corona->layoutsManager()->memoryUsage() != inMemoryOption) { 1820 Types::LayoutsMemoryUsage previousMemoryUsage = m_corona->layoutsManager()->memoryUsage(); 1821 m_corona->layoutsManager()->setMemoryUsage(inMemoryOption); 1822 1823 QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); 1824 QString layoutName = value.toString(); 1825 1826 m_corona->layoutsManager()->switchToLayout(layoutName, previousMemoryUsage); 1827 } else { 1828 if (!switchToLayout.isEmpty()) { 1829 m_corona->layoutsManager()->switchToLayout(switchToLayout); 1830 } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 1831 m_corona->layoutsManager()->synchronizer()->syncMultipleLayoutsToActivities(orphanedLayout); 1832 } 1833 } 1834 1835 return true; 1836 } 1837 1838 void SettingsDialog::syncActiveShares() 1839 { 1840 if (m_corona->layoutsManager()->memoryUsage() != Types::MultipleLayouts) { 1841 return; 1842 } 1843 1844 QHash<const QString, QStringList> currentSharesIdMap; 1845 Layouts::SharesMap currentSharesNamesMap; 1846 1847 for (int i = 0; i < m_model->rowCount(); ++i) { 1848 if (isShared(i)) { 1849 QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); 1850 QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 1851 QStringList shareIds = m_model->data(m_model->index(i, SHAREDCOLUMN), Qt::UserRole).toStringList(); 1852 QStringList shareNames; 1853 1854 for (const auto &shareid : shareIds) { 1855 QString shareName = nameForId(shareid); 1856 shareNames << shareName; 1857 } 1858 1859 currentSharesIdMap[id] = shareIds; 1860 currentSharesNamesMap[name] = shareNames; 1861 } 1862 } 1863 1864 QStringList deprecatedShares; 1865 1866 for (const auto &oldSharesIds : m_sharesMap) { 1867 for(const auto &oldId : oldSharesIds) { 1868 QString oldShareName = nameForId(oldId); 1869 if (!m_corona->layoutsManager()->synchronizer()->mapHasRecord(oldShareName, currentSharesNamesMap)) { 1870 deprecatedShares << oldShareName; 1871 } 1872 } 1873 } 1874 1875 qDebug() << " CURRENT SHARES ID MAP :: " << currentSharesIdMap; 1876 m_corona->layoutsManager()->synchronizer()->syncActiveShares(currentSharesNamesMap, deprecatedShares); 1877 1878 m_sharesMap.clear(); 1879 m_sharesMap = currentSharesIdMap; 1880 } 1881 1882 void SettingsDialog::addActivityInCurrent(const QString &activityId) 1883 { 1884 int currentRow = ui->layoutsView->currentIndex().row(); 1885 QStringList activities = m_model->data(m_model->index(currentRow, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); 1886 if (!activities.contains(activityId)) { 1887 activities << activityId; 1888 m_model->setData(m_model->index(currentRow, ACTIVITYCOLUMN), activities, Qt::UserRole); 1889 } 1890 } 1891 1892 void SettingsDialog::removeActivityFromCurrent(const QString &activityId) 1893 { 1894 int currentRow = ui->layoutsView->currentIndex().row(); 1895 QStringList activities = m_model->data(m_model->index(currentRow, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); 1896 if (activities.contains(activityId)) { 1897 activities.removeAll(activityId); 1898 m_model->setData(m_model->index(currentRow, ACTIVITYCOLUMN), activities, Qt::UserRole); 1899 } 1900 } 1901 1902 void SettingsDialog::addShareInCurrent(const QString &layoutId) 1903 { 1904 int currentRow = ui->layoutsView->currentIndex().row(); 1905 QStringList shares = m_model->data(m_model->index(currentRow, SHAREDCOLUMN), Qt::UserRole).toStringList(); 1906 if (!shares.contains(layoutId)) { 1907 shares << layoutId; 1908 m_model->setData(m_model->index(currentRow, SHAREDCOLUMN), shares, Qt::UserRole); 1909 } 1910 } 1911 1912 void SettingsDialog::removeShareFromCurrent(const QString &layoutId) 1913 { 1914 int currentRow = ui->layoutsView->currentIndex().row(); 1915 QStringList shares = m_model->data(m_model->index(currentRow, SHAREDCOLUMN), Qt::UserRole).toStringList(); 1916 if (shares.contains(layoutId)) { 1917 shares.removeAll(layoutId); 1918 m_model->setData(m_model->index(currentRow, SHAREDCOLUMN), shares, Qt::UserRole); 1919 } 1920 } 1921 1922 bool SettingsDialog::idExistsInModel(QString id) 1923 { 1924 for (int i = 0; i < m_model->rowCount(); ++i) { 1925 QString rowId = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); 1926 1927 if (rowId == id) { 1928 return true; 1929 } 1930 } 1931 1932 return false; 1933 } 1934 1935 bool SettingsDialog::nameExistsInModel(QString name) 1936 { 1937 for (int i = 0; i < m_model->rowCount(); ++i) { 1938 QString rowName = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 1939 1940 if (rowName == name) { 1941 return true; 1942 } 1943 } 1944 1945 return false; 1946 } 1947 1948 bool SettingsDialog::inMultipleLayoutsLook() const 1949 { 1950 Latte::Types::LayoutsMemoryUsage inMemoryOption = static_cast<Latte::Types::LayoutsMemoryUsage>(m_inMemoryButtons->checkedId()); 1951 return inMemoryOption == Latte::Types::MultipleLayouts; 1952 } 1953 1954 bool SettingsDialog::isActive(QString layoutName) const 1955 { 1956 return (m_corona->layoutsManager()->synchronizer()->layout(layoutName) != nullptr); 1957 } 1958 1959 bool SettingsDialog::isMenuCell(int column) const 1960 { 1961 return column == MENUCOLUMN; 1962 } 1963 1964 bool SettingsDialog::isShared(int row) const 1965 { 1966 if (row >=0 ) { 1967 QStringList shares = m_model->data(m_model->index(row, SHAREDCOLUMN), Qt::UserRole).toStringList(); 1968 if (!shares.isEmpty()) { 1969 return true; 1970 } 1971 } 1972 1973 return false; 1974 } 1975 1976 int SettingsDialog::ascendingRowFor(QString name) 1977 { 1978 for (int i = 0; i < m_model->rowCount(); ++i) { 1979 QString rowName = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 1980 1981 if (rowName.toUpper() > name.toUpper()) { 1982 return i; 1983 } 1984 } 1985 1986 return m_model->rowCount(); 1987 } 1988 1989 int SettingsDialog::rowForId(QString id) const 1990 { 1991 for (int i = 0; i < m_model->rowCount(); ++i) { 1992 QString rowId = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); 1993 1994 if (rowId == id) { 1995 return i; 1996 } 1997 } 1998 1999 return -1; 2000 } 2001 2002 int SettingsDialog::rowForName(QString layoutName) const 2003 { 2004 for (int i = 0; i < m_model->rowCount(); ++i) { 2005 QString rowName = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); 2006 2007 if (rowName == layoutName) { 2008 return i; 2009 } 2010 } 2011 2012 return -1; 2013 } 2014 2015 QString SettingsDialog::idForRow(int row) const 2016 { 2017 return m_model->data(m_model->index(row, IDCOLUMN), Qt::DisplayRole).toString(); 2018 } 2019 2020 QString SettingsDialog::nameForId(QString id) const 2021 { 2022 int row = rowForId(id); 2023 return m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole).toString(); 2024 } 2025 2026 QString SettingsDialog::uniqueTempDirectory() 2027 { 2028 QTemporaryDir tempDir; 2029 tempDir.setAutoRemove(false); 2030 m_tempDirectories.append(tempDir.path()); 2031 2032 return tempDir.path(); 2033 } 2034 2035 QString SettingsDialog::uniqueLayoutName(QString name) 2036 { 2037 int pos_ = name.lastIndexOf(QRegExp(QString("[-][0-9]+"))); 2038 2039 if (nameExistsInModel(name) && pos_ > 0) { 2040 name = name.left(pos_); 2041 } 2042 2043 int i = 2; 2044 2045 QString namePart = name; 2046 2047 while (nameExistsInModel(name)) { 2048 name = namePart + "-" + QString::number(i); 2049 i++; 2050 } 2051 2052 return name; 2053 } 2054 2055 }//end of namespace 2056