diff --git a/app/layout.cpp b/app/layout.cpp index 6afe8d04..5eebf18f 100644 --- a/app/layout.cpp +++ b/app/layout.cpp @@ -1,1714 +1,1715 @@ /* * 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 "layout.h" #include "dockcorona.h" #include "importer.h" #include "layoutmanager.h" #include "screenpool.h" #include "universalsettings.h" #include "dock/dockview.h" #include #include #include #include #include #include #include #include namespace Latte { const QString Layout::MultipleLayoutsName = ".multiple-layouts_hidden"; Layout::Layout(QObject *parent, QString layoutFile, QString assignedName) : QObject(parent) { qDebug() << "Layout file to create object: " << layoutFile << " with name: " << assignedName; if (QFile(layoutFile).exists()) { if (assignedName.isEmpty()) { assignedName = layoutName(layoutFile); } //!this order is important because setFile initializes also the m_layoutGroup setFile(layoutFile); setName(assignedName); loadConfig(); init(); } } Layout::~Layout() { if (!m_layoutFile.isEmpty()) { m_layoutGroup.sync(); } } void Layout::syncToLayoutFile() { if (!m_corona || !isWritable()) { return; } KSharedConfigPtr filePtr = KSharedConfig::openConfig(m_layoutFile); KConfigGroup oldContainments = KConfigGroup(filePtr, "Containments"); oldContainments.deleteGroup(); oldContainments.sync(); qDebug() << " LAYOUT :: " << m_layoutName << " is syncing its original file."; foreach (auto containment, m_containments) { containment->config().writeEntry("layoutId", ""); KConfigGroup newGroup = oldContainments.group(QString::number(containment->id())); containment->config().copyTo(&newGroup); } oldContainments.sync(); } void Layout::unloadContainments() { if (!m_corona) { return; } qDebug() << "Layout - " + name() + " unload: containments ... size ::: " << m_containments.size() << " ,dockViews in memory ::: " << m_dockViews.size() << " ,hidden dockViews in memory ::: " << m_waitingDockViews.size(); foreach (auto view, m_dockViews) { view->disconnectSensitiveSignals(); } foreach (auto view, m_waitingDockViews) { view->disconnectSensitiveSignals(); } m_unloadedContainmentsIds.clear(); QList systrays; //!identify systrays and unload them first foreach (auto containment, m_containments) { if (Plasma::Applet *parentApplet = qobject_cast(containment->parent())) { systrays.append(containment); } } while (!systrays.isEmpty()) { Plasma::Containment *systray = systrays.at(0); m_unloadedContainmentsIds << QString::number(systray->id()); systrays.removeFirst(); m_containments.removeAll(systray); delete systray; } while (!m_containments.isEmpty()) { Plasma::Containment *containment = m_containments.at(0); m_unloadedContainmentsIds << QString::number(containment->id()); m_containments.removeFirst(); delete containment; } } void Layout::unloadDockViews() { if (!m_corona) { return; } qDebug() << "Layout - " + name() + " unload: dockViews ... size: " << m_dockViews.size(); qDeleteAll(m_dockViews); qDeleteAll(m_waitingDockViews); m_dockViews.clear(); m_waitingDockViews.clear(); } void Layout::init() { connect(this, &Layout::activitiesChanged, this, &Layout::saveConfig); connect(this, &Layout::backgroundChanged, this, &Layout::saveConfig); connect(this, &Layout::versionChanged, this, &Layout::saveConfig); connect(this, &Layout::colorChanged, this, &Layout::textColorChanged); connect(this, &Layout::disableBordersForMaximizedWindowsChanged, this, &Layout::saveConfig); connect(this, &Layout::showInMenuChanged, this, &Layout::saveConfig); connect(this, &Layout::textColorChanged, this, &Layout::saveConfig); connect(this, &Layout::launchersChanged, this, &Layout::saveConfig); connect(this, &Layout::lastUsedActivityChanged, this, &Layout::saveConfig); } void Layout::initToCorona(DockCorona *corona) { m_corona = corona; connect(this, &Layout::dockColorizerSupportChanged, m_corona->layoutManager(), &LayoutManager::updateColorizerSupport); foreach (auto containment, m_corona->containments()) { if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { addContainment(containment); } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { QString layoutId = containment->config().readEntry("layoutId", QString()); if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { addContainment(containment); } } } qDebug() << "Layout ::::: " << name() << " added contaiments ::: " << m_containments.size(); connect(m_corona->universalSettings(), &UniversalSettings::canDisableBordersChanged, this, [&]() { if (m_corona->universalSettings()->canDisableBorders()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } else { kwin_setDisabledMaximizedBorders(false); } }); if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { connect(m_corona->layoutManager(), &LayoutManager::currentLayoutNameChanged, this, [&]() { if (m_corona->universalSettings()->canDisableBorders() && m_corona->layoutManager()->currentLayoutName() == name()) { kwin_setDisabledMaximizedBorders(disableBordersForMaximizedWindows()); } }); } if (m_layoutName != MultipleLayoutsName) { updateLastUsedActivity(); } connect(m_corona, &Plasma::Corona::containmentAdded, this, &Layout::addContainment); connect(m_corona->m_activityConsumer, &KActivities::Consumer::currentActivityChanged, this, &Layout::updateLastUsedActivity); } int Layout::version() const { return m_version; } void Layout::setVersion(int ver) { if (m_version == ver) { return; } m_version = ver; emit versionChanged(); } bool Layout::disableBordersForMaximizedWindows() const { return m_disableBordersForMaximizedWindows; } void Layout::setDisableBordersForMaximizedWindows(bool disable) { if (m_disableBordersForMaximizedWindows == disable) { return; } m_disableBordersForMaximizedWindows = disable; + kwin_setDisabledMaximizedBorders(disable); emit disableBordersForMaximizedWindowsChanged(); } bool Layout::kwin_disabledMaximizedBorders() const { //! Indentify Plasma Desktop version QProcess process; process.start("kreadconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows"); process.waitForFinished(); QString output(process.readAllStandardOutput()); output = output.remove("\n"); return (output == "true"); } void Layout::kwin_setDisabledMaximizedBorders(bool disable) { if (kwin_disabledMaximizedBorders() == disable) { return; } QString disableText = disable ? "true" : "false"; QProcess process; QString commandStr = "kwriteconfig5 --file kwinrc --group Windows --key BorderlessMaximizedWindows --type bool " + disableText; process.start(commandStr); process.waitForFinished(); QDBusInterface iface("org.kde.KWin", "/KWin", "", QDBusConnection::sessionBus()); if (iface.isValid()) { iface.call("reconfigure"); } } bool Layout::showInMenu() const { return m_showInMenu; } void Layout::setShowInMenu(bool show) { if (m_showInMenu == show) { return; } m_showInMenu = show; emit showInMenuChanged(); } bool Layout::isWritable() const { QFileInfo layoutFileInfo(m_layoutFile); if (layoutFileInfo.exists() && !layoutFileInfo.isWritable()) { return false; } else { return true; } } void Layout::lock() { QFileInfo layoutFileInfo(m_layoutFile); if (layoutFileInfo.exists() && layoutFileInfo.isWritable()) { QFile(m_layoutFile).setPermissions(QFileDevice::ReadUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } } void Layout::unlock() { QFileInfo layoutFileInfo(m_layoutFile); if (layoutFileInfo.exists() && !layoutFileInfo.isWritable()) { QFile(m_layoutFile).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } } QString Layout::background() const { return m_background; } void Layout::setBackground(QString path) { if (path == m_background) { return; } if (!path.isEmpty() && !QFileInfo(path).exists()) { return; } m_background = path; //! initialize the text color also if (path.isEmpty()) { setTextColor(QString()); } emit backgroundChanged(); } QString Layout::name() const { return m_layoutName; } void Layout::setName(QString name) { if (m_layoutName == name) { return; } qDebug() << "Layout name:" << name; m_layoutName = name; emit nameChanged(); } void Layout::renameLayout(QString newName) { if (m_layoutFile != Importer::layoutFilePath(newName)) { setFile(Importer::layoutFilePath(newName)); } if (m_layoutName != newName) { setName(newName); } //! thus this is a linked file if (m_corona) { foreach (auto containment, m_containments) { containment->config().writeEntry("layoutId", m_layoutName); } } } QString Layout::color() const { return m_color; } void Layout::setColor(QString color) { if (m_color == color) { return; } m_color = color; emit colorChanged(); } QString Layout::textColor() const { //! the user is in default layout theme if (m_background.isEmpty()) { if (m_color == "blue") { return "#D7E3FF"; } else if (m_color == "brown") { return "#F1DECB"; } else if (m_color == "darkgrey") { return "#ECECEC"; } else if (m_color == "gold") { return "#7C3636"; } else if (m_color == "green") { return "#4D7549"; } else if (m_color == "lightskyblue") { return "#0C2A43"; } else if (m_color == "orange") { return "#6F3902"; } else if (m_color == "pink") { return "#743C46"; } else if (m_color == "purple") { return "#ECD9FF"; } else if (m_color == "red") { return "#F3E4E4"; } else if (m_color == "wheat") { return "#6A4E25"; } else { return "#FCFCFC"; } } return "#" + m_textColor; } void Layout::setTextColor(QString color) { //! remove # if someone is trying to set it this way if (color.startsWith("#")) { color.remove(0, 1); } if (m_textColor == color) { return; } m_textColor = color; emit textColorChanged(); } QString Layout::file() const { return m_layoutFile; } void Layout::setFile(QString file) { if (m_layoutFile == file) { return; } qDebug() << "Layout file:" << file; m_layoutFile = file; KSharedConfigPtr filePtr = KSharedConfig::openConfig(m_layoutFile); m_layoutGroup = KConfigGroup(filePtr, "LayoutSettings"); emit fileChanged(); } QStringList Layout::launchers() const { return m_launchers; } void Layout::setLaunchers(QStringList launcherList) { if (m_launchers == launcherList) return; m_launchers = launcherList; emit launchersChanged(); } QStringList Layout::activities() const { return m_activities; } void Layout::setActivities(QStringList activities) { if (m_activities == activities) { return; } m_activities = activities; emit activitiesChanged(); } QStringList Layout::unloadedContainmentsIds() { return m_unloadedContainmentsIds; } bool Layout::isActiveLayout() const { if (!m_corona) { return false; } Layout *activeLayout = m_corona->layoutManager()->activeLayout(m_layoutName); if (activeLayout) { return true; } else { return false; } } bool Layout::isOriginalLayout() const { return m_layoutName != MultipleLayoutsName; } bool Layout::layoutIsBroken() const { if (m_layoutFile.isEmpty() || !QFile(m_layoutFile).exists()) { return false; } QStringList ids; QStringList conts; QStringList applets; KSharedConfigPtr lFile = KSharedConfig::openConfig(m_layoutFile); if (!m_corona) { KConfigGroup containmentsEntries = KConfigGroup(lFile, "Containments"); ids << containmentsEntries.groupList(); conts << ids; foreach (auto cId, containmentsEntries.groupList()) { auto appletsEntries = containmentsEntries.group(cId).group("Applets"); ids << appletsEntries.groupList(); applets << appletsEntries.groupList(); } } else { foreach (auto containment, m_containments) { ids << QString::number(containment->id()); conts << ids; foreach (auto applet, containment->applets()) { ids << QString::number(applet->id()); applets << QString::number(applet->id()); } } } QSet idsSet = QSet::fromList(ids); /* a different way to count duplicates QMap countOfStrings; for (int i = 0; i < ids.count(); i++) { countOfStrings[ids[i]]++; }*/ if (idsSet.count() != ids.count()) { qDebug() << " ---- ERROR - BROKEN LAYOUT :: " << m_layoutName << " ----"; if (!m_corona) { qDebug() << " ---- file : " << m_layoutFile; } else { qDebug() << " ---- in multiple layouts hidden file : " << Importer::layoutFilePath(Layout::MultipleLayoutsName); } qDebug() << "Contaiments :: " << conts; qDebug() << "Applets :: " << applets; foreach (QString c, conts) { if (applets.contains(c)) { qDebug() << "Error: Same applet and containment id found ::: " << c; } } for (int i = 0; i < ids.count(); ++i) { for (int j = i + 1; j < ids.count(); ++j) { if (ids[i] == ids[j]) { qDebug() << "Error: Applets with same id ::: " << ids[i]; } } } qDebug() << " -- - -- - -- - -- - - -- - - - - -- - - - - "; if (!m_corona) { KConfigGroup containmentsEntries = KConfigGroup(lFile, "Containments"); foreach (auto cId, containmentsEntries.groupList()) { auto appletsEntries = containmentsEntries.group(cId).group("Applets"); qDebug() << " CONTAINMENT : " << cId << " APPLETS : " << appletsEntries.groupList(); } } else { foreach (auto containment, m_containments) { QStringList appletsIds; foreach (auto applet, containment->applets()) { appletsIds << QString::number(applet->id()); } qDebug() << " CONTAINMENT : " << containment->id() << " APPLETS : " << appletsIds.join(","); } } return true; } return false; } QString Layout::layoutName(const QString &fileName) { int lastSlash = fileName.lastIndexOf("/"); QString tempLayoutFile = fileName; QString layoutName = tempLayoutFile.remove(0, lastSlash + 1); int ext = layoutName.lastIndexOf(".layout.latte"); layoutName = layoutName.remove(ext, 13); return layoutName; } void Layout::loadConfig() { m_version = m_layoutGroup.readEntry("version", 2); m_color = m_layoutGroup.readEntry("color", QString("blue")); m_disableBordersForMaximizedWindows = m_layoutGroup.readEntry("disableBordersForMaximizedWindows", false); m_showInMenu = m_layoutGroup.readEntry("showInMenu", false); m_textColor = m_layoutGroup.readEntry("textColor", QString("fcfcfc")); m_activities = m_layoutGroup.readEntry("activities", QStringList()); m_launchers = m_layoutGroup.readEntry("launchers", QStringList()); m_lastUsedActivity = m_layoutGroup.readEntry("lastUsedActivity", QString()); QString back = m_layoutGroup.readEntry("background", ""); if (!back.isEmpty()) { if (QFileInfo(back).exists()) { m_background = back; } else { m_layoutGroup.writeEntry("background", QString()); } } emit activitiesChanged(); } void Layout::saveConfig() { qDebug() << "layout is saving... for layout:" << m_layoutName; m_layoutGroup.writeEntry("version", m_version); m_layoutGroup.writeEntry("showInMenu", m_showInMenu); m_layoutGroup.writeEntry("color", m_color); m_layoutGroup.writeEntry("disableBordersForMaximizedWindows", m_disableBordersForMaximizedWindows); m_layoutGroup.writeEntry("launchers", m_launchers); m_layoutGroup.writeEntry("background", m_background); m_layoutGroup.writeEntry("activities", m_activities); m_layoutGroup.writeEntry("lastUsedActivity", m_lastUsedActivity); m_layoutGroup.writeEntry("textColor", m_textColor); m_layoutGroup.sync(); } //! Containments Actions void Layout::addContainment(Plasma::Containment *containment) { if (!containment || m_containments.contains(containment)) { return; } bool containmentInLayout{false}; if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { m_containments.append(containment); containmentInLayout = true; } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { QString layoutId = containment->config().readEntry("layoutId", QString()); if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { m_containments.append(containment); containmentInLayout = true; } } if (containmentInLayout) { addDock(containment); connect(containment, &QObject::destroyed, this, &Layout::containmentDestroyed); } } QHash *Layout::dockViews() { return &m_dockViews; } QList *Layout::containments() { return &m_containments; } const QStringList Layout::appliedActivities() { if (!m_corona) { return {}; } if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { return {"0"}; } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { if (m_activities.isEmpty()) { return m_corona->layoutManager()->orphanedActivities(); } else { return m_activities; } } } QString Layout::lastUsedActivity() { return m_lastUsedActivity; } void Layout::clearLastUsedActivity() { m_lastUsedActivity = ""; emit lastUsedActivityChanged(); } void Layout::updateLastUsedActivity() { if (!m_corona) { return; } if (!m_lastUsedActivity.isEmpty() && !m_corona->layoutManager()->activities().contains(m_lastUsedActivity)) { clearLastUsedActivity(); } QString currentId = m_corona->activitiesConsumer()->currentActivity(); QStringList appliedActivitiesIds = appliedActivities(); if (m_lastUsedActivity != currentId && (appliedActivitiesIds.contains(currentId) || m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout)) { m_lastUsedActivity = currentId; emit lastUsedActivityChanged(); } } void Layout::destroyedChanged(bool destroyed) { if (!m_corona) { return; } qDebug() << "dock containment destroyed changed!!!!"; Plasma::Containment *sender = qobject_cast(QObject::sender()); if (!sender) { return; } if (destroyed) { m_waitingDockViews[sender] = m_dockViews.take(static_cast(sender)); } else { m_dockViews[sender] = m_waitingDockViews.take(static_cast(sender)); } emit m_corona->docksCountChanged(); emit m_corona->availableScreenRectChanged(); emit m_corona->availableScreenRegionChanged(); } void Layout::containmentDestroyed(QObject *cont) { if (!m_corona) { return; } Plasma::Containment *containment = static_cast(cont); if (containment) { int containmentIndex = m_containments.indexOf(containment); if (containmentIndex >= 0) { m_containments.removeAt(containmentIndex); } qDebug() << "Layout " << name() << " :: containment destroyed!!!!"; auto view = m_dockViews.take(containment); if (!view) { view = m_waitingDockViews.take(containment); } if (view) { view->disconnectSensitiveSignals(); view->deleteLater(); emit m_corona->docksCountChanged(); emit m_corona->availableScreenRectChanged(); emit m_corona->availableScreenRegionChanged(); emit dockColorizerSupportChanged(); } } } void Layout::addDock(Plasma::Containment *containment, bool forceLoading, int expDockScreen) { qDebug() << "Layout :::: " << m_layoutName << " ::: addDock was called... m_containments :: " << m_containments.size(); if (!containment || !m_corona || !containment->kPackage().isValid()) { qWarning() << "the requested containment plugin can not be located or loaded"; return; } auto metadata = containment->kPackage().metadata(); qDebug() << "step 1..."; if (metadata.pluginId() != "org.kde.latte.containment") return; qDebug() << "step 2..."; for (auto *dock : m_dockViews) { if (dock->containment() == containment) return; } qDebug() << "step 3..."; QScreen *nextScreen{qGuiApp->primaryScreen()}; bool onPrimary = containment->config().readEntry("onPrimary", true); int id = containment->screen(); if (id == -1 && expDockScreen == -1) { id = containment->lastScreen(); } if (expDockScreen > -1) { id = expDockScreen; } qDebug() << "add dock - containment id: " << containment->id() << " ,screen id : " << id << " ,onprimary:" << onPrimary << " ,forceDockLoad:" << forceLoading; if (id >= 0 && !onPrimary && !forceLoading) { QString connector = m_corona->screenPool()->connector(id); qDebug() << "add dock - connector : " << connector; bool found{false}; foreach (auto scr, qGuiApp->screens()) { if (scr && scr->name() == connector) { found = true; nextScreen = scr; break; } } if (!found) { qDebug() << "adding dock rejected, screen not available ! : " << connector; return; } } else if (onPrimary) { if (explicitDockOccupyEdge(m_corona->screenPool()->primaryScreenId(), containment->location())) { qDebug() << "CORONA ::: adding dock rejected, the edge is occupied by explicit dock ! : " << containment->location(); //we must check that an onPrimary dock should never catch up the same edge on //the same screen with an explicit dock return; } } qDebug() << "Adding dock for container..."; qDebug() << "onPrimary: " << onPrimary << "screen!!! :" << nextScreen->name(); //! it is used to set the correct flag during the creation //! of the window... This of course is also used during //! recreations of the window between different visibility modes auto mode = static_cast(containment->config().readEntry("visibility", static_cast(Dock::DodgeActive))); bool dockWin{true}; if (mode == Dock::AlwaysVisible || mode == Dock::WindowsGoBelow) { dockWin = true; } else { dockWin = containment->config().readEntry("dockWindowBehavior", true); } auto dockView = new DockView(m_corona, nextScreen, dockWin); dockView->init(); dockView->setContainment(containment); dockView->setManagedLayout(this); //! force this special dock case to become primary //! even though it isnt if (forceLoading) { dockView->setOnPrimary(true); } // connect(containment, &QObject::destroyed, this, &Layout::containmentDestroyed); connect(containment, &Plasma::Applet::destroyedChanged, this, &Layout::destroyedChanged); connect(containment, &Plasma::Applet::locationChanged, m_corona, &DockCorona::dockLocationChanged); connect(containment, &Plasma::Containment::appletAlternativesRequested , m_corona, &DockCorona::showAlternativesForApplet, Qt::QueuedConnection); if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { connect(containment, &Plasma::Containment::appletCreated, this, &Layout::appletCreated); } connect(dockView, &DockView::colorizerSupportChanged, this, &Layout::dockColorizerSupportChanged); //! Qt 5.9 creates a crash for this in wayland, that is why the check is used //! but on the other hand we need this for copy to work correctly and show //! the copied dock under X11 //if (!KWindowSystem::isPlatformWayland()) { dockView->show(); //} m_dockViews[containment] = dockView; emit dockColorizerSupportChanged(); emit m_corona->docksCountChanged(); } void Layout::copyDock(Plasma::Containment *containment) { if (!containment || !m_corona) return; qDebug() << "copying containment layout"; //! Settting mutable for create a containment m_corona->setImmutability(Plasma::Types::Mutable); QString temp1File = QDir::homePath() + "/.config/lattedock.copy1.bak"; //! WE NEED A WAY TO COPY A CONTAINMENT!!!! QFile copyFile(temp1File); if (copyFile.exists()) copyFile.remove(); KSharedConfigPtr newFile = KSharedConfig::openConfig(temp1File); KConfigGroup copied_conts = KConfigGroup(newFile, "Containments"); KConfigGroup copied_c1 = KConfigGroup(&copied_conts, QString::number(containment->id())); KConfigGroup copied_systray; // toCopyContainmentIds << QString::number(containment->id()); // toCopyAppletIds << containment->config().group("Applets").groupList(); containment->config().copyTo(&copied_c1); //!investigate if there is a systray in the containment to copy also int systrayId = -1; QString systrayAppletId; auto applets = containment->config().group("Applets"); foreach (auto applet, applets.groupList()) { KConfigGroup appletSettings = applets.group(applet).group("Configuration"); int tSysId = appletSettings.readEntry("SystrayContainmentId", -1); if (tSysId != -1) { systrayId = tSysId; systrayAppletId = applet; qDebug() << "systray was found in the containment... ::: " << tSysId; break; } } if (systrayId != -1) { Plasma::Containment *systray{nullptr}; foreach (auto containment, m_corona->containments()) { if (containment->id() == systrayId) { systray = containment; break; } } if (systray) { copied_systray = KConfigGroup(&copied_conts, QString::number(systray->id())); // toCopyContainmentIds << QString::number(systray->id()); // toCopyAppletIds << systray->config().group("Applets").groupList(); systray->config().copyTo(&copied_systray); } } //! end of systray specific code //! update ids to unique ones QString temp2File = newUniqueIdsLayoutFromFile(temp1File); //! Finally import the configuration QList importedDocks = importLayoutFile(temp2File); Plasma::Containment *newContainment{nullptr}; if (importedDocks.size() == 1) { newContainment = importedDocks[0]; } if (!newContainment || !newContainment->kPackage().isValid()) { qWarning() << "the requested containment plugin can not be located or loaded"; return; } auto config = newContainment->config(); //in multi-screen environment the copied dock is moved to alternative screens first const auto screens = qGuiApp->screens(); auto dock = m_dockViews[containment]; bool setOnExplicitScreen = false; int dockScrId = -1; int copyScrId = -1; if (dock) { dockScrId = m_corona->screenPool()->id(dock->currentScreen()); qDebug() << "COPY DOCK SCREEN ::: " << dockScrId; if (dockScrId != -1 && screens.count() > 1) { foreach (auto scr, screens) { copyScrId = m_corona->screenPool()->id(scr->name()); //the screen must exist and not be the same with the original dock if (copyScrId > -1 && copyScrId != dockScrId) { QList fEdges = freeEdges(copyScrId); if (fEdges.contains((Plasma::Types::Location)containment->location())) { ///set this containment to an explicit screen config.writeEntry("onPrimary", false); config.writeEntry("lastScreen", copyScrId); newContainment->setLocation(containment->location()); qDebug() << "COPY DOCK SCREEN NEW SCREEN ::: " << copyScrId; setOnExplicitScreen = true; break; } } } } } if (!setOnExplicitScreen) { QList edges = freeEdges(newContainment->screen()); if (edges.count() > 0) { newContainment->setLocation(edges.at(0)); } else { newContainment->setLocation(Plasma::Types::BottomEdge); } config.writeEntry("onPrimary", false); config.writeEntry("lastScreen", dockScrId); } newContainment->config().sync(); if (setOnExplicitScreen && copyScrId > -1) { qDebug() << "Copy Dock in explicit screen ::: " << copyScrId; addDock(newContainment, copyScrId); newContainment->reactToScreenChange(); } else { qDebug() << "Copy Dock in current screen..."; addDock(newContainment, dockScrId); } } void Layout::appletCreated(Plasma::Applet *applet) { //! In Multiple Layout the orphaned systrays must be assigned to layouts //! when the user adds them KConfigGroup appletSettings = applet->containment()->config().group("Applets").group(QString::number(applet->id())).group("Configuration"); int systrayId = appletSettings.readEntry("SystrayContainmentId", -1); if (systrayId != -1) { uint sId = (uint)systrayId; foreach (auto containment, m_corona->containments()) { if (containment->id() == sId) { containment->config().writeEntry("layoutId", m_layoutName); } addContainment(containment); } } } void Layout::importToCorona() { if (!m_corona) { return; } //! Settting mutable for create a containment m_corona->setImmutability(Plasma::Types::Mutable); QString temp1File = QDir::homePath() + "/.config/lattedock.copy1.bak"; //! WE NEED A WAY TO COPY A CONTAINMENT!!!! QFile copyFile(temp1File); if (copyFile.exists()) copyFile.remove(); KSharedConfigPtr filePtr = KSharedConfig::openConfig(m_layoutFile); KSharedConfigPtr newFile = KSharedConfig::openConfig(temp1File); KConfigGroup copyGroup = KConfigGroup(newFile, "Containments"); KConfigGroup current_containments = KConfigGroup(filePtr, "Containments"); current_containments.copyTo(©Group); copyGroup.sync(); //! update ids to unique ones QString temp2File = newUniqueIdsLayoutFromFile(temp1File); //! Finally import the configuration importLayoutFile(temp2File); } QString Layout::availableId(QStringList all, QStringList assigned, int base) { bool found = false; int i = base; while (!found && i < 32000) { QString iStr = QString::number(i); if (!all.contains(iStr) && !assigned.contains(iStr)) { return iStr; } i++; } return QString(""); } QString Layout::newUniqueIdsLayoutFromFile(QString file) { if (!m_corona) { return QString(); } QString tempFile = QDir::homePath() + "/.config/lattedock.copy2.bak"; QFile copyFile(tempFile); if (copyFile.exists()) copyFile.remove(); //! BEGIN updating the ids in the temp file QStringList allIds; allIds << m_corona->containmentsIds(); allIds << m_corona->appletsIds(); QStringList toInvestigateContainmentIds; QStringList toInvestigateAppletIds; QStringList toInvestigateSystrayContIds; //! first is the systray containment id QHash systrayParentContainmentIds; QHash systrayAppletIds; //qDebug() << "Ids:" << allIds; //qDebug() << "to copy containments: " << toCopyContainmentIds; //qDebug() << "to copy applets: " << toCopyAppletIds; QStringList assignedIds; QHash assigned; KSharedConfigPtr filePtr = KSharedConfig::openConfig(file); KConfigGroup investigate_conts = KConfigGroup(filePtr, "Containments"); //KConfigGroup copied_c1 = KConfigGroup(&copied_conts, QString::number(containment->id())); //! Record the containment and applet ids foreach (auto cId, investigate_conts.groupList()) { toInvestigateContainmentIds << cId; auto appletsEntries = investigate_conts.group(cId).group("Applets"); toInvestigateAppletIds << appletsEntries.groupList(); //! investigate for systrays foreach (auto appletId, appletsEntries.groupList()) { KConfigGroup appletSettings = appletsEntries.group(appletId).group("Configuration"); int tSysId = appletSettings.readEntry("SystrayContainmentId", -1); //! It is a systray !!! if (tSysId != -1) { QString tSysIdStr = QString::number(tSysId); toInvestigateSystrayContIds << tSysIdStr; systrayParentContainmentIds[tSysIdStr] = cId; systrayAppletIds[tSysIdStr] = appletId; qDebug() << "systray was found in the containment..."; } } } //! Reassign containment and applet ids to unique ones foreach (auto contId, toInvestigateContainmentIds) { QString newId = availableId(allIds, assignedIds, 12); assignedIds << newId; assigned[contId] = newId; } foreach (auto appId, toInvestigateAppletIds) { QString newId = availableId(allIds, assignedIds, 40); assignedIds << newId; assigned[appId] = newId; } qDebug() << "ALL CORONA IDS ::: " << allIds; qDebug() << "FULL ASSIGNMENTS ::: " << assigned; foreach (auto cId, toInvestigateContainmentIds) { QString value = assigned[cId]; if (assigned.contains(value)) { QString value2 = assigned[value]; if (cId != assigned[cId] && !value2.isEmpty() && cId == value2) { qDebug() << "PROBLEM APPEARED !!!! FOR :::: " << cId << " .. fixed .."; assigned[cId] = cId; assigned[value] = value; } } } foreach (auto aId, toInvestigateAppletIds) { QString value = assigned[aId]; if (assigned.contains(value)) { QString value2 = assigned[value]; if (aId != assigned[aId] && !value2.isEmpty() && aId == value2) { qDebug() << "PROBLEM APPEARED !!!! FOR :::: " << aId << " .. fixed .."; assigned[aId] = aId; assigned[value] = value; } } } qDebug() << "FIXED FULL ASSIGNMENTS ::: " << assigned; //! update applet ids in their contaiment order and in MultipleLayouts update also the layoutId foreach (auto cId, investigate_conts.groupList()) { //! Update (appletOrder) and (lockedZoomApplets) for (int i = 1; i <= 2; ++i) { QString settingStr = (i == 1) ? "appletOrder" : "lockedZoomApplets"; QString order1 = investigate_conts.group(cId).group("General").readEntry(settingStr, QString()); if (!order1.isEmpty()) { QStringList order1Ids = order1.split(";"); QStringList fixedOrder1Ids; for (int i = 0; i < order1Ids.count(); ++i) { fixedOrder1Ids.append(assigned[order1Ids[i]]); } QString fixedOrder1 = fixedOrder1Ids.join(";"); investigate_conts.group(cId).group("General").writeEntry(settingStr, fixedOrder1); } } if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { investigate_conts.group(cId).writeEntry("layoutId", m_layoutName); } } //! must update also the systray id in its applet foreach (auto systrayId, toInvestigateSystrayContIds) { KConfigGroup systrayParentContainment = investigate_conts.group(systrayParentContainmentIds[systrayId]); systrayParentContainment.group("Applets").group(systrayAppletIds[systrayId]).group("Configuration").writeEntry("SystrayContainmentId", assigned[systrayId]); systrayParentContainment.sync(); } investigate_conts.sync(); //! Copy To Temp 2 File And Update Correctly The Ids KSharedConfigPtr file2Ptr = KSharedConfig::openConfig(tempFile); KConfigGroup fixedNewContainmets = KConfigGroup(file2Ptr, "Containments"); foreach (auto contId, investigate_conts.groupList()) { QString pluginId = investigate_conts.group(contId).readEntry("plugin", ""); if (pluginId != "org.kde.desktopcontainment") { //!dont add ghost containments KConfigGroup newContainmentGroup = fixedNewContainmets.group(assigned[contId]); investigate_conts.group(contId).copyTo(&newContainmentGroup); newContainmentGroup.group("Applets").deleteGroup(); foreach (auto appId, investigate_conts.group(contId).group("Applets").groupList()) { KConfigGroup appletGroup = investigate_conts.group(contId).group("Applets").group(appId); KConfigGroup newAppletGroup = fixedNewContainmets.group(assigned[contId]).group("Applets").group(assigned[appId]); appletGroup.copyTo(&newAppletGroup); } } } fixedNewContainmets.sync(); return tempFile; } QList Layout::importLayoutFile(QString file) { KSharedConfigPtr filePtr = KSharedConfig::openConfig(file); auto newContainments = m_corona->importLayout(KConfigGroup(filePtr, "")); ///Find latte and systray containments qDebug() << " imported containments ::: " << newContainments.length(); QList importedDocks; //QList systrays; foreach (auto containment, newContainments) { KPluginMetaData meta = containment->kPackage().metadata(); if (meta.pluginId() == "org.kde.latte.containment") { qDebug() << "new latte containment id: " << containment->id(); importedDocks << containment; } } ///after systrays were found we must update in latte the relevant ids /*if (!systrays.isEmpty()) { foreach (auto systray, systrays) { qDebug() << "systray found with id : " << systray->id(); Plasma::Applet *parentApplet = qobject_cast(systray->parent()); if (parentApplet) { KConfigGroup appletSettings = parentApplet->config().group("Configuration"); if (appletSettings.hasKey("SystrayContainmentId")) { qDebug() << "!!! updating systray id to : " << systray->id(); appletSettings.writeEntry("SystrayContainmentId", systray->id()); } } } }*/ return importedDocks; } void Layout::recreateDock(Plasma::Containment *containment) { if (!m_corona) { return; } //! give the time to config window to close itself first and then recreate the dock //! step:1 remove the dockview QTimer::singleShot(350, [this, containment]() { auto view = m_dockViews.take(containment); if (view) { qDebug() << "recreate - step 1: removing dock for containment:" << containment->id(); //! step:2 add the new dockview connect(view, &QObject::destroyed, this, [this, containment]() { QTimer::singleShot(250, this, [this, containment]() { if (!m_dockViews.contains(containment)) { qDebug() << "recreate - step 2: adding dock for containment:" << containment->id(); addDock(containment); } }); }); view->deleteLater(); } }); } //! the central functions that updates loading/unloading dockviews //! concerning screen changed (for multi-screen setups mainly) void Layout::syncDockViewsToScreens() { if (!m_corona) { return; } qDebug() << "LAYOUT ::: " << name(); qDebug() << "screen count changed -+-+ " << qGuiApp->screens().size(); qDebug() << "adding consideration...."; qDebug() << "dock view running : " << m_dockViews.count(); foreach (auto scr, qGuiApp->screens()) { qDebug() << "Found screen: " << scr->name(); foreach (auto cont, m_containments) { int id = cont->screen(); if (id == -1) { id = cont->lastScreen(); } bool onPrimary = cont->config().readEntry("onPrimary", true); Plasma::Types::Location location = static_cast((int)cont->config().readEntry("location", (int)Plasma::Types::BottomEdge)); //! two main situations that a dock must be added when it is not already running //! 1. when a dock is primary, not running and the edge for which is associated is free //! 2. when a dock in explicit, not running and the associated screen currently exists //! e.g. the screen has just been added if (((onPrimary && freeEdges(qGuiApp->primaryScreen()).contains(location)) || (!onPrimary && (m_corona->screenPool()->connector(id) == scr->name()))) && (!m_dockViews.contains(cont))) { qDebug() << "screen Count signal: view must be added... for:" << scr->name(); addDock(cont); } } } qDebug() << "removing consideration & updating screen for always on primary docks...."; //! this code tries to find a containment that must not be deleted by //! automatic algorithm. Currently the containment with the minimum id //! containing tasks plasmoid wins int preserveContainmentId{ -1}; bool dockWithTasksWillBeShown{false}; //! associate correct values for preserveContainmentId and //! dockWithTasksWillBeShown foreach (auto view, m_dockViews) { bool found{false}; foreach (auto scr, qGuiApp->screens()) { if (scr->name() == view->currentScreen() || (view->onPrimary() && scr == qGuiApp->primaryScreen())) { found = true; break; } } //!check if a tasks dock will be shown (try to prevent its deletion) if (found && view->tasksPresent()) { dockWithTasksWillBeShown = true; } if (!found && !view->onPrimary() && (m_dockViews.size() > 1) && m_dockViews.contains(view->containment()) && !(view->tasksPresent() && noDocksWithTasks() == 1)) { //do not delete last dock containing tasks if (view->tasksPresent()) { if (preserveContainmentId == -1) preserveContainmentId = view->containment()->id(); else if (view->containment()->id() < preserveContainmentId) preserveContainmentId = view->containment()->id(); } } } //! check which docks must be deleted e.g. when the corresponding //! screen does not exist any more. //! The code is smart enough in order //! to never delete the last tasks dock and also it makes sure that //! the last tasks dock which will exist in the end will be the one //! with the lowest containment id foreach (auto view, m_dockViews) { bool found{false}; foreach (auto scr, qGuiApp->screens()) { if (scr->name() == view->currentScreen() || (view->onPrimary() && scr == qGuiApp->primaryScreen())) { found = true; break; } } //! which explicit docks can be deleted if (!found && !view->onPrimary() && (m_dockViews.size() > 1) && m_dockViews.contains(view->containment()) && !(view->tasksPresent() && noDocksWithTasks() == 1)) { //do not delete last dock containing tasks if (dockWithTasksWillBeShown || preserveContainmentId != view->containment()->id()) { qDebug() << "screen Count signal: view must be deleted... for:" << view->currentScreen(); auto viewToDelete = m_dockViews.take(view->containment()); viewToDelete->deleteLater(); } //!which primary docks can be deleted } else if (view->onPrimary() && !found && !freeEdges(qGuiApp->primaryScreen()).contains(view->location())) { qDebug() << "screen Count signal: primary view must be deleted... for:" << view->currentScreen(); auto viewToDelete = m_dockViews.take(view->containment()); viewToDelete->deleteLater(); } else { //! if the dock will not be deleted its a very good point to reconsider //! if the screen in which is running is the correct one view->reconsiderScreen(); } } qDebug() << "end of screens count change...."; } void Layout::assignToLayout(DockView *dockView, QList containments) { if (!m_corona) { return; } if (dockView) { m_dockViews[dockView->containment()] = dockView; m_containments << containments; foreach (auto containment, containments) { containment->config().writeEntry("layoutId", name()); connect(containment, &QObject::destroyed, this, &Layout::containmentDestroyed); connect(containment, &Plasma::Applet::destroyedChanged, this, &Layout::destroyedChanged); connect(containment, &Plasma::Containment::appletCreated, this, &Layout::appletCreated); } dockView->setManagedLayout(this); emit m_corona->docksCountChanged(); emit m_corona->availableScreenRectChanged(); emit m_corona->availableScreenRegionChanged(); } } QList Layout::unassignFromLayout(DockView *dockView) { QList containments; if (!m_corona) { return containments; } containments << dockView->containment(); foreach (auto containment, m_containments) { Plasma::Applet *parentApplet = qobject_cast(containment->parent()); //! add systrays from that dockView if (parentApplet && parentApplet->containment() && parentApplet->containment() == dockView->containment()) { containments << containment; disconnect(containment, &QObject::destroyed, this, &Layout::containmentDestroyed); disconnect(containment, &Plasma::Applet::destroyedChanged, this, &Layout::destroyedChanged); disconnect(containment, &Plasma::Containment::appletCreated, this, &Layout::appletCreated); } } foreach (auto containment, containments) { m_containments.removeAll(containment); } if (containments.size() > 0) { m_dockViews.remove(dockView->containment()); } return containments; } QList Layout::freeEdges(QScreen *screen) const { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; if (!m_corona) { return edges; } foreach (auto view, m_dockViews) { if (view && view->currentScreen() == screen->name()) { edges.removeOne(view->location()); } } return edges; } QList Layout::freeEdges(int screen) const { using Plasma::Types; QList edges{Types::BottomEdge, Types::LeftEdge, Types::TopEdge, Types::RightEdge}; if (!m_corona) { return edges; } QScreen *scr = m_corona->screenPool()->screenForId(screen); foreach (auto view, m_dockViews) { if (view && scr && view->currentScreen() == scr->name()) { edges.removeOne(view->location()); } } return edges; } bool Layout::explicitDockOccupyEdge(int screen, Plasma::Types::Location location) const { if (!m_corona) { return false; } foreach (auto containment, m_containments) { if (containment->pluginMetaData().pluginId() == "org.kde.latte.containment") { bool onPrimary = containment->config().readEntry("onPrimary", true); int id = containment->lastScreen(); Plasma::Types::Location contLocation = containment->location(); if (!onPrimary && id == screen && contLocation == location) { return true; } } } return false; } int Layout::noDocksWithTasks() const { if (!m_corona) { return 0; } int result = 0; foreach (auto view, m_dockViews) { if (view->tasksPresent()) { result++; } } return result; } int Layout::docksCount(int screen) const { if (!m_corona) { return 0; } QScreen *scr = m_corona->screenPool()->screenForId(screen); int docks{0}; foreach (auto view, m_dockViews) { if (view && view->screen() == scr && !view->containment()->destroyed()) { ++docks; } } return docks; } int Layout::docksCount() const { if (!m_corona) { return 0; } int docks{0}; foreach (auto view, m_dockViews) { if (view && view->containment() && !view->containment()->destroyed()) { ++docks; } } return docks; } int Layout::docksCount(QScreen *screen) const { if (!m_corona) { return 0; } int docks{0}; foreach (auto view, m_dockViews) { if (view && view->screen() == screen && !view->containment()->destroyed()) { ++docks; } } return docks; } } diff --git a/app/settingsdialog.cpp b/app/settingsdialog.cpp index 296e1b2a..d4cda152 100644 --- a/app/settingsdialog.cpp +++ b/app/settingsdialog.cpp @@ -1,1524 +1,1564 @@ /* * 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 "settingsdialog.h" #include "dockcorona.h" #include "layout.h" #include "layoutmanager.h" #include "importer.h" #include "universalsettings.h" #include "ui_settingsdialog.h" #include "../liblattedock/dock.h" #include "layoutsDelegates/checkboxdelegate.h" #include "layoutsDelegates/colorcmbboxdelegate.h" #include "layoutsDelegates/activitycmbboxdelegate.h" #include "layoutsDelegates/layoutnamedelegate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Latte { const int IDCOLUMN = 0; const int HIDDENTEXTCOLUMN = 1; const int COLORCOLUMN = 2; const int NAMECOLUMN = 3; const int MENUCOLUMN = 4; -const int ACTIVITYCOLUMN = 5; +const int BORDERSCOLUMN = 5; +const int ACTIVITYCOLUMN = 6; const int SCREENTRACKERDEFAULTVALUE = 2500; const QChar CheckMark{0x2714}; SettingsDialog::SettingsDialog(QWidget *parent, DockCorona *corona) : QDialog(parent), ui(new Ui::SettingsDialog), m_corona(corona) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); resize(m_corona->universalSettings()->layoutsWindowSize()); connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked , this, &SettingsDialog::apply); connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked , this, &SettingsDialog::restoreDefaults); m_model = new QStandardItemModel(m_corona->layoutManager()->layouts().count(), 6, this); ui->layoutsView->setModel(m_model); ui->layoutsView->horizontalHeader()->setStretchLastSection(true); ui->layoutsView->verticalHeader()->setVisible(false); connect(m_corona->layoutManager(), &LayoutManager::currentLayoutNameChanged, this, &SettingsDialog::layoutsChanged); connect(m_corona->layoutManager(), &LayoutManager::activeLayoutsChanged, this, &SettingsDialog::layoutsChanged); QString iconsPath(m_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(NAMECOLUMN, new LayoutNameDelegate(this)); ui->layoutsView->setItemDelegateForColumn(COLORCOLUMN, new ColorCmbBoxDelegate(this, iconsPath, colors)); ui->layoutsView->setItemDelegateForColumn(MENUCOLUMN, new CheckBoxDelegate(this)); + ui->layoutsView->setItemDelegateForColumn(BORDERSCOLUMN, new CheckBoxDelegate(this)); ui->layoutsView->setItemDelegateForColumn(ACTIVITYCOLUMN, new ActivityCmbBoxDelegate(this)); m_inMemoryButtons = new QButtonGroup(this); m_inMemoryButtons->addButton(ui->singleToolBtn, Latte::Dock::SingleLayout); m_inMemoryButtons->addButton(ui->multipleToolBtn, Latte::Dock::MultipleLayouts); m_inMemoryButtons->setExclusive(true); if (KWindowSystem::isPlatformWayland()) { m_inMemoryButtons->button(Latte::Dock::MultipleLayouts)->setEnabled(false); } m_mouseSensitivityButtons = new QButtonGroup(this); m_mouseSensitivityButtons->addButton(ui->lowSensitivityBtn, Latte::Dock::LowSensitivity); m_mouseSensitivityButtons->addButton(ui->mediumSensitivityBtn, Latte::Dock::MediumSensitivity); m_mouseSensitivityButtons->addButton(ui->highSensitivityBtn, Latte::Dock::HighSensitivity); m_mouseSensitivityButtons->setExclusive(true); ui->screenTrackerSpinBox->setValue(m_corona->universalSettings()->screenTrackerInterval()); //! About Menu QMenuBar *menuBar = new QMenuBar(this); // QMenuBar *rightAlignedMenuBar = new QMenuBar(menuBar); layout()->setMenuBar(menuBar); //menuBar->setCornerWidget(rightAlignedMenuBar); QMenu *fileMenu = new QMenu(i18n("File"), menuBar); menuBar->addMenu(fileMenu); QMenu *helpMenu = new QMenu(i18n("Help"), menuBar); //rightAlignedMenuBar->addMenu(helpMenu); menuBar->addMenu(helpMenu); QAction *quitAction = fileMenu->addAction(i18n("Quit Latte")); quitAction->setIcon(QIcon::fromTheme("application-exit")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); QAction *aboutAction = helpMenu->addAction(i18n("About Latte")); aboutAction->setIcon(QIcon::fromTheme("latte-dock")); //! RTL support for labels in preferences if (qApp->layoutDirection() == Qt::RightToLeft) { ui->behaviorLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); ui->mouseSensetivityLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); ui->delayLbl->setAlignment(Qt::AlignRight | Qt::AlignTop); } loadSettings(); //! SIGNALS connect(m_model, &QStandardItemModel::itemChanged, this, &SettingsDialog::itemChanged); connect(ui->layoutsView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, [&]() { updatePerLayoutButtonsState(); updateApplyButtonsState(); }); connect(m_inMemoryButtons, static_cast(&QButtonGroup::buttonToggled), [ = ](int id, bool checked) { updateApplyButtonsState(); }); connect(m_mouseSensitivityButtons, static_cast(&QButtonGroup::buttonToggled), [ = ](int id, bool checked) { updateApplyButtonsState(); }); connect(ui->screenTrackerSpinBox, QOverload::of(&QSpinBox::valueChanged), [ = ](int i) { updateApplyButtonsState(); }); connect(ui->autostartChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->infoWindowChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); - connect(ui->noBordersForMaximizedChkBox, &QCheckBox::stateChanged, this, &SettingsDialog::updateApplyButtonsState); connect(ui->tabWidget, &QTabWidget::currentChanged, this, &SettingsDialog::updateApplyButtonsState); + connect(ui->noBordersForMaximizedChkBox, &QCheckBox::stateChanged, this, [&]() { + bool noBordersForMaximized = ui->noBordersForMaximizedChkBox->isChecked(); + + if (noBordersForMaximized) { + ui->layoutsView->setColumnHidden(BORDERSCOLUMN, false); + } else { + ui->layoutsView->setColumnHidden(BORDERSCOLUMN, true); + } + + updateApplyButtonsState(); + }); + connect(aboutAction, &QAction::triggered, m_corona, &DockCorona::aboutApplication); connect(quitAction, &QAction::triggered, m_corona, &DockCorona::closeApplication); //! update all layouts view when runningActivities changed. This way we update immediately //! the running Activities in Activities checkboxes which are shown as bold connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, [&]() { ui->layoutsView->update(); }); blockDeleteOnActivityStopped(); } SettingsDialog::~SettingsDialog() { qDebug() << Q_FUNC_INFO; qDeleteAll(m_layouts); if (m_model) { delete m_model; } if (m_corona && m_corona->universalSettings()) { m_corona->universalSettings()->setLayoutsWindowSize(size()); QStringList columnWidths; columnWidths << QString::number(ui->layoutsView->columnWidth(COLORCOLUMN)); columnWidths << QString::number(ui->layoutsView->columnWidth(NAMECOLUMN)); columnWidths << QString::number(ui->layoutsView->columnWidth(MENUCOLUMN)); + columnWidths << QString::number(ui->layoutsView->columnWidth(BORDERSCOLUMN)); m_corona->universalSettings()->setLayoutsColumnWidths(columnWidths); } m_inMemoryButtons->deleteLater(); m_mouseSensitivityButtons->deleteLater(); foreach (auto tempDir, m_tempDirectories) { QDir tDir(tempDir); if (tDir.exists() && tempDir.startsWith("/tmp/")) { tDir.removeRecursively(); } } } void SettingsDialog::blockDeleteOnActivityStopped() { connect(m_corona->activitiesConsumer(), &KActivities::Consumer::runningActivitiesChanged, this, [&]() { m_blockDeleteOnReject = true; m_activityClosedTimer.start(); }); m_activityClosedTimer.setSingleShot(true); m_activityClosedTimer.setInterval(500); connect(&m_activityClosedTimer, &QTimer::timeout, this, [&]() { m_blockDeleteOnReject = false; }); } QStringList SettingsDialog::activities() { return m_corona->layoutManager()->activities(); } QStringList SettingsDialog::availableActivities() { return m_availableActivities; } void SettingsDialog::setCurrentPage(Dock::LatteConfigPage page) { if (page == Dock::LayoutPage) { ui->tabWidget->setCurrentIndex(0); } else if (page == Dock::PreferencesPage) { ui->tabWidget->setCurrentIndex(1); } } void SettingsDialog::on_newButton_clicked() { qDebug() << Q_FUNC_INFO; //! find Default preset path foreach (auto preset, m_corona->layoutManager()->presetsPaths()) { QString presetName = Layout::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 SettingsDialog::on_copyButton_clicked() { qDebug() << Q_FUNC_INFO; int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } //! Update original layout before copying if this layout is active if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { QString lName = (m_model->data(m_model->index(row, NAMECOLUMN), Qt::DisplayRole)).toString(); if (Importer::layoutExists(lName)) { Layout *layout = m_corona->layoutManager()->activeLayout(lName); if (layout && layout->isOriginalLayout()) { layout->syncToLayoutFile(); } } } 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 textColor = m_model->data(m_model->index(row, COLORCOLUMN), Qt::UserRole).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; + bool disabledBorders = m_model->data(m_model->index(row, BORDERSCOLUMN), Qt::DisplayRole).toString() == CheckMark; QString copiedId = tempDir + "/" + layoutName + ".layout.latte"; QFile(id).copy(copiedId); QFileInfo newFileInfo(copiedId); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(copiedId).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } Layout *settings = new Layout(this, copiedId); m_layouts[copiedId] = settings; - insertLayoutInfoAtRow(row + 1, copiedId, color, textColor, layoutName, menu, QStringList(), false); + insertLayoutInfoAtRow(row + 1, copiedId, color, textColor, layoutName, menu, disabledBorders, QStringList(), false); ui->layoutsView->selectRow(row + 1); } void SettingsDialog::on_downloadButton_clicked() { qDebug() << Q_FUNC_INFO; KNS3::DownloadDialog dialog(QStringLiteral("latte-layouts.knsrc"), this); dialog.resize(m_corona->universalSettings()->downloadWindowSize()); dialog.exec(); bool layoutAdded{false}; if (!dialog.changedEntries().isEmpty() || !dialog.installedEntries().isEmpty()) { foreach (auto entry, dialog.installedEntries()) { foreach (auto entryFile, entry.installedFiles()) { Importer::LatteFileVersion version = Importer::fileVersion(entryFile); if (version == Importer::LayoutVersion2) { layoutAdded = true; addLayoutForFile(entryFile); break; } } } } m_corona->universalSettings()->setDownloadWindowSize(dialog.size()); if (layoutAdded) { apply(); } } void SettingsDialog::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 (m_corona->layoutManager()->activeLayout(layoutName)) { return; } m_model->removeRow(row); updateApplyButtonsState(); row = qMax(row - 1, 0); ui->layoutsView->selectRow(row); } void SettingsDialog::on_lockedButton_clicked() { qDebug() << Q_FUNC_INFO; int row = ui->layoutsView->currentIndex().row(); if (row < 0) { return; } bool lockedModel = m_model->data(m_model->index(row, NAMECOLUMN), Qt::UserRole).toBool(); m_model->setData(m_model->index(row, NAMECOLUMN), QVariant(!lockedModel), Qt::UserRole); updatePerLayoutButtonsState(); updateApplyButtonsState(); } void SettingsDialog::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-full \"" + 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-full \"" + file + "\""); qGuiApp->exit(); } }); msg->open(); } }); fileDialog->open(); } bool SettingsDialog::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_corona->layoutManager()->importer()->importOldLayout(applets, name, false, tempDir.absolutePath())) { addLayoutForFile(tempDir.absolutePath() + "/" + name + ".layout.latte", name, false); } QString alternativeName = name + "-" + i18nc("layout", "Alternative"); if (m_corona->layoutManager()->importer()->importOldLayout(applets, alternativeName, false, tempDir.absolutePath())) { addLayoutForFile(tempDir.absolutePath() + "/" + alternativeName + ".layout.latte", alternativeName, false); } } return true; } return false; } void SettingsDialog::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(); //! Update ALL active original layouts before exporting, //! this is needed because the export method can export also the full configuration qDebug() << Q_FUNC_INFO; m_corona->layoutManager()->syncActiveLayoutsToOriginalFiles(); 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 configuration", "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; } QFileInfo newFileInfo(file); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(file).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } Layout layoutS(this, file); layoutS.setActivities(QStringList()); layoutS.clearLastUsedActivity(); //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_corona->layoutManager()->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 SettingsDialog::requestImagesDialog(int row) { QStringList mimeTypeFilters; mimeTypeFilters << "image/jpeg" // will show "JPEG image (*.jpeg *.jpg) << "image/png"; // will show "PNG image (*.png)" QFileDialog dialog(this); dialog.setMimeTypeFilters(mimeTypeFilters); QString background = m_model->data(m_model->index(row, COLORCOLUMN), Qt::BackgroundRole).toString(); if (background.startsWith("/")) { dialog.selectFile(background); } if (dialog.exec()) { QStringList files = dialog.selectedFiles(); if (files.count() > 0) { m_model->setData(m_model->index(row, COLORCOLUMN), files[0], Qt::BackgroundRole); } } } void SettingsDialog::requestColorsDialog(int row) { QColorDialog dialog(this); QString textColor = m_model->data(m_model->index(row, COLORCOLUMN), Qt::UserRole).toString(); dialog.setCurrentColor(QColor(textColor)); if (dialog.exec()) { qDebug() << dialog.selectedColor().name(); m_model->setData(m_model->index(row, COLORCOLUMN), dialog.selectedColor().name(), Qt::UserRole); } } void SettingsDialog::accept() { qDebug() << Q_FUNC_INFO; if (saveAllChanges()) { deleteLater(); } } void SettingsDialog::reject() { qDebug() << Q_FUNC_INFO; if (!m_blockDeleteOnReject) { deleteLater(); } } void SettingsDialog::apply() { qDebug() << Q_FUNC_INFO; saveAllChanges(); o_settings = currentSettings(); o_settingsLayouts = currentLayoutsSettings(); updateApplyButtonsState(); updatePerLayoutButtonsState(); } void SettingsDialog::restoreDefaults() { qDebug() << Q_FUNC_INFO; if (ui->tabWidget->currentIndex() == 0) { //! Default layouts missing from layouts list foreach (auto preset, m_corona->layoutManager()->presetsPaths()) { QString presetName = Layout::layoutName(preset); QByteArray presetNameChars = presetName.toUtf8(); const char *prset_str = presetNameChars.data(); presetName = i18n(prset_str); if (!nameExistsInModel(presetName)) { addLayoutForFile(preset, presetName); } } } else if (ui->tabWidget->currentIndex() == 1) { //! Defaults for general Latte settings ui->autostartChkBox->setChecked(true); ui->infoWindowChkBox->setChecked(true); ui->noBordersForMaximizedChkBox->setChecked(false); ui->highSensitivityBtn->setChecked(true); ui->screenTrackerSpinBox->setValue(SCREENTRACKERDEFAULTVALUE); } } void SettingsDialog::addLayoutForFile(QString file, QString layoutName, bool newTempDirectory, bool showNotification) { if (layoutName.isEmpty()) { layoutName = Layout::layoutName(file); } QString copiedId; if (newTempDirectory) { QString tempDir = uniqueTempDirectory(); copiedId = tempDir + "/" + layoutName + ".layout.latte"; QFile(file).copy(copiedId); } else { copiedId = file; } QFileInfo newFileInfo(copiedId); if (newFileInfo.exists() && !newFileInfo.isWritable()) { QFile(copiedId).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); } if (m_layouts.contains(copiedId)) { Layout *oldSettings = m_layouts.take(copiedId); delete oldSettings; } Layout *settings = new Layout(this, copiedId); m_layouts[copiedId] = settings; QString id = copiedId; QString color = settings->color(); QString textColor = settings->textColor(); QString background = settings->background(); bool menu = settings->showInMenu(); + bool disabledBorders = settings->disableBordersForMaximizedWindows(); bool locked = !settings->isWritable(); layoutName = uniqueLayoutName(layoutName); int row = ascendingRowFor(layoutName); if (background.isEmpty()) { - insertLayoutInfoAtRow(row, copiedId, color, QString(), layoutName, menu, QStringList(), locked); + insertLayoutInfoAtRow(row, copiedId, color, QString(), layoutName, menu, disabledBorders, QStringList(), locked); } else { - insertLayoutInfoAtRow(row, copiedId, background, textColor, layoutName, menu, QStringList(), locked); + insertLayoutInfoAtRow(row, copiedId, background, textColor, layoutName, menu, disabledBorders, QStringList(), locked); } 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
").arg(layoutName)); notification->sendEvent(); } } void SettingsDialog::loadSettings() { m_initLayoutPaths.clear(); m_model->clear(); int i = 0; QStringList brokenLayouts; if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { m_corona->layoutManager()->syncActiveLayoutsToOriginalFiles(); } foreach (auto layout, m_corona->layoutManager()->layouts()) { QString layoutPath = QDir::homePath() + "/.config/latte/" + layout + ".layout.latte"; m_initLayoutPaths.append(layoutPath); Layout *layoutSets = new Layout(this, layoutPath); m_layouts[layoutPath] = layoutSets; QString background = layoutSets->background(); if (background.isEmpty()) { insertLayoutInfoAtRow(i, layoutPath, layoutSets->color(), QString(), layoutSets->name(), - layoutSets->showInMenu(), layoutSets->activities(), !layoutSets->isWritable()); + layoutSets->showInMenu(), layoutSets->disableBordersForMaximizedWindows(), + layoutSets->activities(), !layoutSets->isWritable()); } else { insertLayoutInfoAtRow(i, layoutPath, background, layoutSets->textColor(), layoutSets->name(), - layoutSets->showInMenu(), layoutSets->activities(), !layoutSets->isWritable()); + layoutSets->showInMenu(), layoutSets->disableBordersForMaximizedWindows(), + layoutSets->activities(), !layoutSets->isWritable()); } qDebug() << "counter:" << i << " total:" << m_model->rowCount(); i++; if (layoutSets->name() == m_corona->layoutManager()->currentLayoutName()) { ui->layoutsView->selectRow(i - 1); } Layout *activeLayout = m_corona->layoutManager()->activeLayout(layoutSets->name()); if ((activeLayout && activeLayout->layoutIsBroken()) || (!activeLayout && layoutSets->layoutIsBroken())) { brokenLayouts.append(layoutSets->name()); } } recalculateAvailableActivities(); m_model->setHorizontalHeaderItem(IDCOLUMN, new QStandardItem(QString("#path"))); m_model->setHorizontalHeaderItem(COLORCOLUMN, new QStandardItem(QString(i18n("Background")))); m_model->setHorizontalHeaderItem(NAMECOLUMN, new QStandardItem(QString(i18n("Name")))); m_model->setHorizontalHeaderItem(MENUCOLUMN, new QStandardItem(QString(i18n("In Menu")))); + m_model->setHorizontalHeaderItem(BORDERSCOLUMN, new QStandardItem(QString(i18n("Borders")))); m_model->setHorizontalHeaderItem(ACTIVITYCOLUMN, new QStandardItem(QString(i18n("Activities")))); //! this line should be commented for debugging layouts window functionality ui->layoutsView->setColumnHidden(IDCOLUMN, true); ui->layoutsView->setColumnHidden(HIDDENTEXTCOLUMN, true); + if (m_corona->universalSettings()->canDisableBorders()) { + ui->layoutsView->setColumnHidden(BORDERSCOLUMN, false); + } else { + ui->layoutsView->setColumnHidden(BORDERSCOLUMN, true); + } + ui->layoutsView->resizeColumnsToContents(); QStringList columnWidths = m_corona->universalSettings()->layoutsColumnWidths(); - if (!columnWidths.isEmpty() && columnWidths.count() == 3) { + if (!columnWidths.isEmpty() && columnWidths.count() == 4) { ui->layoutsView->setColumnWidth(COLORCOLUMN, columnWidths[0].toInt()); ui->layoutsView->setColumnWidth(NAMECOLUMN, columnWidths[1].toInt()); ui->layoutsView->setColumnWidth(MENUCOLUMN, columnWidths[2].toInt()); + ui->layoutsView->setColumnWidth(BORDERSCOLUMN, columnWidths[3].toInt()); } if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { ui->singleToolBtn->setChecked(true); } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { ui->multipleToolBtn->setChecked(true); } updatePerLayoutButtonsState(); ui->autostartChkBox->setChecked(m_corona->universalSettings()->autostart()); ui->infoWindowChkBox->setChecked(m_corona->universalSettings()->showInfoWindow()); ui->noBordersForMaximizedChkBox->setChecked(m_corona->universalSettings()->canDisableBorders()); if (m_corona->universalSettings()->mouseSensitivity() == Dock::LowSensitivity) { ui->lowSensitivityBtn->setChecked(true); } else if (m_corona->universalSettings()->mouseSensitivity() == Dock::MediumSensitivity) { ui->mediumSensitivityBtn->setChecked(true); } else if (m_corona->universalSettings()->mouseSensitivity() == Dock::HighSensitivity) { ui->highSensitivityBtn->setChecked(true); } o_settings = currentSettings(); o_settingsLayouts = currentLayoutsSettings(); updateApplyButtonsState(); //! 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(); } } QList SettingsDialog::currentSettings() { QList settings; settings << m_inMemoryButtons->checkedId(); settings << (int)ui->autostartChkBox->isChecked(); settings << (int)ui->infoWindowChkBox->isChecked(); settings << (int)ui->noBordersForMaximizedChkBox->isChecked(); settings << m_mouseSensitivityButtons->checkedId(); settings << ui->screenTrackerSpinBox->value(); settings << m_model->rowCount(); return settings; } QStringList SettingsDialog::currentLayoutsSettings() { QStringList layoutSettings; 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 textColor = m_model->data(m_model->index(i, COLORCOLUMN), Qt::UserRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); bool menu = m_model->data(m_model->index(i, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; + bool borders = m_model->data(m_model->index(i, BORDERSCOLUMN), Qt::DisplayRole).toString() == CheckMark; QStringList lActivities = m_model->data(m_model->index(i, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); layoutSettings << id; layoutSettings << color; layoutSettings << textColor; layoutSettings << name; layoutSettings << QString::number((int)locked); layoutSettings << QString::number((int)menu); + layoutSettings << QString::number((int)borders); layoutSettings << lActivities; } return layoutSettings; } -void SettingsDialog::insertLayoutInfoAtRow(int row, QString path, QString color, QString textColor, QString name, bool menu, QStringList activities, bool locked) +void SettingsDialog::insertLayoutInfoAtRow(int row, QString path, QString color, QString textColor, QString name, bool menu, + bool disabledBorders, QStringList activities, bool locked) { QStandardItem *pathItem = new QStandardItem(path); QStandardItem *hiddenTextItem = new QStandardItem(); 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 *bordersItem = new QStandardItem(); + bordersItem->setEditable(false); + bordersItem->setSelectable(true); + bordersItem->setText(disabledBorders ? CheckMark : QString()); + bordersItem->setTextAlignment(Qt::AlignCenter); + QStandardItem *activitiesItem = new QStandardItem(activities.join(",")); QList items; items.append(pathItem); items.append(hiddenTextItem); items.append(colorItem); items.append(nameItem); items.append(menuItem); + items.append(bordersItem); 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); m_model->setData(m_model->index(row, COLORCOLUMN), textColor, Qt::UserRole); QFont font; if (m_corona->layoutManager()->activeLayout(name)) { 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, NAMECOLUMN), QVariant(locked), Qt::UserRole); m_model->setData(m_model->index(row, ACTIVITYCOLUMN), activities, Qt::UserRole); } void SettingsDialog::on_switchButton_clicked() { if (ui->buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) { //! thus there are changes in the settings QString lName; QStringList lActivities; if (m_inMemoryButtons->checkedId() == Latte::Dock::MultipleLayouts) { lName = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole).toString(); lActivities = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), ACTIVITYCOLUMN), Qt::UserRole).toStringList(); } apply(); if (!lName.isEmpty() && !lActivities.isEmpty()) { //! an activities-assigned layout is chosen and at the same time we are moving //! to multiple layouts state m_corona->layoutManager()->switchToLayout(lName); } } else { QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); if (value.isValid()) { m_corona->layoutManager()->switchToLayout(value.toString()); } else { qDebug() << "not valid layout"; } } updatePerLayoutButtonsState(); } void SettingsDialog::on_pauseButton_clicked() { ui->pauseButton->setEnabled(false); QString id = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), IDCOLUMN), Qt::DisplayRole).toString(); Layout *layout = m_layouts[id]; if (layout) { m_corona->layoutManager()->pauseLayout(layout->name()); } } void SettingsDialog::layoutsChanged() { 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()) { QString name = value.toString(); QFont font; if (m_corona->layoutManager()->currentLayoutName() == name) { font.setBold(true); // ui->layoutsView->selectRow(i); } else { Layout *layout = m_corona->layoutManager()->activeLayout(name); if (layout && (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts)) { font.setBold(true); } else { font.setBold(false); } } m_model->setData(nameIndex, font, Qt::FontRole); } } } void SettingsDialog::itemChanged(QStandardItem *item) { updatePerLayoutButtonsState(); if (item->column() == ACTIVITYCOLUMN) { //! recalculate the available activities recalculateAvailableActivities(); } else if (item->column() == NAMECOLUMN) { int currentRow = ui->layoutsView->currentIndex().row(); QString id = m_model->data(m_model->index(currentRow, IDCOLUMN), Qt::DisplayRole).toString(); QString name = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::DisplayRole).toString(); QFont font = qvariant_cast(m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::FontRole)); if (m_layouts[id]->name() != name) { font.setItalic(true); m_model->setData(m_model->index(currentRow, NAMECOLUMN), font, Qt::FontRole); } else { font.setItalic(false); m_model->setData(m_model->index(currentRow, NAMECOLUMN), font, Qt::FontRole); } } updateApplyButtonsState(); } void SettingsDialog::updateApplyButtonsState() { bool changed{false}; //! Ok, Apply Buttons if ((o_settings != currentSettings()) || (o_settingsLayouts != currentLayoutsSettings())) { changed = true; } if (changed) { ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); } else { ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); } //! RestoreDefaults Button if (ui->tabWidget->currentIndex() == 0) { //! Check Default layouts missing from layouts list bool layoutMissing{false}; foreach (auto preset, m_corona->layoutManager()->presetsPaths()) { QString presetName = Layout::layoutName(preset); QByteArray presetNameChars = presetName.toUtf8(); const char *prset_str = presetNameChars.data(); presetName = i18n(prset_str); if (!nameExistsInModel(presetName)) { layoutMissing = true; break; } } if (layoutMissing) { ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(true); } else { ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(false); } } else if (ui->tabWidget->currentIndex() == 1) { //! Defaults for general Latte settings if (!ui->autostartChkBox->isChecked() || !ui->infoWindowChkBox->isChecked() || ui->noBordersForMaximizedChkBox->isChecked() || !ui->highSensitivityBtn->isChecked() || ui->screenTrackerSpinBox->value() != SCREENTRACKERDEFAULTVALUE) { ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(true); } else { ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(false); } } } void SettingsDialog::updatePerLayoutButtonsState() { int currentRow = ui->layoutsView->currentIndex().row(); QString id = m_model->data(m_model->index(currentRow, IDCOLUMN), Qt::DisplayRole).toString(); QString nameInModel = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::DisplayRole).toString(); QString originalName = m_layouts.contains(id) ? m_layouts[id]->name() : ""; bool lockedInModel = m_model->data(m_model->index(currentRow, NAMECOLUMN), Qt::UserRole).toBool(); //! Switch Button if (id.startsWith("/tmp/") || originalName != nameInModel) { ui->switchButton->setEnabled(false); } else { ui->switchButton->setEnabled(true); } //! Pause Button if (m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) { ui->pauseButton->setVisible(false); } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { ui->pauseButton->setVisible(true); QStringList lActivities = m_model->data(m_model->index(currentRow, ACTIVITYCOLUMN), Qt::UserRole).toStringList(); Layout *layout = m_layouts[id]; if (!lActivities.isEmpty() && layout && m_corona->layoutManager()->activeLayout(layout->name())) { ui->pauseButton->setEnabled(true); } else { ui->pauseButton->setEnabled(false); } } //! Remove Layout Button if (originalName != nameInModel || (originalName == m_corona->layoutManager()->currentLayoutName()) || (m_corona->layoutManager()->activeLayout(originalName)) || lockedInModel) { ui->removeButton->setEnabled(false); } else { ui->removeButton->setEnabled(true); } if (lockedInModel) { ui->lockedButton->setChecked(true); } else { ui->lockedButton->setChecked(false); } } void SettingsDialog::recalculateAvailableActivities() { QStringList tempActivities = m_corona->layoutManager()->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 SettingsDialog::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 SettingsDialog::saveAllChanges() { if (!dataAreAccepted()) { return false; } //! Update universal settings Latte::Dock::MouseSensitivity sensitivity = static_cast(m_mouseSensitivityButtons->checkedId()); bool autostart = ui->autostartChkBox->isChecked(); bool showInfoWindow = ui->infoWindowChkBox->isChecked(); bool noBordersForMaximized = ui->noBordersForMaximizedChkBox->isChecked(); m_corona->universalSettings()->setMouseSensitivity(sensitivity); m_corona->universalSettings()->setAutostart(autostart); m_corona->universalSettings()->setShowInfoWindow(showInfoWindow); m_corona->universalSettings()->setCanDisableBorders(noBordersForMaximized); m_corona->universalSettings()->setScreenTrackerInterval(ui->screenTrackerSpinBox->value()); //! Update Layouts QStringList knownActivities = activities(); QTemporaryDir layoutTempDir; qDebug() << "Temporary Directory ::: " << layoutTempDir.path(); QStringList fromRenamePaths; QStringList toRenamePaths; QStringList toRenameNames; QString switchToLayout; QHash activeLayoutsToRename; //! remove layouts that have been removed from the user foreach (auto initLayout, m_initLayoutPaths) { if (!idExistsInModel(initLayout)) { QFile(initLayout).remove(); if (m_layouts.contains(initLayout)) { Layout *removedLayout = m_layouts.take(initLayout); delete removedLayout; } } } 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 textColor = m_model->data(m_model->index(i, COLORCOLUMN), Qt::UserRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); bool menu = m_model->data(m_model->index(i, MENUCOLUMN), Qt::DisplayRole).toString() == CheckMark; + bool disabledBorders = m_model->data(m_model->index(i, BORDERSCOLUMN), 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; Layout *activeLayout = m_corona->layoutManager()->activeLayout(m_layouts[id]->name()); Layout *layout = activeLayout ? activeLayout : m_layouts[id]; //! unlock read-only layout if (!layout->isWritable()) { layout->unlock(); } if (color.startsWith("/")) { //it is image file in such case if (color != layout->background()) { layout->setBackground(color); } if (layout->textColor() != textColor) { layout->setTextColor(textColor); } } else { if (color != layout->color()) { layout->setColor(color); layout->setBackground(QString()); layout->setTextColor(QString()); } } if (layout->showInMenu() != menu) { layout->setShowInMenu(menu); } + if (layout->disableBordersForMaximizedWindows() != disabledBorders) { + layout->setDisableBordersForMaximizedWindows(disabledBorders); + } + if (layout->activities() != cleanedActivities) { layout->setActivities(cleanedActivities); } //! If the layout name changed OR the layout path is a temporary one if (layout->name() != name || (id.startsWith("/tmp/"))) { //! If the layout is Active in MultipleLayouts if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts && activeLayout) { qDebug() << " Active Layout Should Be Renamed From : " << layout->name() << " TO :: " << name; activeLayoutsToRename[name] = layout; } QString tempFile = layoutTempDir.path() + "/" + QString(layout->name() + ".layout.latte"); qDebug() << "new temp file ::: " << tempFile; if ((m_corona->layoutManager()->memoryUsage() == Dock::SingleLayout) && (layout->name() == m_corona->layoutManager()->currentLayoutName())) { switchToLayout = name; } 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); Layout *nLayout = new Layout(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); } } } QString orphanedLayout; if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { foreach (auto newLayoutName, activeLayoutsToRename.keys()) { qDebug() << " Active Layout Is Renamed From : " << activeLayoutsToRename[newLayoutName]->name() << " TO :: " << newLayoutName; Layout *layout = activeLayoutsToRename[newLayoutName]; layout->renameLayout(newLayoutName); //! that means it is an active layout for orphaned Activities if (layout->activities().isEmpty()) { orphanedLayout = newLayoutName; } } } //! lock layouts in the end when the user has chosen it for (int i = 0; i < m_model->rowCount(); ++i) { QString id = m_model->data(m_model->index(i, IDCOLUMN), Qt::DisplayRole).toString(); QString name = m_model->data(m_model->index(i, NAMECOLUMN), Qt::DisplayRole).toString(); bool locked = m_model->data(m_model->index(i, NAMECOLUMN), Qt::UserRole).toBool(); Layout *activeLayout = m_corona->layoutManager()->activeLayout(m_layouts[id]->name()); Layout *layout = activeLayout ? activeLayout : m_layouts[id]; if (layout && locked && layout->isWritable()) { layout->lock(); } } m_corona->layoutManager()->loadLayouts(); Latte::Dock::LayoutsMemoryUsage inMemoryOption = static_cast(m_inMemoryButtons->checkedId()); if (m_corona->layoutManager()->memoryUsage() != inMemoryOption) { Dock::LayoutsMemoryUsage previousMemoryUsage = m_corona->layoutManager()->memoryUsage(); m_corona->layoutManager()->setMemoryUsage(inMemoryOption); QVariant value = m_model->data(m_model->index(ui->layoutsView->currentIndex().row(), NAMECOLUMN), Qt::DisplayRole); QString layoutName = value.toString(); m_corona->layoutManager()->switchToLayout(layoutName, previousMemoryUsage); } else { if (!switchToLayout.isEmpty()) { m_corona->layoutManager()->switchToLayout(switchToLayout); } else if (m_corona->layoutManager()->memoryUsage() == Dock::MultipleLayouts) { m_corona->layoutManager()->syncMultipleLayoutsToActivities(orphanedLayout); } } return true; } bool SettingsDialog::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 SettingsDialog::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 SettingsDialog::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 SettingsDialog::uniqueTempDirectory() { QTemporaryDir tempDir; tempDir.setAutoRemove(false); m_tempDirectories.append(tempDir.path()); return tempDir.path(); } QString SettingsDialog::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 diff --git a/app/settingsdialog.h b/app/settingsdialog.h index 272ec515..6095824e 100644 --- a/app/settingsdialog.h +++ b/app/settingsdialog.h @@ -1,134 +1,135 @@ /* * 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 . * */ #ifndef SETTINGSDIALOG_H #define SETTINGSDIALOG_H #include "../liblattedock/dock.h" #include #include #include #include #include #include namespace Ui { class SettingsDialog; } namespace KActivities { class Controller; } namespace Latte { class DockCorona; class Layout; } namespace Latte { class SettingsDialog : public QDialog { Q_OBJECT public: SettingsDialog(QWidget *parent, DockCorona *corona); ~SettingsDialog(); void setCurrentPage(Dock::LatteConfigPage page); QStringList activities(); QStringList availableActivities(); void requestImagesDialog(int row); void requestColorsDialog(int row); private slots: // auto connections void on_newButton_clicked(); void on_copyButton_clicked(); void on_downloadButton_clicked(); void on_lockedButton_clicked(); void on_pauseButton_clicked(); void on_removeButton_clicked(); void on_switchButton_clicked(); void on_importButton_clicked(); void on_exportButton_clicked(); void accept() override; void reject() override; void apply(); void restoreDefaults(); void updatePerLayoutButtonsState(); void layoutsChanged(); void itemChanged(QStandardItem *item); private: void addLayoutForFile(QString file, QString layoutName = QString(), bool newTempDirectory = true, bool showNotification = true); //! When an activity is closed for some reason the window manager hides and reshows //! the windows. This function prevents this because we dont want to delete the window //! on reject in such case. void blockDeleteOnActivityStopped(); void loadSettings(); void recalculateAvailableActivities(); - void insertLayoutInfoAtRow(int row, QString path, QString color, QString textColor, QString name, bool menu, QStringList activities, bool locked = false); + void insertLayoutInfoAtRow(int row, QString path, QString color, QString textColor, QString name, bool menu, bool disabledBorders, + QStringList activities, bool locked = false); void updateApplyButtonsState(); bool dataAreAccepted(); bool idExistsInModel(QString id); bool importLayoutsFromV1ConfigFile(QString file); bool nameExistsInModel(QString name); bool saveAllChanges(); int ascendingRowFor(QString name); QString uniqueTempDirectory(); QString uniqueLayoutName(QString name); QList currentSettings(); QStringList currentLayoutsSettings(); private: QStringList m_availableActivities; QStringList m_tempDirectories; QStringList m_initLayoutPaths; QButtonGroup *m_inMemoryButtons; QButtonGroup *m_mouseSensitivityButtons; QTimer m_activityClosedTimer; bool m_blockDeleteOnReject{false}; DockCorona *m_corona{nullptr}; QStandardItemModel *m_model{nullptr}; Ui::SettingsDialog *ui; QHash m_layouts; QList o_settings; QStringList o_settingsLayouts; }; } #endif // SETTINGSDIALOG_H