File indexing completed on 2024-09-15 04:52:31
0001 /* 0002 SPDX-FileCopyrightText: 2017 Smith AR <audoban@openmailbox.org> 0003 SPDX-FileCopyrightText: 2019 Michail Vourlakos <mvourlakos@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "manager.h" 0009 0010 // local 0011 #include "importer.h" 0012 #include "syncedlaunchers.h" 0013 #include "../infoview.h" 0014 #include "../screenpool.h" 0015 #include "../data/layoutdata.h" 0016 #include "../data/generictable.h" 0017 #include "../layout/abstractlayout.h" 0018 #include "../layout/centrallayout.h" 0019 #include "../layouts/storage.h" 0020 #include "../settings/universalsettings.h" 0021 #include "../templates/templatesmanager.h" 0022 #include "../tools/commontools.h" 0023 0024 // Qt 0025 #include <QDir> 0026 #include <QFile> 0027 #include <QMessageBox> 0028 #include <QLatin1String> 0029 0030 // KDE 0031 #include <KMessageBox> 0032 #include <KLocalizedString> 0033 #include <KNotification> 0034 0035 namespace Latte { 0036 namespace Layouts { 0037 0038 Manager::Manager(QObject *parent) 0039 : QObject(parent), 0040 m_importer(new Importer(this)), 0041 m_syncedLaunchers(new SyncedLaunchers(this)) 0042 { 0043 m_corona = qobject_cast<Latte::Corona *>(parent); 0044 //! needs to be created AFTER corona assignment 0045 m_synchronizer = new Synchronizer(this); 0046 0047 if (m_corona) { 0048 connect(m_synchronizer, &Synchronizer::centralLayoutsChanged, this, &Manager::centralLayoutsChanged); 0049 connect(m_synchronizer, &Synchronizer::currentLayoutIsSwitching, this, &Manager::currentLayoutIsSwitching); 0050 } 0051 } 0052 0053 Manager::~Manager() 0054 { 0055 if (memoryUsage() == Latte::MemoryUsage::MultipleLayouts) { 0056 m_importer->setMultipleLayoutsStatus(Latte::MultipleLayouts::Paused); 0057 } 0058 0059 m_importer->deleteLater(); 0060 m_syncedLaunchers->deleteLater(); 0061 0062 //! no needed because Latte:Corona is calling it at better place 0063 // unload(); 0064 0065 m_synchronizer->deleteLater(); 0066 } 0067 0068 void Manager::init() 0069 { 0070 QDir layoutsDir(Layouts::Importer::layoutUserDir()); 0071 bool firstRun = !layoutsDir.exists(); 0072 0073 int configVer = m_corona->universalSettings()->version(); 0074 qDebug() << "Universal Settings version : " << configVer; 0075 0076 if (firstRun) { 0077 m_corona->universalSettings()->setVersion(2); 0078 m_corona->universalSettings()->setSingleModeLayoutName(i18n("My Layout")); 0079 0080 //startup create what is necessary.... 0081 if (!layoutsDir.exists()) { 0082 QDir(Latte::configPath()).mkdir("latte"); 0083 } 0084 0085 QString defpath = m_corona->templatesManager()->newLayout(i18n("My Layout"), i18n(Templates::DEFAULTLAYOUTTEMPLATENAME)); 0086 setOnAllActivities(Layout::AbstractLayout::layoutName(defpath)); 0087 0088 m_corona->templatesManager()->importSystemLayouts(); 0089 } else if (configVer < 2 && !firstRun) { 0090 m_corona->universalSettings()->setVersion(2); 0091 0092 bool isOlderVersion = m_importer->updateOldConfiguration(); 0093 if (isOlderVersion) { 0094 qDebug() << "Latte is updating its older configuration..."; 0095 m_corona->templatesManager()->importSystemLayouts(); 0096 } else { 0097 m_corona->universalSettings()->setSingleModeLayoutName(i18n("My Layout")); 0098 } 0099 } 0100 0101 //! Custom Templates path creation 0102 QDir localTemplatesDir(Latte::configPath() + "/latte/templates"); 0103 0104 if (!localTemplatesDir.exists()) { 0105 QDir(Latte::configPath() + "/latte").mkdir("templates"); 0106 } 0107 0108 //! Check if the multiple-layouts hidden file is present, add it if it isnt 0109 if (!QFile(Layouts::Importer::layoutUserFilePath(Layout::MULTIPLELAYOUTSHIDDENNAME)).exists()) { 0110 m_corona->templatesManager()->newLayout("", Layout::MULTIPLELAYOUTSHIDDENNAME); 0111 } 0112 0113 qDebug() << "Latte is loading its layouts..."; 0114 0115 m_synchronizer->initLayouts(); 0116 } 0117 0118 void Manager::unload() 0119 { 0120 m_synchronizer->unloadLayouts(); 0121 } 0122 0123 Latte::Corona *Manager::corona() 0124 { 0125 return m_corona; 0126 } 0127 0128 Importer *Manager::importer() 0129 { 0130 return m_importer; 0131 } 0132 0133 SyncedLaunchers *Manager::syncedLaunchers() const 0134 { 0135 return m_syncedLaunchers; 0136 } 0137 0138 Synchronizer *Manager::synchronizer() const 0139 { 0140 return m_synchronizer; 0141 } 0142 0143 MemoryUsage::LayoutsMemory Manager::memoryUsage() const 0144 { 0145 return m_corona->universalSettings()->layoutsMemoryUsage(); 0146 } 0147 0148 void Manager::setMemoryUsage(MemoryUsage::LayoutsMemory memoryUsage) 0149 { 0150 m_corona->universalSettings()->setLayoutsMemoryUsage(memoryUsage); 0151 } 0152 0153 QStringList Manager::centralLayoutsNames() 0154 { 0155 return m_synchronizer->centralLayoutsNames(); 0156 } 0157 0158 QStringList Manager::currentLayoutsNames() const 0159 { 0160 return m_synchronizer->currentLayoutsNames(); 0161 } 0162 0163 QStringList Manager::viewTemplateNames() const 0164 { 0165 Latte::Data::GenericTable<Data::Generic> viewtemplates = m_corona->templatesManager()->viewTemplates(); 0166 0167 QStringList names; 0168 0169 for(int i=0; i<viewtemplates.rowCount(); ++i) { 0170 names << viewtemplates[i].name; 0171 } 0172 0173 return names; 0174 } 0175 0176 QStringList Manager::viewTemplateIds() const 0177 { 0178 Latte::Data::GenericTable<Data::Generic> viewtemplates = m_corona->templatesManager()->viewTemplates(); 0179 0180 QStringList ids; 0181 0182 for(int i=0; i<viewtemplates.rowCount(); ++i) { 0183 ids << viewtemplates[i].id; 0184 } 0185 0186 return ids; 0187 } 0188 0189 Latte::Data::LayoutIcon Manager::iconForLayout(const QString &storedLayoutName) const 0190 { 0191 Data::Layout l = m_synchronizer->data(storedLayoutName); 0192 return iconForLayout(l); 0193 } 0194 0195 Latte::Data::LayoutIcon Manager::iconForLayout(const Data::Layout &layout) const 0196 { 0197 Latte::Data::LayoutIcon _icon; 0198 0199 if (!layout.icon.isEmpty()) { 0200 //! if there is specific icon set from the user for this layout we draw only that icon 0201 _icon.name = layout.icon; 0202 _icon.isBackgroundFile = false; 0203 return _icon; 0204 } 0205 0206 //! fallback icon: background image 0207 if (_icon.isEmpty()) { 0208 QString colorPath = m_corona->kPackage().path() + "../../shells/org.kde.latte.shell/contents/images/canvas/"; 0209 0210 if (layout.backgroundStyle == Layout::PatternBackgroundStyle && layout.background.isEmpty()) { 0211 colorPath += "defaultcustomprint.jpg"; 0212 } else { 0213 colorPath = layout.background.startsWith("/") ? layout.background : colorPath + layout.color + "print.jpg"; 0214 } 0215 0216 if (QFileInfo(colorPath).exists()) { 0217 _icon.isBackgroundFile = true; 0218 _icon.name = colorPath; 0219 return _icon; 0220 } 0221 } 0222 0223 return Latte::Data::LayoutIcon(); 0224 } 0225 0226 QList<CentralLayout *> Manager::currentLayouts() const 0227 { 0228 return m_synchronizer->currentLayouts(); 0229 } 0230 0231 bool Manager::switchToLayout(QString layoutName, MemoryUsage::LayoutsMemory newMemoryUsage) 0232 { 0233 return m_synchronizer->switchToLayout(layoutName, newMemoryUsage); 0234 } 0235 0236 void Manager::loadLayoutOnStartup(QString layoutName) 0237 { 0238 /* QStringList layouts = m_importer->checkRepairMultipleLayoutsLinkedFile(); 0239 0240 //! Latte didn't close correctly, maybe a crash 0241 if (layouts.size() > 0) { 0242 QDialog* dialog = new QDialog(nullptr); 0243 dialog->setWindowTitle(i18n("Multiple Layouts Startup Warning")); 0244 dialog->setObjectName("sorry"); 0245 dialog->setAttribute(Qt::WA_DeleteOnClose); 0246 0247 auto buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok); 0248 0249 KMessageBox::createKMessageBox(dialog, 0250 buttonbox, 0251 QMessageBox::Warning, 0252 i18np("<b>Multiple Layouts based on Activities</b> mode did not close properly during the last session.<br/><br/>The following layout <b>[ %2 ]</b> had to be updated for consistency!", 0253 "<b>Multiple Layouts based on Activities</b> mode did not close properly during the last session.<br/><br/>The following layouts <b>[ %2 ]</b> had to be updated for consistency!", 0254 layouts.count(), 0255 layouts.join(", ")), 0256 QStringList(), 0257 QString(), 0258 0, 0259 KMessageBox::NoExec, 0260 QString()); 0261 dialog->show(); 0262 }*/ 0263 0264 m_synchronizer->switchToLayout(layoutName); 0265 } 0266 0267 void Manager::moveView(QString originLayoutName, uint originViewId, QString destinationLayoutName) 0268 { 0269 if (memoryUsage() != Latte::MemoryUsage::MultipleLayouts 0270 || originLayoutName.isEmpty() 0271 || destinationLayoutName.isEmpty() 0272 || originViewId <= 0 0273 || originLayoutName == destinationLayoutName) { 0274 return; 0275 } 0276 0277 auto originlayout = m_synchronizer->layout(originLayoutName); 0278 auto destinationlayout = m_synchronizer->layout(destinationLayoutName); 0279 0280 if (!originlayout || !destinationlayout || originlayout == destinationlayout) { 0281 return; 0282 } 0283 0284 Plasma::Containment *originviewcontainment = originlayout->containmentForId(originViewId); 0285 Latte::View *originview = originlayout->viewForContainment(originViewId); 0286 0287 if (!originviewcontainment) { 0288 return; 0289 } 0290 0291 QList<Plasma::Containment *> origincontainments = originlayout->unassignFromLayout(originviewcontainment); 0292 0293 if (origincontainments.size() > 0) { 0294 destinationlayout->assignToLayout(originview, origincontainments); 0295 } 0296 } 0297 0298 void Manager::loadLatteLayout(QString layoutPath) 0299 { 0300 qDebug() << " -------------------------------------------------------------------- "; 0301 qDebug() << " -------------------------------------------------------------------- "; 0302 0303 if (m_corona->containments().size() > 0) { 0304 qDebug() << "LOAD LATTE LAYOUT ::: There are still containments present !!!! :: " << m_corona->containments().size(); 0305 } 0306 0307 if (!layoutPath.isEmpty() && m_corona->containments().size() == 0) { 0308 cleanupOnStartup(layoutPath); 0309 qDebug() << "LOADING CORONA LAYOUT:" << layoutPath; 0310 m_corona->loadLayout(layoutPath); 0311 } 0312 } 0313 0314 void Manager::setOnAllActivities(QString layoutName) 0315 { 0316 CentralLayout *central = m_synchronizer->centralLayout(layoutName); 0317 0318 if (central) { 0319 central->setActivities(QStringList(Data::Layout::ALLACTIVITIESID)); 0320 } else if (m_importer->layoutExists(layoutName)) { 0321 CentralLayout storage(this, m_importer->layoutUserFilePath(layoutName)); 0322 storage.setActivities(QStringList(Data::Layout::ALLACTIVITIESID)); 0323 } 0324 } 0325 0326 void Manager::setOnActivities(QString layoutName, QStringList activities) 0327 { 0328 CentralLayout *central = m_synchronizer->centralLayout(layoutName); 0329 0330 if (central) { 0331 central->setActivities(activities); 0332 } else if (m_importer->layoutExists(layoutName)) { 0333 CentralLayout storage(this, m_importer->layoutUserFilePath(layoutName)); 0334 storage.setActivities(activities); 0335 } 0336 } 0337 0338 void Manager::cleanupOnStartup(QString path) 0339 { 0340 Layouts::Storage::self()->removeAllClonedViews(path); 0341 0342 KSharedConfigPtr filePtr = KSharedConfig::openConfig(path); 0343 0344 KConfigGroup actionGroups = KConfigGroup(filePtr, "ActionPlugins"); 0345 0346 QStringList deprecatedActionGroup; 0347 0348 for (const auto &actId : actionGroups.groupList()) { 0349 QString pluginId = actionGroups.group(actId).readEntry("RightButton;NoModifier", ""); 0350 0351 if (pluginId == QStringLiteral("org.kde.contextmenu")) { 0352 deprecatedActionGroup << actId; 0353 } 0354 } 0355 0356 for (const auto &pId : deprecatedActionGroup) { 0357 qDebug() << "!!!!!!!!!!!!!!!! !!!!!!!!!!!! !!!!!!! REMOVING :::: " << pId; 0358 actionGroups.group(pId).deleteGroup(); 0359 } 0360 0361 KConfigGroup containmentGroups = KConfigGroup(filePtr, "Containments"); 0362 0363 QStringList removeContaimentsList; 0364 0365 for (const auto &cId : containmentGroups.groupList()) { 0366 QString pluginId = containmentGroups.group(cId).readEntry("plugin", ""); 0367 0368 if (pluginId == QStringLiteral("org.kde.desktopcontainment")) { //!must remove ghost containments first 0369 removeContaimentsList << cId; 0370 } 0371 } 0372 0373 for (const auto &cId : removeContaimentsList) { 0374 containmentGroups.group(cId).deleteGroup(); 0375 } 0376 } 0377 0378 0379 void Manager::showAboutDialog() 0380 { 0381 m_corona->aboutApplication(); 0382 } 0383 0384 void Manager::clearUnloadedContainmentsFromLinkedFile(QStringList containmentsIds, bool bypassChecks) 0385 { 0386 if (!m_corona || (memoryUsage() == MemoryUsage::SingleLayout && !bypassChecks)) { 0387 return; 0388 } 0389 0390 auto containments = m_corona->config()->group("Containments"); 0391 0392 for (const auto &conId : containmentsIds) { 0393 qDebug() << "unloads ::: " << conId; 0394 KConfigGroup containment = containments.group(conId); 0395 containment.deleteGroup(); 0396 containment.sync(); 0397 } 0398 0399 containments.sync(); 0400 } 0401 0402 void Manager::showLatteSettingsDialog(int firstPage, bool toggleCurrentPage) 0403 { 0404 if (!m_latteSettingsDialog) { 0405 m_latteSettingsDialog = new Latte::Settings::Dialog::SettingsDialog(nullptr, m_corona); 0406 } 0407 m_latteSettingsDialog->show(); 0408 0409 if (m_latteSettingsDialog->isMinimized()) { 0410 m_latteSettingsDialog->showNormal(); 0411 } 0412 0413 if (toggleCurrentPage) { 0414 m_latteSettingsDialog->toggleCurrentPage(); 0415 } else { 0416 m_latteSettingsDialog->setCurrentPage(firstPage); 0417 } 0418 0419 m_latteSettingsDialog->activateWindow(); 0420 } 0421 0422 void Manager::hideLatteSettingsDialog() 0423 { 0424 if (m_latteSettingsDialog) { 0425 m_latteSettingsDialog->deleteLater(); 0426 m_latteSettingsDialog = nullptr; 0427 } 0428 } 0429 0430 void Manager::showInfoWindow(QString info, int duration, QStringList activities) 0431 { 0432 for (const auto screen : qGuiApp->screens()) { 0433 InfoView *infoView = new InfoView(m_corona, info, screen); 0434 0435 infoView->show(); 0436 infoView->setOnActivities(activities); 0437 0438 QTimer::singleShot(duration, [this, infoView]() { 0439 infoView->deleteLater(); 0440 }); 0441 } 0442 } 0443 0444 } 0445 }