File indexing completed on 2025-04-13 11:09:12
0001 /* 0002 SPDX-FileCopyrightText: 2019 Michail Vourlakos <mvourlakos@gmail.com> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "containmentinterface.h" 0007 0008 // local 0009 #include "view.h" 0010 #include "../lattecorona.h" 0011 #include "../layout/genericlayout.h" 0012 #include "../layouts/importer.h" 0013 #include "../layouts/storage.h" 0014 #include "../settings/universalsettings.h" 0015 0016 // Qt 0017 #include <QDebug> 0018 #include <QDir> 0019 #include <QLatin1String> 0020 0021 // Plasma 0022 #include <Plasma/Applet> 0023 #include <Plasma/Containment> 0024 #include <PlasmaQuick/AppletQuickItem> 0025 0026 // KDE 0027 #include <KDesktopFile> 0028 #include <KLocalizedString> 0029 #include <KPluginMetaData> 0030 #include <KDeclarative/ConfigPropertyMap> 0031 0032 namespace Latte { 0033 namespace ViewPart { 0034 0035 ContainmentInterface::ContainmentInterface(Latte::View *parent) 0036 : QObject(parent), 0037 m_view(parent) 0038 { 0039 m_corona = qobject_cast<Latte::Corona *>(m_view->corona()); 0040 0041 m_latteTasksModel = new TasksModel(this); 0042 m_plasmaTasksModel = new TasksModel(this); 0043 0044 m_appletsExpandedConnectionsTimer.setInterval(2000); 0045 m_appletsExpandedConnectionsTimer.setSingleShot(true); 0046 0047 m_appletDelayedConfigurationTimer.setInterval(1000); 0048 m_appletDelayedConfigurationTimer.setSingleShot(true); 0049 connect(&m_appletDelayedConfigurationTimer, &QTimer::timeout, this, &ContainmentInterface::updateAppletDelayedConfiguration); 0050 0051 connect(&m_appletsExpandedConnectionsTimer, &QTimer::timeout, this, &ContainmentInterface::updateAppletsTracking); 0052 0053 connect(m_view, &View::containmentChanged 0054 , this, [&]() { 0055 if (m_view->containment()) { 0056 connect(m_view->containment(), &Plasma::Containment::appletAdded, this, &ContainmentInterface::onAppletAdded); 0057 m_appletsExpandedConnectionsTimer.start(); 0058 } 0059 }); 0060 0061 connect(m_latteTasksModel, &TasksModel::countChanged, this, &ContainmentInterface::onLatteTasksCountChanged); 0062 connect(m_plasmaTasksModel, &TasksModel::countChanged, this, &ContainmentInterface::onPlasmaTasksCountChanged); 0063 } 0064 0065 ContainmentInterface::~ContainmentInterface() 0066 { 0067 } 0068 0069 void ContainmentInterface::identifyShortcutsHost() 0070 { 0071 if (m_shortcutsHost) { 0072 return; 0073 } 0074 0075 if (QQuickItem *graphicItem = m_view->containment()->property("_plasma_graphicObject").value<QQuickItem *>()) { 0076 const auto &childItems = graphicItem->childItems(); 0077 0078 for (QQuickItem *item : childItems) { 0079 if (item->objectName() == QLatin1String("containmentViewLayout")) { 0080 for (QQuickItem *subitem : item->childItems()) { 0081 if (subitem->objectName() == QLatin1String("PositionShortcutsAbilityHost")) { 0082 m_shortcutsHost = subitem; 0083 identifyMethods(); 0084 return; 0085 } 0086 } 0087 } 0088 } 0089 } 0090 } 0091 0092 void ContainmentInterface::identifyMethods() 0093 { 0094 int aeIndex = m_shortcutsHost->metaObject()->indexOfMethod("activateEntryAtIndex(QVariant)"); 0095 int niIndex = m_shortcutsHost->metaObject()->indexOfMethod("newInstanceForEntryAtIndex(QVariant)"); 0096 int sbIndex = m_shortcutsHost->metaObject()->indexOfMethod("setShowAppletShortcutBadges(QVariant,QVariant,QVariant,QVariant)"); 0097 int afiIndex = m_shortcutsHost->metaObject()->indexOfMethod("appletIdForIndex(QVariant)"); 0098 0099 m_activateEntryMethod = m_shortcutsHost->metaObject()->method(aeIndex); 0100 m_appletIdForIndexMethod = m_shortcutsHost->metaObject()->method(afiIndex); 0101 m_newInstanceMethod = m_shortcutsHost->metaObject()->method(niIndex); 0102 m_showShortcutsMethod = m_shortcutsHost->metaObject()->method(sbIndex); 0103 } 0104 0105 bool ContainmentInterface::applicationLauncherHasGlobalShortcut() const 0106 { 0107 if (!containsApplicationLauncher()) { 0108 return false; 0109 } 0110 0111 uint launcherAppletId = applicationLauncherId(); 0112 0113 const auto applets = m_view->containment()->applets(); 0114 0115 for (auto applet : applets) { 0116 if (applet->id() == launcherAppletId) { 0117 return !applet->globalShortcut().isEmpty(); 0118 } 0119 } 0120 0121 return false; 0122 } 0123 0124 bool ContainmentInterface::applicationLauncherInPopup() const 0125 { 0126 if (!containsApplicationLauncher()) { 0127 return false; 0128 } 0129 0130 uint launcherAppletId = applicationLauncherId(); 0131 const auto applets = m_view->containment()->applets(); 0132 0133 PlasmaQuick::AppletQuickItem *appLauncherItem{nullptr}; 0134 0135 for (auto applet : applets) { 0136 if (applet->id() == launcherAppletId) { 0137 appLauncherItem = applet->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0138 } 0139 } 0140 0141 return appLauncherItem && appletIsExpandable(appLauncherItem); 0142 } 0143 0144 bool ContainmentInterface::containsApplicationLauncher() const 0145 { 0146 return (applicationLauncherId() >= 0); 0147 } 0148 0149 bool ContainmentInterface::isCapableToShowShortcutBadges() 0150 { 0151 identifyShortcutsHost(); 0152 0153 if (!hasLatteTasks() && hasPlasmaTasks()) { 0154 return false; 0155 } 0156 0157 return m_showShortcutsMethod.isValid(); 0158 } 0159 0160 bool ContainmentInterface::isApplication(const QUrl &url) const 0161 { 0162 if (!url.isValid() || !url.isLocalFile()) { 0163 return false; 0164 } 0165 0166 const QString &localPath = url.toLocalFile(); 0167 0168 if (!KDesktopFile::isDesktopFile(localPath)) { 0169 return false; 0170 } 0171 0172 KDesktopFile desktopFile(localPath); 0173 return desktopFile.hasApplicationType(); 0174 } 0175 0176 int ContainmentInterface::applicationLauncherId() const 0177 { 0178 const auto applets = m_view->containment()->applets(); 0179 0180 auto launcherId{-1}; 0181 0182 for (auto applet : applets) { 0183 const auto provides = applet->kPackage().metadata().value(QStringLiteral("X-Plasma-Provides")); 0184 0185 if (provides.contains(QLatin1String("org.kde.plasma.launchermenu"))) { 0186 if (!applet->globalShortcut().isEmpty()) { 0187 return applet->id(); 0188 } else if (launcherId == -1) { 0189 launcherId = applet->id(); 0190 } 0191 } 0192 } 0193 0194 return launcherId; 0195 } 0196 0197 bool ContainmentInterface::updateBadgeForLatteTask(const QString identifier, const QString value) 0198 { 0199 if (!hasLatteTasks()) { 0200 return false; 0201 } 0202 0203 const auto &applets = m_view->containment()->applets(); 0204 0205 for (auto *applet : applets) { 0206 KPluginMetaData meta = applet->kPackage().metadata(); 0207 0208 if (meta.pluginId() == QLatin1String("org.kde.latte.plasmoid")) { 0209 0210 if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value<QQuickItem *>()) { 0211 const auto &childItems = appletInterface->childItems(); 0212 0213 if (childItems.isEmpty()) { 0214 continue; 0215 } 0216 0217 for (QQuickItem *item : childItems) { 0218 if (auto *metaObject = item->metaObject()) { 0219 // not using QMetaObject::invokeMethod to avoid warnings when calling 0220 // this on applets that don't have it or other child items since this 0221 // is pretty much trial and error. 0222 // Also, "var" arguments are treated as QVariant in QMetaObject 0223 0224 int methodIndex = metaObject->indexOfMethod("updateBadge(QVariant,QVariant)"); 0225 0226 if (methodIndex == -1) { 0227 continue; 0228 } 0229 0230 QMetaMethod method = metaObject->method(methodIndex); 0231 0232 if (method.invoke(item, Q_ARG(QVariant, identifier), Q_ARG(QVariant, value))) { 0233 return true; 0234 } 0235 } 0236 } 0237 } 0238 } 0239 } 0240 0241 return false; 0242 } 0243 0244 bool ContainmentInterface::activatePlasmaTask(const int index) 0245 { 0246 bool containsPlasmaTaskManager{hasPlasmaTasks() && !hasLatteTasks()}; 0247 0248 if (!containsPlasmaTaskManager) { 0249 return false; 0250 } 0251 0252 const auto &applets = m_view->containment()->applets(); 0253 0254 for (auto *applet : applets) { 0255 const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); 0256 0257 if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { 0258 if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value<QQuickItem *>()) { 0259 const auto &childItems = appletInterface->childItems(); 0260 0261 if (childItems.isEmpty()) { 0262 continue; 0263 } 0264 0265 KPluginMetaData meta = applet->kPackage().metadata(); 0266 0267 for (QQuickItem *item : childItems) { 0268 if (auto *metaObject = item->metaObject()) { 0269 int methodIndex{metaObject->indexOfMethod("activateTaskAtIndex(QVariant)")}; 0270 0271 if (methodIndex == -1) { 0272 continue; 0273 } 0274 0275 QMetaMethod method = metaObject->method(methodIndex); 0276 0277 if (method.invoke(item, Q_ARG(QVariant, index - 1))) { 0278 showShortcutBadges(false, true); 0279 0280 return true; 0281 } 0282 } 0283 } 0284 } 0285 } 0286 } 0287 0288 return false; 0289 } 0290 0291 bool ContainmentInterface::newInstanceForPlasmaTask(const int index) 0292 { 0293 bool containsPlasmaTaskManager{hasPlasmaTasks() && !hasLatteTasks()}; 0294 0295 if (!containsPlasmaTaskManager) { 0296 return false; 0297 } 0298 0299 const auto &applets = m_view->containment()->applets(); 0300 0301 for (auto *applet : applets) { 0302 const auto &provides = KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")); 0303 0304 if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { 0305 if (QQuickItem *appletInterface = applet->property("_plasma_graphicObject").value<QQuickItem *>()) { 0306 const auto &childItems = appletInterface->childItems(); 0307 0308 if (childItems.isEmpty()) { 0309 continue; 0310 } 0311 0312 KPluginMetaData meta = applet->kPackage().metadata(); 0313 0314 for (QQuickItem *item : childItems) { 0315 if (auto *metaObject = item->metaObject()) { 0316 int methodIndex{metaObject->indexOfMethod("newInstanceForTaskAtIndex(QVariant)")}; 0317 0318 if (methodIndex == -1) { 0319 continue; 0320 } 0321 0322 QMetaMethod method = metaObject->method(methodIndex); 0323 0324 if (method.invoke(item, Q_ARG(QVariant, index - 1))) { 0325 showShortcutBadges(false, true); 0326 0327 return true; 0328 } 0329 } 0330 } 0331 } 0332 } 0333 } 0334 0335 return false; 0336 } 0337 0338 bool ContainmentInterface::activateEntry(const int index) 0339 { 0340 identifyShortcutsHost(); 0341 0342 if (!m_activateEntryMethod.isValid()) { 0343 return false; 0344 } 0345 0346 return m_activateEntryMethod.invoke(m_shortcutsHost, Q_ARG(QVariant, index)); 0347 } 0348 0349 bool ContainmentInterface::newInstanceForEntry(const int index) 0350 { 0351 identifyShortcutsHost(); 0352 0353 if (!m_newInstanceMethod.isValid()) { 0354 return false; 0355 } 0356 0357 return m_newInstanceMethod.invoke(m_shortcutsHost, Q_ARG(QVariant, index)); 0358 } 0359 0360 bool ContainmentInterface::hideShortcutBadges() 0361 { 0362 identifyShortcutsHost(); 0363 0364 if (!m_showShortcutsMethod.isValid()) { 0365 return false; 0366 } 0367 0368 return m_showShortcutsMethod.invoke(m_shortcutsHost, Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, false), Q_ARG(QVariant, -1)); 0369 } 0370 0371 bool ContainmentInterface::showOnlyMeta() 0372 { 0373 if (!m_corona->universalSettings()->kwin_metaForwardedToLatte()) { 0374 return false; 0375 } 0376 0377 return showShortcutBadges(false, true); 0378 } 0379 0380 bool ContainmentInterface::showShortcutBadges(const bool showLatteShortcuts, const bool showMeta) 0381 { 0382 identifyShortcutsHost(); 0383 0384 if (!m_showShortcutsMethod.isValid() || !isCapableToShowShortcutBadges()) { 0385 return false; 0386 } 0387 0388 int appLauncherId = m_corona->universalSettings()->kwin_metaForwardedToLatte() && showMeta ? applicationLauncherId() : -1; 0389 0390 return m_showShortcutsMethod.invoke(m_shortcutsHost, Q_ARG(QVariant, showLatteShortcuts), Q_ARG(QVariant, true), Q_ARG(QVariant, showMeta), Q_ARG(QVariant, appLauncherId)); 0391 } 0392 0393 int ContainmentInterface::appletIdForVisualIndex(const int index) 0394 { 0395 identifyShortcutsHost(); 0396 0397 if (!m_appletIdForIndexMethod.isValid()) { 0398 return -1; 0399 } 0400 0401 QVariant appletId{-1}; 0402 0403 m_appletIdForIndexMethod.invoke(m_shortcutsHost, Q_RETURN_ARG(QVariant, appletId), Q_ARG(QVariant, index)); 0404 0405 return appletId.toInt(); 0406 } 0407 0408 0409 void ContainmentInterface::deactivateApplets() 0410 { 0411 if (!m_view->containment() || !m_view->inReadyState()) { 0412 return; 0413 } 0414 0415 for (const auto applet : m_view->containment()->applets()) { 0416 PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0417 0418 if (ai) { 0419 ai->setExpanded(false); 0420 } 0421 } 0422 } 0423 0424 bool ContainmentInterface::appletIsExpandable(const int id) const 0425 { 0426 if (!m_view->containment() || !m_view->inReadyState()) { 0427 return false; 0428 } 0429 0430 for (const auto applet : m_view->containment()->applets()) { 0431 if (applet && applet->id() == (uint)id) { 0432 if (Layouts::Storage::self()->isSubContainment(m_view->corona(), applet)) { 0433 return true; 0434 } 0435 0436 PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0437 0438 if (ai) { 0439 return appletIsExpandable(ai); 0440 } 0441 } 0442 } 0443 0444 return false; 0445 } 0446 0447 bool ContainmentInterface::appletIsExpandable(PlasmaQuick::AppletQuickItem *appletQuickItem) const 0448 { 0449 if (!appletQuickItem || !m_view->inReadyState()) { 0450 return false; 0451 } 0452 0453 return ((appletQuickItem->fullRepresentation() != nullptr 0454 && appletQuickItem->preferredRepresentation() != appletQuickItem->fullRepresentation()) 0455 || Latte::Layouts::Storage::self()->isSubContainment(m_view->corona(), appletQuickItem->applet())); 0456 } 0457 0458 bool ContainmentInterface::appletIsActivationTogglesExpanded(const int id) const 0459 { 0460 if (!m_view->containment() || !m_view->inReadyState()) { 0461 return false; 0462 } 0463 0464 for (const auto applet : m_view->containment()->applets()) { 0465 if (applet && applet->id() == (uint)id) { 0466 if (Layouts::Storage::self()->isSubContainment(m_view->corona(), applet)) { 0467 return true; 0468 } 0469 0470 PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0471 0472 if (ai) { 0473 return ai->isActivationTogglesExpanded(); 0474 } 0475 } 0476 } 0477 0478 return false; 0479 } 0480 0481 bool ContainmentInterface::hasExpandedApplet() const 0482 { 0483 return m_expandedAppletIds.count() > 0; 0484 } 0485 0486 bool ContainmentInterface::hasLatteTasks() const 0487 { 0488 return (m_latteTasksModel->count() > 0); 0489 } 0490 0491 bool ContainmentInterface::hasPlasmaTasks() const 0492 { 0493 return (m_plasmaTasksModel->count() > 0); 0494 } 0495 0496 int ContainmentInterface::indexOfApplet(const int &id) 0497 { 0498 if (m_appletOrder.contains(id)) { 0499 return m_appletOrder.indexOf(id); 0500 } else if (m_appletData.contains(id)) { 0501 return m_appletData[id].lastValidIndex; 0502 } 0503 0504 return -1; 0505 } 0506 0507 ViewPart::AppletInterfaceData ContainmentInterface::appletDataAtIndex(const int &index) 0508 { 0509 ViewPart::AppletInterfaceData data; 0510 0511 if (index<0 || (index > (m_appletOrder.count()-1))) { 0512 return data; 0513 } 0514 0515 return m_appletData[m_appletOrder[index]]; 0516 } 0517 0518 ViewPart::AppletInterfaceData ContainmentInterface::appletDataForId(const int &id) 0519 { 0520 ViewPart::AppletInterfaceData data; 0521 0522 if (!m_appletData.contains(id)) { 0523 return data; 0524 } 0525 0526 return m_appletData[id]; 0527 } 0528 0529 QObject *ContainmentInterface::plasmoid() const 0530 { 0531 return m_plasmoid; 0532 } 0533 0534 void ContainmentInterface::setPlasmoid(QObject *plasmoid) 0535 { 0536 if (m_plasmoid == plasmoid) { 0537 return; 0538 } 0539 0540 m_plasmoid = plasmoid; 0541 0542 if (m_plasmoid) { 0543 m_configuration = qobject_cast<KDeclarative::ConfigPropertyMap *>(m_plasmoid->property("configuration").value<QObject *>()); 0544 0545 if (m_configuration) { 0546 connect(m_configuration, &QQmlPropertyMap::valueChanged, this, &ContainmentInterface::containmentConfigPropertyChanged); 0547 } 0548 } 0549 0550 emit plasmoidChanged(); 0551 } 0552 0553 QObject *ContainmentInterface::layoutManager() const 0554 { 0555 return m_layoutManager; 0556 } 0557 0558 void ContainmentInterface::setLayoutManager(QObject *manager) 0559 { 0560 if (m_layoutManager == manager) { 0561 return; 0562 } 0563 0564 m_layoutManager = manager; 0565 0566 // applets order 0567 int metaorderindex = m_layoutManager->metaObject()->indexOfProperty("order"); 0568 if (metaorderindex >= 0) { 0569 QMetaProperty metaorder = m_layoutManager->metaObject()->property(metaorderindex); 0570 if (metaorder.hasNotifySignal()) { 0571 QMetaMethod metaorderchanged = metaorder.notifySignal(); 0572 QMetaMethod metaupdateappletorder = this->metaObject()->method(this->metaObject()->indexOfSlot("updateAppletsOrder()")); 0573 connect(m_layoutManager, metaorderchanged, this, metaupdateappletorder); 0574 updateAppletsOrder(); 0575 } 0576 } 0577 0578 // applets in locked zoom 0579 metaorderindex = m_layoutManager->metaObject()->indexOfProperty("lockedZoomApplets"); 0580 if (metaorderindex >= 0) { 0581 QMetaProperty metaorder = m_layoutManager->metaObject()->property(metaorderindex); 0582 if (metaorder.hasNotifySignal()) { 0583 QMetaMethod metaorderchanged = metaorder.notifySignal(); 0584 QMetaMethod metaupdateapplets = this->metaObject()->method(this->metaObject()->indexOfSlot("updateAppletsInLockedZoom()")); 0585 connect(m_layoutManager, metaorderchanged, this, metaupdateapplets); 0586 updateAppletsInLockedZoom(); 0587 } 0588 } 0589 0590 // applets disabled their autocoloring 0591 metaorderindex = m_layoutManager->metaObject()->indexOfProperty("userBlocksColorizingApplets"); 0592 if (metaorderindex >= 0) { 0593 QMetaProperty metaorder = m_layoutManager->metaObject()->property(metaorderindex); 0594 if (metaorder.hasNotifySignal()) { 0595 QMetaMethod metaorderchanged = metaorder.notifySignal(); 0596 QMetaMethod metaupdateapplets = this->metaObject()->method(this->metaObject()->indexOfSlot("updateAppletsDisabledColoring()")); 0597 connect(m_layoutManager, metaorderchanged, this, metaupdateapplets); 0598 updateAppletsDisabledColoring(); 0599 } 0600 } 0601 0602 emit layoutManagerChanged(); 0603 } 0604 0605 void ContainmentInterface::addApplet(const QString &pluginId) 0606 { 0607 if (pluginId.isEmpty()) { 0608 return; 0609 } 0610 0611 QStringList paths = Latte::Layouts::Importer::standardPaths(); 0612 QString pluginpath; 0613 0614 for(int i=0; i<paths.count(); ++i) { 0615 QString cpath = paths[i] + "/plasma/plasmoids/" + pluginId; 0616 0617 if (QDir(cpath).exists()) { 0618 pluginpath = cpath; 0619 break; 0620 } 0621 } 0622 0623 if (!pluginpath.isEmpty()) { 0624 m_view->containment()->createApplet(pluginId); 0625 } 0626 } 0627 0628 void ContainmentInterface::addApplet(QObject *metadata, int x, int y) 0629 { 0630 int processmimedataindex = m_plasmoid->metaObject()->indexOfMethod("processMimeData(QObject*,int,int)"); 0631 QMetaMethod processmethod = m_plasmoid->metaObject()->method(processmimedataindex); 0632 processmethod.invoke(m_plasmoid, 0633 Q_ARG(QObject *, metadata), 0634 Q_ARG(int, x), 0635 Q_ARG(int, y)); 0636 } 0637 0638 void ContainmentInterface::addExpandedApplet(PlasmaQuick::AppletQuickItem * appletQuickItem) 0639 { 0640 if (appletQuickItem && m_expandedAppletIds.contains(appletQuickItem) && appletIsExpandable(appletQuickItem)) { 0641 return; 0642 } 0643 0644 bool isExpanded = hasExpandedApplet(); 0645 0646 m_expandedAppletIds[appletQuickItem] = appletQuickItem->applet()->id(); 0647 0648 if (isExpanded != hasExpandedApplet()) { 0649 emit hasExpandedAppletChanged(); 0650 } 0651 0652 emit expandedAppletStateChanged(); 0653 } 0654 0655 void ContainmentInterface::removeExpandedApplet(PlasmaQuick::AppletQuickItem *appletQuickItem) 0656 { 0657 if (!m_expandedAppletIds.contains(appletQuickItem)) { 0658 return; 0659 } 0660 0661 bool isExpanded = hasExpandedApplet(); 0662 0663 m_expandedAppletIds.remove(appletQuickItem); 0664 0665 if (isExpanded != hasExpandedApplet()) { 0666 emit hasExpandedAppletChanged(); 0667 } 0668 0669 emit expandedAppletStateChanged(); 0670 } 0671 0672 QAbstractListModel *ContainmentInterface::latteTasksModel() const 0673 { 0674 return m_latteTasksModel; 0675 } 0676 0677 QAbstractListModel *ContainmentInterface::plasmaTasksModel() const 0678 { 0679 return m_plasmaTasksModel; 0680 } 0681 0682 void ContainmentInterface::onAppletExpandedChanged() 0683 { 0684 PlasmaQuick::AppletQuickItem *appletItem = static_cast<PlasmaQuick::AppletQuickItem *>(QObject::sender()); 0685 0686 if (appletItem) { 0687 bool added{false}; 0688 0689 if (appletItem->isExpanded()) { 0690 if (appletItem->switchWidth()>0 && appletItem->switchHeight()>0) { 0691 added = ((appletItem->width()<=appletItem->switchWidth()) 0692 && (appletItem->height()<=appletItem->switchHeight())); 0693 } else { 0694 added = true; 0695 } 0696 } 0697 0698 if (added && appletIsExpandable(appletItem)) { 0699 addExpandedApplet(appletItem); 0700 } else { 0701 removeExpandedApplet(appletItem); 0702 } 0703 } 0704 } 0705 0706 QList<int> ContainmentInterface::appletsOrder() const 0707 { 0708 return m_appletOrder; 0709 } 0710 0711 void ContainmentInterface::updateAppletsOrder() 0712 { 0713 if (!m_layoutManager) { 0714 return; 0715 } 0716 0717 QList<int> neworder = m_layoutManager->property("order").value<QList<int>>(); 0718 0719 if (m_appletOrder == neworder) { 0720 return; 0721 } 0722 0723 m_appletOrder = neworder; 0724 0725 //! update applets last recorded index, this is needed for example when an applet is removed 0726 //! to know in which index was located before the removal 0727 for(const auto &id: m_appletOrder) { 0728 if (m_appletData.contains(id)) { 0729 m_appletData[id].lastValidIndex = m_appletOrder.indexOf(id); 0730 } 0731 } 0732 0733 emit appletsOrderChanged(); 0734 } 0735 0736 void ContainmentInterface::updateAppletsInLockedZoom() 0737 { 0738 if (!m_layoutManager) { 0739 return; 0740 } 0741 0742 QList<int> appletslockedzoom = m_layoutManager->property("lockedZoomApplets").value<QList<int>>(); 0743 0744 if (m_appletsInLockedZoom == appletslockedzoom) { 0745 return; 0746 } 0747 0748 m_appletsInLockedZoom = appletslockedzoom; 0749 emit appletsInLockedZoomChanged(m_appletsInLockedZoom); 0750 } 0751 0752 void ContainmentInterface::updateAppletsDisabledColoring() 0753 { 0754 if (!m_layoutManager) { 0755 return; 0756 } 0757 0758 QList<int> appletsdisabledcoloring = m_layoutManager->property("userBlocksColorizingApplets").value<QList<int>>(); 0759 0760 if (m_appletsDisabledColoring == appletsdisabledcoloring) { 0761 return; 0762 } 0763 0764 m_appletsDisabledColoring = appletsdisabledcoloring; 0765 emit appletsDisabledColoringChanged(appletsdisabledcoloring); 0766 } 0767 0768 void ContainmentInterface::onLatteTasksCountChanged() 0769 { 0770 if ((m_hasLatteTasks && m_latteTasksModel->count()>0) 0771 || (!m_hasLatteTasks && m_latteTasksModel->count() == 0)) { 0772 return; 0773 } 0774 0775 m_hasLatteTasks = (m_latteTasksModel->count() > 0); 0776 emit hasLatteTasksChanged(); 0777 } 0778 0779 void ContainmentInterface::onPlasmaTasksCountChanged() 0780 { 0781 if ((m_hasPlasmaTasks && m_plasmaTasksModel->count()>0) 0782 || (!m_hasPlasmaTasks && m_plasmaTasksModel->count() == 0)) { 0783 return; 0784 } 0785 0786 m_hasPlasmaTasks = (m_plasmaTasksModel->count() > 0); 0787 emit hasPlasmaTasksChanged(); 0788 } 0789 0790 bool ContainmentInterface::appletIsExpanded(const int id) const 0791 { 0792 return m_expandedAppletIds.values().contains(id); 0793 } 0794 0795 void ContainmentInterface::toggleAppletExpanded(const int id) 0796 { 0797 if (!m_view->containment() || !m_view->inReadyState()) { 0798 return; 0799 } 0800 0801 for (const auto applet : m_view->containment()->applets()) { 0802 if (applet->id() == (uint)id && !Layouts::Storage::self()->isSubContainment(m_view->corona(), applet)/*block for sub-containments*/) { 0803 PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0804 0805 if (ai) { 0806 emit applet->activated(); 0807 } 0808 } 0809 } 0810 } 0811 0812 void ContainmentInterface::removeApplet(const int &id) 0813 { 0814 if (!m_appletData.contains(id)) { 0815 return; 0816 } 0817 0818 auto applet = m_appletData[id].applet; 0819 emit applet->appletDeleted(applet); //! this signal should be part of Plasma Frameworks AppletPrivate::destroy() function... 0820 applet->destroy(); 0821 } 0822 0823 0824 void ContainmentInterface::setAppletsOrder(const QList<int> &order) 0825 { 0826 QMetaObject::invokeMethod(m_layoutManager, 0827 "requestAppletsOrder", 0828 Qt::DirectConnection, 0829 Q_ARG(QList<int>, order)); 0830 0831 } 0832 0833 void ContainmentInterface::setAppletsInLockedZoom(const QList<int> &applets) 0834 { 0835 QMetaObject::invokeMethod(m_layoutManager, 0836 "requestAppletsInLockedZoom", 0837 Qt::DirectConnection, 0838 Q_ARG(QList<int>, applets)); 0839 } 0840 0841 void ContainmentInterface::setAppletsDisabledColoring(const QList<int> &applets) 0842 { 0843 QMetaObject::invokeMethod(m_layoutManager, 0844 "requestAppletsDisabledColoring", 0845 Qt::DirectConnection, 0846 Q_ARG(QList<int>, applets)); 0847 } 0848 0849 void ContainmentInterface::setAppletInScheduledDestruction(const int &id, const bool &enabled) 0850 { 0851 QMetaObject::invokeMethod(m_layoutManager, 0852 "setAppletInScheduledDestruction", 0853 Qt::DirectConnection, 0854 Q_ARG(int, id), 0855 Q_ARG(bool, enabled)); 0856 } 0857 0858 void ContainmentInterface::updateContainmentConfigProperty(const QString &key, const QVariant &value) 0859 { 0860 if (!m_configuration || !m_configuration->keys().contains(key)) { 0861 0862 } 0863 0864 if (m_configuration->keys().contains(key) 0865 && (*m_configuration)[key] != value) { 0866 m_configuration->insert(key, value); 0867 emit m_configuration->valueChanged(key, value); 0868 } 0869 } 0870 0871 void ContainmentInterface::updateAppletConfigProperty(const int &id, const QString &key, const QVariant &value) 0872 { 0873 if (!m_appletData.contains(id) || !m_appletData[id].configuration || !m_appletData[id].configuration->keys().contains(key)) { 0874 return; 0875 } 0876 0877 if (m_appletData[id].configuration->keys().contains(key) 0878 && (*m_appletData[id].configuration)[key] != value) { 0879 m_appletData[id].configuration->insert(key, value); 0880 emit m_appletData[id].configuration->valueChanged(key, value); 0881 } 0882 } 0883 0884 void ContainmentInterface::updateAppletsTracking() 0885 { 0886 if (!m_view->containment()) { 0887 return; 0888 } 0889 0890 for (const auto applet : m_view->containment()->applets()) { 0891 onAppletAdded(applet); 0892 } 0893 0894 emit initializationCompleted(); 0895 } 0896 0897 void ContainmentInterface::updateAppletDelayedConfiguration() 0898 { 0899 for (const auto id : m_appletData.keys()) { 0900 if (!m_appletData[id].configuration) { 0901 m_appletData[id].configuration = appletConfiguration(m_appletData[id].applet); 0902 0903 if (m_appletData[id].configuration) { 0904 qDebug() << "org.kde.sync delayed applet configuration was successful for : " << id; 0905 initAppletConfigurationSignals(id, m_appletData[id].configuration); 0906 } 0907 } 0908 } 0909 } 0910 0911 void ContainmentInterface::initAppletConfigurationSignals(const int &id, KDeclarative::ConfigPropertyMap *configuration) 0912 { 0913 if (!configuration) { 0914 return; 0915 } 0916 0917 connect(configuration, &QQmlPropertyMap::valueChanged, 0918 this, [&, id](const QString &key, const QVariant &value) { 0919 //qDebug() << "org.kde.sync applet property changed : " << currentAppletId << " __ " << m_appletData[currentAppletId].plugin << " __ " << key << " __ " << value; 0920 emit appletConfigPropertyChanged(id, key, value); 0921 }); 0922 } 0923 0924 KDeclarative::ConfigPropertyMap *ContainmentInterface::appletConfiguration(const Plasma::Applet *applet) 0925 { 0926 if (!m_view->containment() || !applet) { 0927 return nullptr; 0928 } 0929 0930 PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0931 bool isSubContainment = Layouts::Storage::self()->isSubContainment(m_view->corona(), applet); //we use corona() to make sure that returns true even when it is first created from user 0932 int currentAppletId = applet->id(); 0933 KDeclarative::ConfigPropertyMap *configuration{nullptr}; 0934 0935 //! set configuration object properly for applets and subcontainments 0936 if (!isSubContainment) { 0937 int metaconfigindex = ai->metaObject()->indexOfProperty("configuration"); 0938 if (metaconfigindex >=0 ){ 0939 configuration = qobject_cast<KDeclarative::ConfigPropertyMap *>((ai->property("configuration")).value<QObject *>()); 0940 } 0941 } else { 0942 Plasma::Containment *subcontainment = Layouts::Storage::self()->subContainmentOf(m_view->corona(), applet); 0943 if (subcontainment) { 0944 PlasmaQuick::AppletQuickItem *subcai = subcontainment->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0945 0946 if (subcai) { 0947 int metaconfigindex = subcai->metaObject()->indexOfProperty("configuration"); 0948 if (metaconfigindex >=0 ){ 0949 configuration = qobject_cast<KDeclarative::ConfigPropertyMap *>((subcai->property("configuration")).value<QObject *>()); 0950 } 0951 } 0952 } 0953 } 0954 0955 return configuration; 0956 } 0957 0958 void ContainmentInterface::onAppletAdded(Plasma::Applet *applet) 0959 { 0960 if (!m_view->containment() || !applet) { 0961 return; 0962 } 0963 0964 PlasmaQuick::AppletQuickItem *ai = applet->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0965 bool isSubContainment = Layouts::Storage::self()->isSubContainment(m_view->corona(), applet); //we use corona() to make sure that returns true even when it is first created from user 0966 int currentAppletId = applet->id(); 0967 0968 //! Track expanded/able applets and Tasks applets 0969 if (isSubContainment) { 0970 //! internal containment case 0971 Plasma::Containment *subContainment = Layouts::Storage::self()->subContainmentOf(m_view->corona(), applet); 0972 PlasmaQuick::AppletQuickItem *contAi = ai; 0973 0974 if (contAi && !m_appletsExpandedConnections.contains(contAi)) { 0975 m_appletsExpandedConnections[contAi] = connect(contAi, &PlasmaQuick::AppletQuickItem::expandedChanged, this, &ContainmentInterface::onAppletExpandedChanged); 0976 0977 connect(contAi, &QObject::destroyed, this, [&, contAi](){ 0978 m_appletsExpandedConnections.remove(contAi); 0979 removeExpandedApplet(contAi); 0980 }); 0981 } 0982 0983 for (const auto internalApplet : subContainment->applets()) { 0984 PlasmaQuick::AppletQuickItem *ai = internalApplet->property("_plasma_graphicObject").value<PlasmaQuick::AppletQuickItem *>(); 0985 0986 if (ai && !m_appletsExpandedConnections.contains(ai) ){ 0987 m_appletsExpandedConnections[ai] = connect(ai, &PlasmaQuick::AppletQuickItem::expandedChanged, this, &ContainmentInterface::onAppletExpandedChanged); 0988 0989 connect(ai, &QObject::destroyed, this, [&, ai](){ 0990 m_appletsExpandedConnections.remove(ai); 0991 removeExpandedApplet(ai); 0992 }); 0993 } 0994 } 0995 } else if (ai) { 0996 KPluginMetaData meta = applet->kPackage().metadata(); 0997 const auto &provides = KPluginMetaData::readStringList(meta.rawData(), QStringLiteral("X-Plasma-Provides")); 0998 0999 if (meta.pluginId() == QLatin1String("org.kde.latte.plasmoid")) { 1000 //! populate latte tasks applet 1001 m_latteTasksModel->addTask(ai); 1002 } else if (provides.contains(QLatin1String("org.kde.plasma.multitasking"))) { 1003 //! populate plasma tasks applet 1004 m_plasmaTasksModel->addTask(ai); 1005 } else if (!m_appletsExpandedConnections.contains(ai)) { 1006 m_appletsExpandedConnections[ai] = connect(ai, &PlasmaQuick::AppletQuickItem::expandedChanged, this, &ContainmentInterface::onAppletExpandedChanged); 1007 1008 connect(ai, &QObject::destroyed, this, [&, ai](){ 1009 m_appletsExpandedConnections.remove(ai); 1010 removeExpandedApplet(ai); 1011 }); 1012 } 1013 } 1014 1015 //! Track All Applets, for example to support syncing between different docks and panels 1016 if (ai) { 1017 bool initializing{!m_appletData.contains(currentAppletId)}; 1018 1019 KPluginMetaData meta = applet->kPackage().metadata(); 1020 ViewPart::AppletInterfaceData data; 1021 data.id = currentAppletId; 1022 data.plugin = meta.pluginId(); 1023 data.applet = applet; 1024 data.plasmoid = ai; 1025 data.lastValidIndex = m_appletOrder.indexOf(data.id); 1026 //! set configuration object properly for applets and subcontainments 1027 data.configuration = appletConfiguration(applet); 1028 1029 //! track property changes in applets 1030 if (data.configuration) { 1031 initAppletConfigurationSignals(data.id, data.configuration); 1032 } else { 1033 qDebug() << "org.kde.sync Unfortunately configuration syncing for :: " << currentAppletId << " was not established, configuration object was missing!"; 1034 m_appletDelayedConfigurationTimer.start(); 1035 } 1036 1037 if (initializing) { 1038 //! track applet destroyed flag 1039 connect(applet, &Plasma::Applet::destroyedChanged, this, [&, currentAppletId](bool destroyed) { 1040 emit appletInScheduledDestructionChanged(currentAppletId, destroyed); 1041 }); 1042 1043 //! remove on applet destruction 1044 connect(applet, &QObject::destroyed, this, [&, data](){ 1045 emit appletRemoved(data.id); 1046 //qDebug() << "org.kde.sync: removing applet ::: " << data.id << " __ " << data.plugin << " remained : " << m_appletData.keys(); 1047 m_appletData.remove(data.id); 1048 }); 1049 } 1050 1051 m_appletData[data.id] = data; 1052 emit appletDataCreated(data.id); 1053 } 1054 } 1055 1056 QList<int> ContainmentInterface::toIntList(const QVariantList &list) 1057 { 1058 QList<int> converted; 1059 1060 for(const QVariant &item: list) { 1061 converted << item.toInt(); 1062 } 1063 1064 return converted; 1065 } 1066 1067 } 1068 }