File indexing completed on 2024-04-21 05:30:50

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 }