/* * Copyright 2017 Smith AR * Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * Latte-Dock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "ui_layoutconfigdialog.h" #include "layoutconfigdialog.h" #include "layoutsettings.h" #include "layoutsDelegates/checkboxdelegate.h" #include "layoutsDelegates/colorcmbboxdelegate.h" #include "layoutsDelegates/activitycmbboxdelegate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Latte { const int IDCOLUMN = 0; const int COLORCOLUMN = 1; const int NAMECOLUMN = 2; const int MENUCOLUMN = 3; const int ACTIVITYCOLUMN = 4; const QChar CheckMark{0x2714}; LayoutConfigDialog::LayoutConfigDialog(QWidget *parent, LayoutManager *manager) : QDialog(parent), ui(new Ui::LayoutConfigDialog), m_manager(manager) { ui->setupUi(this); setWindowTitle(i18n("Layouts Editor")); setAttribute(Qt::WA_DeleteOnClose, true); setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); resize(m_manager->corona()->universalSettings()->layoutsWindowSize()); connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked , this, &LayoutConfigDialog::apply); connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked , this, &LayoutConfigDialog::restoreDefaults); m_model = new QStandardItemModel(manager->layouts().count(), 5, this); ui->layoutsView->setModel(m_model); ui->layoutsView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->layoutsView->horizontalHeader()->setStretchLastSection(true); ui->layoutsView->verticalHeader()->setVisible(false); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); connect(m_manager, &LayoutManager::currentLayoutNameChanged, this, &LayoutConfigDialog::currentLayoutNameChanged); loadLayouts(); QString iconsPath(m_manager->corona()->kPackage().path() + "../../plasmoids/org.kde.latte.containment/contents/icons/"); //!find the available colors QDir layoutDir(iconsPath); QStringList filter; filter.append(QString("*print.jpg")); QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); QStringList colors; foreach (auto file, files) { int colorEnd = file.lastIndexOf("print.jpg"); QString color = file.remove(colorEnd, 9); colors.append(color); } ui->layoutsView->setItemDelegateForColumn(COLORCOLUMN, new ColorCmbBoxDelegate(this, iconsPath, colors)); ui->layoutsView->setItemDelegateForColumn(MENUCOLUMN, new CheckBoxDelegate(this)); ui->layoutsView->setItemDelegateForColumn(ACTIVITYCOLUMN, new ActivityCmbBoxDelegate(this)); ui->newButton->setText(i18nc("new button", "New")); ui->copyButton->setText(i18nc("copy button", "Copy")); ui->removeButton->setText(i18nc("remove button", "Remove")); ui->switchButton->setText(i18nc("switch button", "Switch")); ui->importButton->setText(i18nc("import button", "Import")); ui->exportButton->setText(i18nc("export button", "Export")); connect(m_model, &QStandardItemModel::itemChanged, this, &LayoutConfigDialog::itemChanged); connect(ui->layoutsView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &LayoutConfigDialog::currentRowChanged); } LayoutConfigDialog::~LayoutConfigDialog() { qDebug() << Q_FUNC_INFO; qDeleteAll(m_layouts); if (m_model) { delete m_model; } if (m_manager && m_manager->corona() && m_manager->corona()->universalSettings()) { m_manager->corona()->universalSettings()->setLayoutsWindowSize(size()); } foreach (auto tempDir, m_tempDirectories) { QDir tDir(tempDir); if (tDir.exists() && tempDir.startsWith("/tmp/")) { tDir.removeRecursively(); } } } QStringList LayoutConfigDialog::activities() { return m_manager->activities(); } QStringList LayoutConfigDialog::availableActivities() { return m_availableActivities; } void LayoutConfigDialog::on_newButton_clicked() { qDebug() << Q_FUNC_INFO; //! find Default preset path foreach (auto preset, m_manager->presetsPaths()) { QString presetName = LayoutSettings::layoutName(preset); if (presetName == "Default") { QByteArray presetNameChars = presetName.toUtf8(); const char *prset_str = presetNameChars.data(); presetName = uniqueLayoutName(i18n(prset_str)); addLayoutForFile(preset, presetName, true, false); break; } } } void LayoutConfigDialog::on_copyButton_clicked() { qDebug() << Q_FUNC_INFO; int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } QString tempDir = uniqueTempDirectory(); QString id = m_model->data(m_model->index(row, IDCOLUMN), Qt::DisplayRole).toString(); QString color = m_model->data(m_model->index(row, COLORCOLUMN), Qt::BackgroundRole).toString(); QString layoutName = uniqueLayoutName(m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole).toString()); bool menu = m_model->data(m_model->index(row, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; QString copiedId = tempDir + "/" + layoutName + ".layout.latte"; QFile(id).copy(copiedId); LayoutSettings *settings = new LayoutSettings(this, copiedId); m_layouts[copiedId] = settings; insertLayoutInfoAtRow(row + 1, copiedId, color, layoutName, menu, QStringList()); ui->layoutsView->selectRow(row + 1); } void LayoutConfigDialog::on_removeButton_clicked() { qDebug() << Q_FUNC_INFO; int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } QString layoutName = m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole).toString(); if (layoutName == m_manager->currentLayoutName()) { return; } m_model->removeRow(row); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); row = qMax(row - 1, 0); ui->layoutsView->selectRow(row); } void LayoutConfigDialog::on_importButton_clicked() { qDebug() << Q_FUNC_INFO; QFileDialog *fileDialog = new QFileDialog(this, i18nc("import layout/configuration", "Import Layout/Configuration") , QDir::homePath() , QStringLiteral("layout.latte")); fileDialog->setFileMode(QFileDialog::AnyFile); fileDialog->setAcceptMode(QFileDialog::AcceptOpen); fileDialog->setDefaultSuffix("layout.latte"); QStringList filters; filters << QString(i18nc("import latte layout", "Latte Dock Layout file v0.2") + "(*.layout.latte)") << QString(i18nc("import latte layouts/configuration", "Latte Dock Full Configuration file (v0.1, v0.2)") + "(*.latterc)"); fileDialog->setNameFilters(filters); connect(fileDialog, &QFileDialog::finished , fileDialog, &QFileDialog::deleteLater); connect(fileDialog, &QFileDialog::fileSelected , this, [&](const QString & file) { Importer::LatteFileVersion version = Importer::fileVersion(file); qDebug() << "VERSION :::: " << version; if (version == Importer::LayoutVersion2) { addLayoutForFile(file); } else if (version == Importer::ConfigVersion1) { auto msg = new QMessageBox(this); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Import: Configuration file version v0.1")); msg->setText( i18n("You are going to import an old version v0.1 configuration file.
Be careful, importing the entire configuration will erase all your current configuration!!!

Alternative, you can import safely from this file
only the contained layouts...
")); msg->setStandardButtons(QMessageBox::Cancel); QPushButton *fullBtn = new QPushButton(msg); QPushButton *layoutsBtn = new QPushButton(msg); fullBtn->setText(i18nc("import full configuration", "Full Configuration")); fullBtn->setIcon(QIcon::fromTheme("settings")); layoutsBtn->setText(i18nc("import only the layouts", "Only Layouts")); layoutsBtn->setIcon(QIcon::fromTheme("user-identity")); msg->addButton(fullBtn, QMessageBox::AcceptRole); msg->addButton(layoutsBtn, QMessageBox::AcceptRole); msg->setDefaultButton(layoutsBtn); connect(msg, &QMessageBox::finished, msg, &QMessageBox::deleteLater); msg->open(); connect(layoutsBtn, &QPushButton::clicked , this, [ &, file](bool check) { importLayoutsFromV1ConfigFile(file); }); connect(fullBtn, &QPushButton::clicked , this, [ &, file](bool check) { //!NOTE: Restart latte for import the new configuration QProcess::startDetached(qGuiApp->applicationFilePath() + " --import \"" + file + "\""); qGuiApp->exit(); }); } else if (version == Importer::ConfigVersion2) { auto msg = new QMessageBox(this); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Import: Configuration file version v0.2")); msg->setText( i18n("You are going to import a v0.2 configuration file.
Be careful, importing will erase all your current configuration!!!

Would you like to proceed?")); msg->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msg->setDefaultButton(QMessageBox::No); connect(msg, &QMessageBox::finished, this, [ &, msg, file](int result) { if (result == QMessageBox::Yes) { //!NOTE: Restart latte for import the new configuration msg->deleteLater(); QProcess::startDetached(qGuiApp->applicationFilePath() + " --import \"" + file + "\""); qGuiApp->exit(); } }); msg->open(); } }); fileDialog->open(); } bool LayoutConfigDialog::importLayoutsFromV1ConfigFile(QString file) { KTar archive(file, QStringLiteral("application/x-tar")); archive.open(QIODevice::ReadOnly); //! if the file isnt a tar archive if (archive.isOpen()) { QDir tempDir{uniqueTempDirectory()}; const auto archiveRootDir = archive.directory(); foreach (auto &name, archiveRootDir->entries()) { auto fileEntry = archiveRootDir->file(name); fileEntry->copyTo(tempDir.absolutePath()); } QString name = Importer::nameOfConfigFile(file); QString applets(tempDir.absolutePath() + "/" + "lattedock-appletsrc"); if (QFile(applets).exists()) { if (m_manager->importer()->importOldLayout(applets, name, false, tempDir.absolutePath())) { addLayoutForFile(tempDir.absolutePath() + "/" + name + ".layout.latte", name, false); } QString alternativeName = name + "-" + i18nc("layout", "Alternative"); if (m_manager->importer()->importOldLayout(applets, alternativeName, false, tempDir.absolutePath())) { addLayoutForFile(tempDir.absolutePath() + "/" + alternativeName + ".layout.latte", alternativeName, false); } } return true; } return false; } void LayoutConfigDialog::on_exportButton_clicked() { int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } QString layoutExported = m_model->data(m_model->index(row, IDCOLUMN), Qt::DisplayRole).toString(); qDebug() << Q_FUNC_INFO; QFileDialog *fileDialog = new QFileDialog(this, i18nc("export layout/configuration", "Export Layout/Configuration") , QDir::homePath() , QStringLiteral("layout.latte")); fileDialog->setFileMode(QFileDialog::AnyFile); fileDialog->setAcceptMode(QFileDialog::AcceptSave); fileDialog->setDefaultSuffix("layout.latte"); QStringList filters; QString filter1(i18nc("export layout", "Latte Dock Layout file v0.2") + "(*.layout.latte)"); QString filter2(i18nc("export full configuraion", "Latte Dock Full Configuration file v0.2") + "(*.latterc)"); filters << filter1 << filter2; fileDialog->setNameFilters(filters); connect(fileDialog, &QFileDialog::finished , fileDialog, &QFileDialog::deleteLater); connect(fileDialog, &QFileDialog::fileSelected , this, [ &, layoutExported](const QString & file) { auto showNotificationError = []() { auto notification = new KNotification("export-fail", KNotification::CloseOnTimeout); notification->setText(i18nc("export layout", "Failed to export layout")); notification->sendEvent(); }; if (QFile::exists(file) && !QFile::remove(file)) { showNotificationError(); return; } if (file.endsWith(".layout.latte")) { if (!QFile(layoutExported).copy(file)) { showNotificationError(); return; } LayoutSettings layoutS(this, file); layoutS.setActivities(QStringList()); //NOTE: The pointer is automatically deleted when the event is closed auto notification = new KNotification("export-done", KNotification::CloseOnTimeout); notification->setActions({i18nc("export layout", "Open location")}); notification->setText(i18nc("export layout", "Layout exported successfully")); connect(notification, &KNotification::action1Activated , this, [file]() { QDesktopServices::openUrl({QFileInfo(file).canonicalPath()}); }); notification->sendEvent(); } else if (file.endsWith(".latterc")) { auto showNotificationError = []() { auto notification = new KNotification("export-fail", KNotification::CloseOnTimeout); notification->setText(i18nc("import/export config", "Failed to export configuration")); notification->sendEvent(); }; if (m_manager->importer()->exportFullConfiguration(file)) { auto notification = new KNotification("export-done", KNotification::CloseOnTimeout); notification->setActions({i18nc("import/export config", "Open location")}); notification->setText(i18nc("import/export config", "Full Configuration exported successfully")); connect(notification, &KNotification::action1Activated , this, [file]() { QDesktopServices::openUrl({QFileInfo(file).canonicalPath()}); }); notification->sendEvent(); } else { showNotificationError(); } } }); fileDialog->open(); } void LayoutConfigDialog::accept() { qDebug() << Q_FUNC_INFO; //setVisible(false); if (saveAllChanges()) { deleteLater(); } } void LayoutConfigDialog::reject() { qDebug() << Q_FUNC_INFO; deleteLater(); } void LayoutConfigDialog::apply() { qDebug() << Q_FUNC_INFO; saveAllChanges(); updateButtonsState(); } void LayoutConfigDialog::restoreDefaults() { qDebug() << Q_FUNC_INFO; foreach (auto preset, m_manager->presetsPaths()) { QString presetName = LayoutSettings::layoutName(preset); QByteArray presetNameChars = presetName.toUtf8(); const char *prset_str = presetNameChars.data(); presetName = i18n(prset_str); if (!nameExistsInModel(presetName)) { addLayoutForFile(preset, presetName); } } } void LayoutConfigDialog::addLayoutForFile(QString file, QString layoutName, bool newTempDirectory, bool showNotification) { if (layoutName.isEmpty()) { layoutName = LayoutSettings::layoutName(file); } QString copiedId; if (newTempDirectory) { QString tempDir = uniqueTempDirectory(); copiedId = tempDir + "/" + layoutName + ".layout.latte"; QFile(file).copy(copiedId); } else { copiedId = file; } LayoutSettings *settings = new LayoutSettings(this, copiedId); m_layouts[copiedId] = settings; QString id = copiedId; QString color = settings->color(); bool menu = settings->showInMenu(); layoutName = uniqueLayoutName(layoutName); int row = ascendingRowFor(layoutName); insertLayoutInfoAtRow(row, copiedId, color, layoutName, menu, QStringList()); ui->layoutsView->selectRow(row); if (showNotification) { //NOTE: The pointer is automatically deleted when the event is closed auto notification = new KNotification("import-done", KNotification::CloseOnTimeout); notification->setText(i18nc("import-done", "Layout: %0 imported successfully\n").arg(layoutName)); notification->sendEvent(); } } void LayoutConfigDialog::loadLayouts() { m_initLayoutPaths.clear(); m_model->clear(); int i = 0; QStringList brokenLayouts; foreach (auto layout, m_manager->layouts()) { QString layoutPath = QDir::homePath() + "/.config/latte/" + layout + ".layout.latte"; m_initLayoutPaths.append(layoutPath); LayoutSettings *layoutSets = new LayoutSettings(this, layoutPath); m_layouts[layoutPath] = layoutSets; insertLayoutInfoAtRow(i, layoutPath, layoutSets->color(), layoutSets->name(), layoutSets->showInMenu(), layoutSets->activities()); qDebug() << "counter:" << i << " total:" << m_model->rowCount(); i++; if (layoutSets->name() == m_manager->currentLayoutName()) { ui->layoutsView->selectRow(i - 1); } if (layoutSets->fileIsBroken()) { brokenLayouts.append(layoutSets->name()); } } recalculateAvailableActivities(); m_model->setHorizontalHeaderItem(IDCOLUMN, new QStandardItem(QString("#path"))); m_model->setHorizontalHeaderItem(COLORCOLUMN, new QStandardItem(QString(i18n("Color")))); m_model->setHorizontalHeaderItem(NAMECOLUMN, new QStandardItem(QString(i18n("Name")))); m_model->setHorizontalHeaderItem(MENUCOLUMN, new QStandardItem(QString(i18n("In Menu")))); m_model->setHorizontalHeaderItem(ACTIVITYCOLUMN, new QStandardItem(QString(i18n("Activities")))); //! this line should be commented for debugging layouts window functionality ui->layoutsView->setColumnHidden(IDCOLUMN, true); //! there are broken layouts and the user must be informed! if (brokenLayouts.count() > 0) { auto msg = new QMessageBox(this); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Layout Warning")); msg->setText(i18n("The layout(s) %0 have broken configuration!!! Please remove them to improve the system stability...").arg(brokenLayouts.join(","))); msg->setStandardButtons(QMessageBox::Ok); msg->open(); } } void LayoutConfigDialog::insertLayoutInfoAtRow(int row, QString path, QString color, QString name, bool menu, QStringList activities) { QStandardItem *pathItem = new QStandardItem(path); QStandardItem *colorItem = new QStandardItem(); colorItem->setSelectable(false); QStandardItem *nameItem = new QStandardItem(name); nameItem->setTextAlignment(Qt::AlignCenter); QStandardItem *menuItem = new QStandardItem(); menuItem->setEditable(false); menuItem->setSelectable(true); menuItem->setText(menu ? CheckMark : QString()); menuItem->setTextAlignment(Qt::AlignCenter); QStandardItem *activitiesItem = new QStandardItem(activities.join(",")); QList items; items.append(pathItem); items.append(colorItem); items.append(nameItem); items.append(menuItem); items.append(activitiesItem); if (row > m_model->rowCount() - 1) { m_model->appendRow(items); row = m_model->rowCount() - 1; qDebug() << "append row at:" << row << " rows:" << m_model->rowCount(); } else { m_model->insertRow(row, items); qDebug() << "insert row at:" << row << " rows:" << m_model->rowCount(); } m_model->setData(m_model->index(row, IDCOLUMN), path, Qt::DisplayRole); m_model->setData(m_model->index(row, COLORCOLUMN), color, Qt::BackgroundRole); QFont font; if (name == m_manager->currentLayoutName()) { font.setBold(true); } else { font.setBold(false); } if (path.startsWith("/tmp/")) { font.setItalic(true); } else { font.setItalic(false); } m_model->setData(m_model->index(row, NAMECOLUMN), QVariant(name), Qt::DisplayRole); m_model->setData(m_model->index(row, NAMECOLUMN), font, Qt::FontRole); m_model->setData(m_model->index(row, ACTIVITYCOLUMN), activities, Qt::UserRole); } void LayoutConfigDialog::on_switchButton_clicked() { QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); if (value.isValid()) { m_manager->switchToLayout(value.toString()); } else { qDebug() << "not valid layout"; } } void LayoutConfigDialog::currentLayoutNameChanged() { for (int i = 0; i < m_model->rowCount(); ++i) { QModelIndex nameIndex = m_model->index(i, NAMECOLUMN); QVariant value = m_model->data(nameIndex); if (value.isValid()) { QFont font; if (m_manager->currentLayoutName() == value.toString()) { font.setBold(true); ui->layoutsView->selectRow(i); } else { font.setBold(false); } m_model->setData(nameIndex, font, Qt::FontRole); } } } void LayoutConfigDialog::itemChanged(QStandardItem *item) { ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); if (item->column() == ACTIVITYCOLUMN) { //! recalculate the available activities recalculateAvailableActivities(); } } void LayoutConfigDialog::currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) { updateButtonsState(); } void LayoutConfigDialog::updateButtonsState() { QString id = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), IDCOLUMN), Qt::DisplayRole).toString(); if (m_layouts[id]->name() == m_manager->currentLayoutName()) { ui->removeButton->setEnabled(false); } else { ui->removeButton->setEnabled(true); } if (id.startsWith("/tmp/")) { ui->switchButton->setEnabled(false); } else { ui->switchButton->setEnabled(true); } } void LayoutConfigDialog::recalculateAvailableActivities() { QStringList tempActivities = m_manager->activities(); for (int i = 0; i < m_model->rowCount(); ++i) { QStringList assigned = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); foreach (auto activity, assigned) { if (tempActivities.contains(activity)) { tempActivities.removeAll(activity); } } } m_availableActivities = tempActivities; } bool LayoutConfigDialog::dataAreAccepted() { for (int i = 0; i < m_model->rowCount(); ++i) { QString layout1 = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); for (int j = i + 1; j < m_model->rowCount(); ++j) { QString temp = m_model->data(m_model->index(j, NAMECOLUMN), Qt::DisplayRole).toString(); //!same layout name exists again if (layout1 == temp) { auto msg = new QMessageBox(this); msg->setIcon(QMessageBox::Warning); msg->setWindowTitle(i18n("Layout Warning")); msg->setText(i18n("There are layouts with the same name, that is not permitted!!! Please update these names to re-apply the changes...")); msg->setStandardButtons(QMessageBox::Ok); connect(msg, &QMessageBox::finished, this, [ &, i, j](int result) { QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect; QModelIndex indexBase = m_model->index(i, NAMECOLUMN); ui->layoutsView->selectionModel()->select(indexBase, flags); QModelIndex indexOccurence = m_model->index(j, NAMECOLUMN); ui->layoutsView->edit(indexOccurence); }); msg->open(); return false; } } } return true; } bool LayoutConfigDialog::saveAllChanges() { if (!dataAreAccepted()) { return false; } QStringList knownActivities = activities(); QTemporaryDir layoutTempDir; qDebug() << "Temporary Directory ::: " << layoutTempDir.path(); QStringList fromRenamePaths; QStringList toRenamePaths; QStringList toRenameNames; QString switchToLayout; for (int i = 0; i < m_model->rowCount(); ++i) { QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); QString color = m_model->data(m_model->index(i, COLORCOLUMN), Qt::BackgroundRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); bool menu = m_model->data(m_model->index(i, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; QStringList lActivities = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); QStringList cleanedActivities; //!update only activities that are valid foreach (auto activity, lActivities) { if (knownActivities.contains(activity)) { cleanedActivities.append(activity); } } //qDebug() << i << ". " << id << " - " << color << " - " << name << " - " << menu << " - " << lActivities; LayoutSettings *layout = name == m_manager->currentLayoutName() ? m_manager->currentLayout() : m_layouts[id]; if (layout->color() != color) { layout->setColor(color); } if (layout->showInMenu() != menu) { layout->setShowInMenu(menu); } if (layout->activities() != cleanedActivities) { layout->setActivities(cleanedActivities); } //!if the layout name changed or when the layout path is a temporary one if (layout->name() != name || (id.startsWith("/tmp/"))) { QString tempFile = layoutTempDir.path() + "/" + QString(layout->name() + ".layout.latte"); qDebug() << "new temp file ::: " << tempFile; if (layout->name() == m_manager->currentLayoutName()) { switchToLayout = name; m_manager->corona()->unload(); } layout = m_layouts.take(id); delete layout; QFile(id).rename(tempFile); fromRenamePaths.append(id); toRenamePaths.append(tempFile); toRenameNames.append(name); } } //! this is necessary in case two layouts have to swap names //! so we copy first the layouts in a temp directory and afterwards all //! together we move them in the official layout directory for (int i = 0; i < toRenamePaths.count(); ++i) { QString newFile = QDir::homePath() + "/.config/latte/" + toRenameNames[i] + ".layout.latte"; QFile(toRenamePaths[i]).rename(newFile); LayoutSettings *nLayout = new LayoutSettings(this, newFile); m_layouts[newFile] = nLayout; for (int j = 0; j < m_model->rowCount(); ++j) { QString tId = m_model->data(m_model->index(j, IDCOLUMN), Qt::DisplayRole).toString(); if (tId == fromRenamePaths[i]) { m_model->setData(m_model->index(j, IDCOLUMN), newFile, Qt::DisplayRole); m_initLayoutPaths.append(newFile); QFont font = qvariant_cast(m_model->data(m_model->index(j, NAMECOLUMN), Qt::FontRole)); font.setItalic(false); m_model->setData(m_model->index(j, NAMECOLUMN), font, Qt::FontRole); } } } //! remove layouts that have been removed from the user foreach (auto initLayout, m_initLayoutPaths) { if (!idExistsInModel(initLayout)) { QFile(initLayout).remove(); } } m_manager->loadLayouts(); if (!switchToLayout.isNull()) { m_manager->switchToLayout(switchToLayout); } return true; } bool LayoutConfigDialog::idExistsInModel(QString id) { for (int i = 0; i < m_model->rowCount(); ++i) { QString rowId = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); if (rowId == id) { return true; } } return false; } bool LayoutConfigDialog::nameExistsInModel(QString name) { for (int i = 0; i < m_model->rowCount(); ++i) { QString rowName = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); if (rowName == name) { return true; } } return false; } int LayoutConfigDialog::ascendingRowFor(QString name) { for (int i = 0; i < m_model->rowCount(); ++i) { QString rowName = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); if (rowName.toUpper() > name.toUpper()) { return i; } } return m_model->rowCount(); } QString LayoutConfigDialog::uniqueTempDirectory() { QTemporaryDir tempDir; tempDir.setAutoRemove(false); m_tempDirectories.append(tempDir.path()); return tempDir.path(); } QString LayoutConfigDialog::uniqueLayoutName(QString name) { int pos_ = name.lastIndexOf(QRegExp(QString("[-][0-9]+"))); if (nameExistsInModel(name) && pos_ > 0) { name = name.left(pos_); } int i = 2; QString namePart = name; while (nameExistsInModel(name)) { name = namePart + "-" + QString::number(i); i++; } return name; } }//end of namespace