File indexing completed on 2024-09-08 13:20:18
0001 /* 0002 * Copyright 2017 Smith AR <audoban@openmailbox.org> 0003 * Michail Vourlakos <mvourlakos@gmail.com> 0004 * 0005 * 2019 Michail Vourlakos <mvourlakos@gmail.com> 0006 * 0007 * This file is part of Latte-Dock 0008 * 0009 * Latte-Dock is free software; you can redistribute it and/or 0010 * modify it under the terms of the GNU General Public License as 0011 * published by the Free Software Foundation; either version 2 of 0012 * the License, or (at your option) any later version. 0013 * 0014 * Latte-Dock is distributed in the hope that it will be useful, 0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 * GNU General Public License for more details. 0018 * 0019 * You should have received a copy of the GNU General Public License 0020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #include "manager.h" 0024 0025 // local 0026 #include "importer.h" 0027 #include "launcherssignals.h" 0028 #include "../infoview.h" 0029 #include "../screenpool.h" 0030 #include "../layout/abstractlayout.h" 0031 #include "../layout/centrallayout.h" 0032 #include "../settings/settingsdialog.h" 0033 #include "../settings/universalsettings.h" 0034 0035 // Qt 0036 #include <QDir> 0037 #include <QFile> 0038 #include <QMessageBox> 0039 0040 // KDE 0041 #include <KLocalizedString> 0042 #include <KNotification> 0043 0044 namespace Latte { 0045 namespace Layouts { 0046 0047 const int MultipleLayoutsPresetId = 10; 0048 0049 Manager::Manager(QObject *parent) 0050 : QObject(parent), 0051 m_importer(new Importer(this)), 0052 m_launchersSignals(new LaunchersSignals(this)) 0053 { 0054 m_corona = qobject_cast<Latte::Corona *>(parent); 0055 //! needs to be created AFTER corona assignment 0056 m_synchronizer = new Synchronizer(this); 0057 0058 if (m_corona) { 0059 connect(m_corona->universalSettings(), &UniversalSettings::currentLayoutNameChanged, this, &Manager::currentLayoutNameChanged); 0060 0061 connect(m_synchronizer, &Synchronizer::centralLayoutsChanged, this, &Manager::centralLayoutsChanged); 0062 connect(m_synchronizer, &Synchronizer::currentLayoutNameChanged, this, &Manager::currentLayoutNameChanged); 0063 connect(m_synchronizer, &Synchronizer::currentLayoutIsSwitching, this, &Manager::currentLayoutIsSwitching); 0064 connect(m_synchronizer, &Synchronizer::layoutsChanged, this, &Manager::layoutsChanged); 0065 connect(m_synchronizer, &Synchronizer::menuLayoutsChanged, this, &Manager::menuLayoutsChanged); 0066 } 0067 } 0068 0069 Manager::~Manager() 0070 { 0071 m_importer->deleteLater(); 0072 m_launchersSignals->deleteLater(); 0073 0074 //! no needed because Latte:Corona is calling it at better place 0075 // unload(); 0076 0077 m_synchronizer->deleteLater(); 0078 } 0079 0080 void Manager::load() 0081 { 0082 m_presetsPaths.clear(); 0083 0084 QDir layoutsDir(QDir::homePath() + "/.config/latte"); 0085 bool firstRun = !layoutsDir.exists(); 0086 0087 int configVer = m_corona->universalSettings()->version(); 0088 qDebug() << "Universal Settings version : " << configVer; 0089 0090 if (firstRun) { 0091 m_corona->universalSettings()->setVersion(2); 0092 m_corona->universalSettings()->setCurrentLayoutName(i18n("My Layout")); 0093 0094 //startup create what is necessary.... 0095 if (!layoutsDir.exists()) { 0096 QDir(QDir::homePath() + "/.config").mkdir("latte"); 0097 } 0098 0099 newLayout(i18n("My Layout")); 0100 importPresets(false); 0101 } else if (configVer < 2 && !firstRun) { 0102 m_corona->universalSettings()->setVersion(2); 0103 0104 bool isOlderVersion = m_importer->updateOldConfiguration(); 0105 if (isOlderVersion) { 0106 qDebug() << "Latte is updating its older configuration..."; 0107 importPresets(false); 0108 } else { 0109 m_corona->universalSettings()->setCurrentLayoutName(i18n("My Layout")); 0110 } 0111 } 0112 0113 //! Check if the multiple-layouts hidden file is present, add it if it isnt 0114 if (!QFile(QDir::homePath() + "/.config/latte/" + Layout::AbstractLayout::MultipleLayoutsName + ".layout.latte").exists()) { 0115 importPreset(MultipleLayoutsPresetId, false); 0116 } 0117 0118 qDebug() << "Latte is loading its layouts..."; 0119 0120 m_presetsPaths.append(m_corona->kPackage().filePath("preset1")); 0121 m_presetsPaths.append(m_corona->kPackage().filePath("preset2")); 0122 m_presetsPaths.append(m_corona->kPackage().filePath("preset3")); 0123 m_presetsPaths.append(m_corona->kPackage().filePath("preset4")); 0124 0125 m_synchronizer->loadLayouts(); 0126 } 0127 0128 void Manager::unload() 0129 { 0130 m_synchronizer->unloadLayouts(); 0131 0132 //! Remove no-needed temp files 0133 QString temp1File = QDir::homePath() + "/.config/lattedock.copy1.bak"; 0134 QString temp2File = QDir::homePath() + "/.config/lattedock.copy2.bak"; 0135 0136 QFile file1(temp1File); 0137 QFile file2(temp2File); 0138 0139 if (file1.exists()) { 0140 file1.remove(); 0141 } 0142 0143 if (file2.exists()) { 0144 file2.remove(); 0145 } 0146 } 0147 0148 Latte::Corona *Manager::corona() 0149 { 0150 return m_corona; 0151 } 0152 0153 Importer *Manager::importer() 0154 { 0155 return m_importer; 0156 } 0157 0158 LaunchersSignals *Manager::launchersSignals() const 0159 { 0160 return m_launchersSignals; 0161 } 0162 0163 Synchronizer *Manager::synchronizer() const 0164 { 0165 return m_synchronizer; 0166 } 0167 0168 QString Manager::currentLayoutName() const 0169 { 0170 return m_synchronizer->currentLayoutName(); 0171 } 0172 0173 QString Manager::defaultLayoutName() const 0174 { 0175 QByteArray presetNameOrig = QString("preset" + QString::number(1)).toUtf8(); 0176 QString presetPath = m_corona->kPackage().filePath(presetNameOrig); 0177 QString presetName = CentralLayout::layoutName(presetPath); 0178 QByteArray presetNameChars = presetName.toUtf8(); 0179 presetName = i18n(presetNameChars); 0180 0181 return presetName; 0182 } 0183 0184 QStringList Manager::layouts() const 0185 { 0186 return m_synchronizer->layouts(); 0187 } 0188 0189 QStringList Manager::menuLayouts() const 0190 { 0191 return m_synchronizer->menuLayouts(); 0192 } 0193 0194 void Manager::setMenuLayouts(QStringList layouts) 0195 { 0196 m_synchronizer->setMenuLayouts(layouts); 0197 } 0198 0199 QStringList Manager::presetsPaths() const 0200 { 0201 return m_presetsPaths; 0202 } 0203 0204 Types::LayoutsMemoryUsage Manager::memoryUsage() const 0205 { 0206 return m_corona->universalSettings()->layoutsMemoryUsage(); 0207 } 0208 0209 int Manager::layoutsMemoryUsage() 0210 { 0211 return (int)m_corona->universalSettings()->layoutsMemoryUsage(); 0212 } 0213 0214 void Manager::setMemoryUsage(Types::LayoutsMemoryUsage memoryUsage) 0215 { 0216 m_corona->universalSettings()->setLayoutsMemoryUsage(memoryUsage); 0217 } 0218 0219 QStringList Manager::centralLayoutsNames() 0220 { 0221 return m_synchronizer->centralLayoutsNames(); 0222 } 0223 0224 QStringList Manager::sharedLayoutsNames() 0225 { 0226 return m_synchronizer->sharedLayoutsNames(); 0227 } 0228 0229 QStringList Manager::storedSharedLayouts() const 0230 { 0231 return m_synchronizer->storedSharedLayouts(); 0232 } 0233 0234 CentralLayout *Manager::currentLayout() const 0235 { 0236 return m_synchronizer->currentLayout(); 0237 } 0238 0239 bool Manager::switchToLayout(QString layoutName, int previousMemoryUsage) 0240 { 0241 return m_synchronizer->switchToLayout(layoutName, previousMemoryUsage); 0242 } 0243 0244 void Manager::loadLayoutOnStartup(QString layoutName) 0245 { 0246 QStringList layouts = m_importer->checkRepairMultipleLayoutsLinkedFile(); 0247 0248 //! Latte didn't close correctly, maybe a crash 0249 if (layouts.size() > 0) { 0250 QMessageBox *msg = new QMessageBox(); 0251 msg->setAttribute(Qt::WA_DeleteOnClose); 0252 msg->setIcon(QMessageBox::Warning); 0253 msg->setWindowTitle(i18n("Multiple Layouts Warning")); 0254 msg->setText(i18n("Latte did not close properly in the previous session. The following layout(s) <b>[%0]</b> were updated for consistency!!!").arg(layouts.join(","))); 0255 msg->setStandardButtons(QMessageBox::Ok); 0256 0257 msg->open(); 0258 } 0259 0260 m_synchronizer->switchToLayout(layoutName); 0261 } 0262 0263 void Manager::loadLatteLayout(QString layoutPath) 0264 { 0265 qDebug() << " -------------------------------------------------------------------- "; 0266 qDebug() << " -------------------------------------------------------------------- "; 0267 0268 if (m_corona->containments().size() > 0) { 0269 qDebug() << "LOAD LATTE LAYOUT ::: There are still containments present !!!! :: " << m_corona->containments().size(); 0270 } 0271 0272 if (!layoutPath.isEmpty() && m_corona->containments().size() == 0) { 0273 cleanupOnStartup(layoutPath); 0274 qDebug() << "LOADING CORONA LAYOUT:" << layoutPath; 0275 m_corona->loadLayout(layoutPath); 0276 } 0277 } 0278 0279 void Manager::cleanupOnStartup(QString path) 0280 { 0281 KSharedConfigPtr filePtr = KSharedConfig::openConfig(path); 0282 0283 KConfigGroup actionGroups = KConfigGroup(filePtr, "ActionPlugins"); 0284 0285 QStringList deprecatedActionGroup; 0286 0287 for (const auto &actId : actionGroups.groupList()) { 0288 QString pluginId = actionGroups.group(actId).readEntry("RightButton;NoModifier", ""); 0289 0290 if (pluginId == "org.kde.contextmenu") { 0291 deprecatedActionGroup << actId; 0292 } 0293 } 0294 0295 for (const auto &pId : deprecatedActionGroup) { 0296 qDebug() << "!!!!!!!!!!!!!!!! !!!!!!!!!!!! !!!!!!! REMOVING :::: " << pId; 0297 actionGroups.group(pId).deleteGroup(); 0298 } 0299 0300 KConfigGroup containmentGroups = KConfigGroup(filePtr, "Containments"); 0301 0302 QStringList removeContaimentsList; 0303 0304 for (const auto &cId : containmentGroups.groupList()) { 0305 QString pluginId = containmentGroups.group(cId).readEntry("plugin", ""); 0306 0307 if (pluginId == "org.kde.desktopcontainment") { //!must remove ghost containments first 0308 removeContaimentsList << cId; 0309 } 0310 } 0311 0312 for (const auto &cId : removeContaimentsList) { 0313 containmentGroups.group(cId).deleteGroup(); 0314 } 0315 0316 0317 actionGroups.sync(); 0318 containmentGroups.sync(); 0319 } 0320 0321 0322 void Manager::showAboutDialog() 0323 { 0324 m_corona->aboutApplication(); 0325 } 0326 0327 void Manager::clearUnloadedContainmentsFromLinkedFile(QStringList containmentsIds, bool bypassChecks) 0328 { 0329 if (!m_corona || (memoryUsage() == Types::SingleLayout && !bypassChecks)) { 0330 return; 0331 } 0332 0333 auto containments = m_corona->config()->group("Containments"); 0334 0335 for (const auto &conId : containmentsIds) { 0336 qDebug() << "unloads ::: " << conId; 0337 KConfigGroup containment = containments.group(conId); 0338 containment.deleteGroup(); 0339 } 0340 0341 containments.sync(); 0342 } 0343 0344 QString Manager::newLayout(QString layoutName, QString preset) 0345 { 0346 QDir layoutDir(QDir::homePath() + "/.config/latte"); 0347 QStringList filter; 0348 filter.append(QString(layoutName + "*.layout.latte")); 0349 QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks); 0350 0351 //! if the newLayout already exists provide a newName that doesn't 0352 if (files.count() >= 1) { 0353 int newCounter = files.count() + 1; 0354 0355 layoutName = layoutName + "-" + QString::number(newCounter); 0356 } 0357 0358 QString newLayoutPath = layoutDir.absolutePath() + "/" + layoutName + ".layout.latte"; 0359 0360 qDebug() << "adding layout : " << layoutName << " based on preset:" << preset; 0361 0362 if (preset == i18n("Default") && !QFile(newLayoutPath).exists()) { 0363 qDebug() << "adding layout : succeed"; 0364 QFile(m_corona->kPackage().filePath("preset1")).copy(newLayoutPath); 0365 } 0366 0367 return newLayoutPath; 0368 } 0369 0370 void Manager::importDefaultLayout(bool newInstanceIfPresent) 0371 { 0372 importPreset(1, newInstanceIfPresent); 0373 0374 if (newInstanceIfPresent) { 0375 m_synchronizer->loadLayouts(); 0376 } 0377 } 0378 0379 void Manager::importPresets(bool includeDefault) 0380 { 0381 int start = 1; 0382 0383 if (!includeDefault) { 0384 start = 2; 0385 } 0386 0387 for (int i = start; i <= 4; ++i) { 0388 importPreset(i, false); 0389 } 0390 } 0391 0392 void Manager::importPreset(int presetNo, bool newInstanceIfPresent) 0393 { 0394 QDir configDir(QDir::homePath() + "/.config"); 0395 0396 if (!QDir(configDir.absolutePath() + "/latte").exists()) { 0397 configDir.mkdir("latte"); 0398 } 0399 0400 QByteArray presetNameOrig = QString("preset" + QString::number(presetNo)).toUtf8(); 0401 QString presetPath = m_corona->kPackage().filePath(presetNameOrig); 0402 QString presetName = Layout::AbstractLayout::layoutName(presetPath); 0403 QByteArray presetNameChars = presetName.toUtf8(); 0404 presetName = i18n(presetNameChars); 0405 0406 //! hide the multiple layouts layout file from user 0407 presetName = (presetNo == MultipleLayoutsPresetId) ? "." + presetName : presetName; 0408 0409 QString newLayoutFile = ""; 0410 0411 if (newInstanceIfPresent) { 0412 newLayoutFile = QDir::homePath() + "/.config/latte/" + m_importer->uniqueLayoutName(presetName) + ".layout.latte"; 0413 } else { 0414 newLayoutFile = QDir::homePath() + "/.config/latte/" + presetName + ".layout.latte"; 0415 } 0416 0417 if (!QFile(newLayoutFile).exists()) { 0418 QFile(presetPath).copy(newLayoutFile); 0419 QFileInfo newFileInfo(newLayoutFile); 0420 0421 if (newFileInfo.exists() && !newFileInfo.isWritable()) { 0422 QFile(newLayoutFile).setPermissions(QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ReadGroup | QFileDevice::ReadOther); 0423 } 0424 } 0425 } 0426 0427 void Manager::showLatteSettingsDialog(int page) 0428 { 0429 bool created{false}; 0430 0431 if (!m_latteSettingsDialog) { 0432 m_latteSettingsDialog = new SettingsDialog(nullptr, m_corona); 0433 created = true; 0434 } 0435 m_latteSettingsDialog->show(); 0436 0437 if (m_latteSettingsDialog->isMinimized()) { 0438 m_latteSettingsDialog->showNormal(); 0439 } 0440 0441 if (!created) { 0442 Types::LatteConfigPage configPage = static_cast<Types::LatteConfigPage>(page); 0443 m_latteSettingsDialog->toggleCurrentPage(); 0444 } 0445 0446 m_latteSettingsDialog->activateWindow(); 0447 } 0448 0449 void Manager::hideLatteSettingsDialog() 0450 { 0451 if (m_latteSettingsDialog) { 0452 m_latteSettingsDialog->deleteLater(); 0453 m_latteSettingsDialog = nullptr; 0454 } 0455 } 0456 0457 void Manager::showInfoWindow(QString info, int duration, QStringList activities) 0458 { 0459 for (const auto screen : qGuiApp->screens()) { 0460 InfoView *infoView = new InfoView(m_corona, info, screen); 0461 0462 infoView->show(); 0463 infoView->setOnActivities(activities); 0464 0465 QTimer::singleShot(duration, [this, infoView]() { 0466 infoView->deleteLater(); 0467 }); 0468 } 0469 } 0470 0471 //! it is used just in order to provide translations for the presets 0472 void Manager::ghostForTranslatedPresets() 0473 { 0474 QString preset1 = i18n("Default"); 0475 QString preset2 = i18n("Plasma"); 0476 QString preset3 = i18n("Unity"); 0477 QString preset4 = i18n("Extended"); 0478 } 0479 0480 } 0481 }