Plasma

appletinterface.cpp
1 /*
2  SPDX-FileCopyrightText: 2008-2013 Aaron Seigo <[email protected]>
3  SPDX-FileCopyrightText: 2010-2013 Marco Martin <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "appletinterface.h"
9 
10 #include <QAction>
11 #include <QActionGroup>
12 #include <QDir>
13 #include <QFile>
14 #include <QIcon>
15 #include <QTimer>
16 
17 #include <KActionCollection>
18 #include <KConfigLoader>
19 #include <KLocalizedString>
20 #include <KService>
21 #include <QDebug>
22 
23 #include <Plasma/ContainmentActions>
24 #include <Plasma/Corona>
25 #include <Plasma/Package>
26 #include <Plasma/Plasma>
27 #include <Plasma/PluginLoader>
28 
29 #include "containmentinterface.h"
30 #include "wallpaperinterface.h"
31 
32 #if KDECLARATIVE_BUILD_DEPRECATED_SINCE(5, 89)
33 #include <kdeclarative/configpropertymap.h>
34 #else
35 #include <KConfigPropertyMap>
36 #endif
37 #include <kdeclarative/qmlobject.h>
38 
39 AppletInterface::AppletInterface(DeclarativeAppletScript *script, const QVariantList &args, QQuickItem *parent)
40  : AppletQuickItem(script->applet(), parent)
41  , m_configuration(nullptr)
42  , m_appletScriptEngine(script)
43  , m_toolTipTextFormat(0)
44  , m_toolTipItem(nullptr)
45  , m_args(args)
46  , m_hideOnDeactivate(true)
47  , m_oldKeyboardShortcut(0)
48  , m_dummyNativeInterface(nullptr)
49  , m_positionBeforeRemoval(QPointF(-1, -1))
50 {
51  qmlRegisterAnonymousType<QAction>("org.kde.plasma.plasmoid", 1);
52 
53  connect(applet()->containment()->corona(), &Plasma::Corona::editModeChanged, this, &AppletInterface::editModeChanged);
54  connect(this, &AppletInterface::configNeedsSaving, applet(), &Plasma::Applet::configNeedsSaving);
55  connect(applet(), &Plasma::Applet::immutabilityChanged, this, &AppletInterface::immutabilityChanged);
56  connect(applet(), &Plasma::Applet::userConfiguringChanged, this, &AppletInterface::userConfiguringChanged);
57 
59 
60  connect(applet(), &Plasma::Applet::statusChanged, this, &AppletInterface::statusChanged);
61 
62  connect(applet(), &Plasma::Applet::destroyedChanged, this, &AppletInterface::destroyedChanged);
63 
64  connect(applet(), &Plasma::Applet::titleChanged, this, &AppletInterface::titleChanged);
65 
66  connect(applet(), &Plasma::Applet::titleChanged, this, [this]() {
67  if (m_toolTipMainText.isNull()) {
68  Q_EMIT toolTipMainTextChanged();
69  }
70  });
71 
72  connect(applet(), &Plasma::Applet::iconChanged, this, &AppletInterface::iconChanged);
73 
74  connect(applet(), &Plasma::Applet::busyChanged, this, &AppletInterface::busyChanged);
75 
76  connect(applet(), &Plasma::Applet::backgroundHintsChanged, this, &AppletInterface::backgroundHintsChanged);
77  connect(applet(), &Plasma::Applet::effectiveBackgroundHintsChanged, this, &AppletInterface::effectiveBackgroundHintsChanged);
78  connect(applet(), &Plasma::Applet::userBackgroundHintsChanged, this, &AppletInterface::userBackgroundHintsChanged);
79 
80  connect(applet(), &Plasma::Applet::configurationRequiredChanged, this, [this](bool configurationRequired, const QString &reason) {
81  Q_UNUSED(configurationRequired);
82  Q_UNUSED(reason);
84  Q_EMIT configurationRequiredReasonChanged();
85  });
86 
88  connect(applet(), &Plasma::Applet::containmentDisplayHintsChanged, this, &AppletInterface::containmentDisplayHintsChanged);
89 
90  connect(appletScript(), &DeclarativeAppletScript::formFactorChanged, this, &AppletInterface::formFactorChanged);
91  connect(appletScript(), &DeclarativeAppletScript::locationChanged, this, &AppletInterface::locationChanged);
92  connect(appletScript(), &DeclarativeAppletScript::contextChanged, this, &AppletInterface::contextChanged);
93 
94  if (applet()->containment()) {
95  connect(applet()->containment(), &Plasma::Containment::screenChanged, this, &AppletInterface::screenChanged);
96 
97  // Screen change implies geo change for good measure.
98  connect(applet()->containment(), &Plasma::Containment::screenChanged, this, &AppletInterface::screenGeometryChanged);
99 
100  connect(applet()->containment()->corona(), &Plasma::Corona::screenGeometryChanged, this, [this](int id) {
101  if (id == applet()->containment()->screen()) {
102  Q_EMIT screenGeometryChanged();
103  }
104  });
105 
106  connect(applet()->containment()->corona(), &Plasma::Corona::availableScreenRegionChanged, this, &ContainmentInterface::availableScreenRegionChanged);
107  connect(applet()->containment()->corona(), &Plasma::Corona::availableScreenRectChanged, this, &ContainmentInterface::availableScreenRectChanged);
108  }
109 
110  connect(this, &AppletInterface::expandedChanged, [=](bool expanded) {
111  // if both compactRepresentationItem and fullRepresentationItem exist,
112  // the applet is in a popup
113  if (expanded) {
114  /* clang-format off */
115  if (compactRepresentationItem()
116  && fullRepresentationItem()
117  && fullRepresentationItem()->window()
118  && compactRepresentationItem()->window()
119  && fullRepresentationItem()->window() != compactRepresentationItem()->window()
120  && fullRepresentationItem()->parentItem()) {
121  /* clang-format on */
122  fullRepresentationItem()->parentItem()->installEventFilter(this);
123  } else if (fullRepresentationItem() && fullRepresentationItem()->parentItem()) {
124  fullRepresentationItem()->parentItem()->removeEventFilter(this);
125  }
126  }
127  });
128 }
129 
130 AppletInterface::~AppletInterface()
131 {
132 }
133 
134 DeclarativeAppletScript *AppletInterface::appletScript() const
135 {
136  return m_appletScriptEngine;
137 }
138 
139 void AppletInterface::init()
140 {
141  if (qmlObject()->rootObject() && m_configuration) {
142  return;
143  }
144 
145 #if KDECLARATIVE_BUILD_DEPRECATED_SINCE(5, 89)
146  m_configuration = new KDeclarative::ConfigPropertyMap(applet()->configScheme(), this);
147 #else
148  m_configuration = new KConfigPropertyMap(applet()->configScheme(), this);
149 #endif
150 
151  AppletQuickItem::init();
152 
153 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
154  geometryChanged(QRectF(), QRectF(x(), y(), width(), height()));
155 #else
156  geometryChange(QRectF(), QRectF(x(), y(), width(), height()));
157 #endif
158  Q_EMIT busyChanged();
159 
160  updateUiReadyConstraint();
161 
162  connect(this, &AppletInterface::isLoadingChanged, this, &AppletInterface::updateUiReadyConstraint);
163 
164  connect(applet(), &Plasma::Applet::activated, this, [=]() {
165  // in case the applet doesn't want to get shrunk on reactivation,
166  // we always expand it again (only in order to conform with legacy behaviour)
167  bool activate = !(isExpanded() && isActivationTogglesExpanded());
168 
169  setExpanded(activate);
170  if (activate) {
171  if (QQuickItem *i = qobject_cast<QQuickItem *>(fullRepresentationItem())) {
172  // Bug 372476: never pull focus away from it, only setFocus(true)
173  i->setFocus(true, Qt::ShortcutFocusReason);
174  }
175  }
176  });
177 
178  if (m_args.count() == 1) {
179  Q_EMIT externalData(QString(), m_args.first());
180  } else if (!m_args.isEmpty()) {
181  Q_EMIT externalData(QString(), m_args);
182  }
183 }
184 
185 void AppletInterface::destroyedChanged(bool destroyed)
186 {
187  // if an item loses its scene before losing the focus, will never
188  // be able to gain focus again
189  if (destroyed && window() && window()->activeFocusItem()) {
190  QQuickItem *focus = window()->activeFocusItem();
191  QQuickItem *candidate = focus;
192  bool isAncestor = false;
193 
194  // search if the current focus item is a child or grandchild of the applet
195  while (candidate) {
196  if (candidate == this) {
197  isAncestor = true;
198  break;
199  }
200  candidate = candidate->parentItem();
201  }
202 
203  if (isAncestor) {
204  // Found? remove focus for the whole hierarchy
205  candidate = focus;
206 
207  while (candidate && candidate != this) {
208  candidate->setFocus(false);
209  candidate = candidate->parentItem();
210  }
211  }
212  }
213 
214  setVisible(!destroyed);
215 }
216 
218 {
219  return applet()->formFactor();
220 }
221 
223 {
224  return applet()->location();
225 }
226 
228 {
229  return applet()->containmentDisplayHints();
230 }
231 
233 {
234  if (applet()->containment()) {
235  return applet()->containment()->activity();
236  } else {
237  return QString();
238  }
239 }
240 
242 {
243  return m_configuration;
244 }
245 
246 uint AppletInterface::id() const
247 {
248  return applet()->id();
249 }
250 
252 {
253  return applet()->pluginMetaData().isValid() ? applet()->pluginMetaData().pluginId() : QString();
254 }
255 
257 {
258  return applet()->icon();
259 }
260 
261 void AppletInterface::setIcon(const QString &icon)
262 {
263  if (applet()->icon() == icon) {
264  return;
265  }
266 
267  applet()->setIcon(icon);
268 }
269 
271 {
272  return applet()->title();
273 }
274 
275 void AppletInterface::setTitle(const QString &title)
276 {
277  if (applet()->title() == title) {
278  return;
279  }
280 
281  applet()->setTitle(title);
282 }
283 
285 {
286  if (m_toolTipMainText.isNull()) {
287  return title();
288  } else {
289  return m_toolTipMainText;
290  }
291 }
292 
293 void AppletInterface::setToolTipMainText(const QString &text)
294 {
295  // Here we are abusing the difference between a null and an empty string.
296  // by default is null so falls back to the name
297  // the fist time it gets set, an empty non null one is set, and won't fallback anymore
298  if (!m_toolTipMainText.isNull() && m_toolTipMainText == text) {
299  return;
300  }
301 
302  if (text.isEmpty()) {
303  m_toolTipMainText = QStringLiteral(""); // this "" makes it non-null
304  } else {
305  m_toolTipMainText = text;
306  }
307 
308  Q_EMIT toolTipMainTextChanged();
309 }
310 
312 {
313  if (m_toolTipSubText.isNull() && applet()->pluginMetaData().isValid()) {
314  return applet()->pluginMetaData().description();
315  } else {
316  return m_toolTipSubText;
317  }
318 }
319 
320 void AppletInterface::setToolTipSubText(const QString &text)
321 {
322  // Also there the difference between null and empty gets exploited
323  if (!m_toolTipSubText.isNull() && m_toolTipSubText == text) {
324  return;
325  }
326 
327  if (text.isEmpty()) {
328  m_toolTipSubText = QStringLiteral(""); // this "" makes it non-null
329  } else {
330  m_toolTipSubText = text;
331  }
332 
333  Q_EMIT toolTipSubTextChanged();
334 }
335 
337 {
338  return m_toolTipTextFormat;
339 }
340 
341 void AppletInterface::setToolTipTextFormat(int format)
342 {
343  if (m_toolTipTextFormat == format) {
344  return;
345  }
346 
347  m_toolTipTextFormat = format;
348  Q_EMIT toolTipTextFormatChanged();
349 }
350 
352 {
353  return m_toolTipItem.data();
354 }
355 
356 void AppletInterface::setToolTipItem(QQuickItem *toolTipItem)
357 {
358  if (m_toolTipItem.data() == toolTipItem) {
359  return;
360  }
361 
362  m_toolTipItem = toolTipItem;
363  connect(m_toolTipItem.data(), &QObject::destroyed, this, &AppletInterface::toolTipItemChanged);
364 
365  Q_EMIT toolTipItemChanged();
366 }
367 
368 bool AppletInterface::isBusy() const
369 {
370  return applet()->isBusy();
371 }
372 
373 void AppletInterface::setBusy(bool busy)
374 {
375  applet()->setBusy(busy);
376 }
377 
379 {
380  return applet()->backgroundHints();
381 }
382 
383 void AppletInterface::setBackgroundHints(Plasma::Types::BackgroundHints hint)
384 {
385  applet()->setBackgroundHints(hint);
386 }
387 
389 {
390  return applet()->effectiveBackgroundHints();
391 }
392 
394 {
395  return applet()->userBackgroundHints();
396 }
397 
398 void AppletInterface::setUserBackgroundHints(Plasma::Types::BackgroundHints hint)
399 {
400  applet()->setUserBackgroundHints(hint);
401 }
402 
403 void AppletInterface::setConfigurationRequired(bool needsConfiguring, const QString &reason)
404 {
405  appletScript()->setConfigurationRequired(needsConfiguring, reason);
406 }
407 
409 {
410  return appletScript()->filePath(fileType, QString());
411 }
412 
413 QString AppletInterface::file(const QString &fileType, const QString &filePath)
414 {
415  return appletScript()->filePath(fileType, filePath);
416 }
417 
418 QList<QObject *> AppletInterface::contextualActionsObjects() const
419 {
420  QList<QObject *> actions;
421  Plasma::Applet *a = applet();
422  if (a->failedToLaunch()) {
423  return actions;
424  }
425 
426  for (const QString &name : std::as_const(m_actions)) {
427  QAction *action = a->actions()->action(name);
428 
429  if (action) {
430  actions << action;
431  }
432  }
433 
434  return actions;
435 }
436 
437 QList<QAction *> AppletInterface::contextualActions() const
438 {
439  QList<QAction *> actions;
440  Plasma::Applet *a = applet();
441  if (a->failedToLaunch()) {
442  return actions;
443  }
444 
445  for (const QString &name : std::as_const(m_actions)) {
446  QAction *action = a->actions()->action(name);
447 
448  if (action) {
449  actions << action;
450  }
451  }
452 
453  return actions;
454 }
455 
456 void AppletInterface::setActionSeparator(const QString &name)
457 {
458  Plasma::Applet *a = applet();
459  QAction *action = a->actions()->action(name);
460 
461  if (action) {
462  action->setSeparator(true);
463  } else {
464  action = new QAction(this);
465  action->setSeparator(true);
466  a->actions()->addAction(name, action);
467  m_actions.append(name);
468  Q_EMIT contextualActionsChanged();
469  }
470 }
471 
472 void AppletInterface::setActionGroup(const QString &actionName, const QString &group)
473 {
474  Plasma::Applet *a = applet();
475  QAction *action = a->actions()->action(actionName);
476 
477  if (!action) {
478  return;
479  }
480 
481  if (!m_actionGroups.contains(group)) {
482  m_actionGroups[group] = new QActionGroup(this);
483  }
484 
485  action->setActionGroup(m_actionGroups[group]);
486 }
487 
488 void AppletInterface::setAction(const QString &name, const QString &text, const QString &icon, const QString &shortcut)
489 {
490  Plasma::Applet *a = applet();
491  QAction *action = a->actions()->action(name);
492 
493  if (action) {
494  action->setText(text);
495  } else {
496  action = new QAction(text, this);
497  a->actions()->addAction(name, action);
498 
499  Q_ASSERT(!m_actions.contains(name));
500  m_actions.append(name);
501  Q_EMIT contextualActionsChanged();
502 
503  connect(action, &QAction::triggered, this, [this, name] {
504  executeAction(name);
505  });
506  }
507 
508  if (!icon.isEmpty()) {
509  action->setIcon(QIcon::fromTheme(icon));
510  }
511 
512  if (!shortcut.isEmpty()) {
513  action->setShortcut(shortcut);
514  }
515 
516  action->setObjectName(name);
517 }
518 
519 void AppletInterface::removeAction(const QString &name)
520 {
521  Plasma::Applet *a = applet();
522  QAction *action = a->actions()->action(name);
523  delete action;
524  m_actions.removeAll(name);
525 }
526 
527 void AppletInterface::clearActions()
528 {
529  const auto oldActionsList = m_actions;
530  for (const QString &action : oldActionsList) {
531  removeAction(action);
532  }
533 }
534 
535 QAction *AppletInterface::action(QString name) const
536 {
537  return applet()->actions()->action(name);
538 }
539 
540 bool AppletInterface::immutable() const
541 {
542  return applet()->immutability() != Plasma::Types::Mutable;
543 }
544 
546 {
547  return applet()->immutability();
548 }
549 
551 {
552  return applet()->isUserConfiguring();
553 }
554 
555 int AppletInterface::apiVersion() const
556 {
557  // Look for C++ plugins first
558  auto filter = [](const KPluginMetaData &md) -> bool {
559  return md.value(QStringLiteral("X-Plasma-API")) == QLatin1String("declarativeappletscript")
560  && md.value(QStringLiteral("X-Plasma-ComponentTypes")).contains(QLatin1String("Applet"));
561  };
562  QVector<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("plasma/scriptengines"), filter);
563  if (plugins.isEmpty()) {
564  return -1;
565  }
566 
567  return plugins.first().value(QStringLiteral("X-KDE-PluginInfo-Version")).toInt();
568 }
569 
570 void AppletInterface::setAssociatedApplication(const QString &string)
571 {
572  if (applet()->associatedApplication() == string) {
573  return;
574  }
575 
576  applet()->setAssociatedApplication(string);
577  Q_EMIT associatedApplicationChanged();
578 }
579 
581 {
582  return applet()->associatedApplication();
583 }
584 
585 void AppletInterface::setAssociatedApplicationUrls(const QList<QUrl> &urls)
586 {
587  if (applet()->associatedApplicationUrls() == urls) {
588  return;
589  }
590 
591  applet()->setAssociatedApplicationUrls(urls);
592  Q_EMIT associatedApplicationUrlsChanged();
593 }
594 
596 {
597  return applet()->associatedApplicationUrls();
598 }
599 
600 void AppletInterface::setStatus(const Plasma::Types::ItemStatus &status)
601 {
602  applet()->setStatus(status);
603 }
604 
606 {
607  return applet()->status();
608 }
609 
610 int AppletInterface::screen() const
611 {
612  if (Plasma::Containment *c = applet()->containment()) {
613  return c->screen();
614  }
615 
616  return -1;
617 }
618 
620 {
621  if (!applet() || !applet()->containment() || !applet()->containment()->corona() || applet()->containment()->screen() < 0) {
622  return QRect();
623  }
624 
625  return applet()->containment()->corona()->screenGeometry(applet()->containment()->screen());
626 }
627 
628 void AppletInterface::setHideOnWindowDeactivate(bool hide)
629 {
630  if (m_hideOnDeactivate != hide) {
631  m_hideOnDeactivate = hide;
632  Q_EMIT hideOnWindowDeactivateChanged();
633  }
634 }
635 
637 {
638  return m_hideOnDeactivate;
639 }
640 
641 void AppletInterface::setConstraintHints(Plasma::Types::ConstraintHints hints)
642 {
643  if (m_constraintHints == hints) {
644  return;
645  }
646 
647  m_constraintHints = hints;
648  Q_EMIT constraintHintsChanged();
649 }
650 
652 {
653  return m_constraintHints;
654 }
655 
657 {
658  return applet()->globalShortcut();
659 }
660 
661 void AppletInterface::setGlobalShortcut(const QKeySequence &sequence)
662 {
663  applet()->setGlobalShortcut(sequence);
664 }
665 
667 {
668  return applet();
669 }
670 
672 {
673  return applet()->configurationRequired();
674 }
675 
676 void AppletInterface::setConfigurationRequiredProperty(bool needsConfiguring)
677 {
678  appletScript()->setConfigurationRequired(needsConfiguring, applet()->configurationRequiredReason());
679 }
680 
682 {
683  return applet()->configurationRequiredReason();
684 }
685 
686 void AppletInterface::setConfigurationRequiredReason(const QString &reason)
687 {
688  appletScript()->setConfigurationRequired(applet()->configurationRequired(), reason);
689 }
690 
692 {
693  Q_UNUSED(file);
694  return downloadPath();
695 }
696 
698 {
699  const QString downloadDir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + QStringLiteral("/Plasma/")
700  + applet()->pluginMetaData().pluginId() + QLatin1Char('/');
701 
702  if (!QFile::exists(downloadDir)) {
703  QDir dir({QLatin1Char('/')});
704  dir.mkpath(downloadDir);
705  }
706 
707  return downloadDir;
708 }
709 
711 {
712  const QString downloadDir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + QStringLiteral("/Plasma/")
713  + applet()->pluginMetaData().pluginId() + QLatin1Char('/');
714  QDir dir(downloadDir);
715  return dir.entryList(QDir::Files | QDir::NoSymLinks | QDir::Readable);
716 }
717 
718 void AppletInterface::executeAction(const QString &name)
719 {
720  if (qmlObject()->rootObject()) {
721  const QMetaObject *metaObj = qmlObject()->rootObject()->metaObject();
722  const QByteArray actionMethodName = "action_" + name.toUtf8();
723  const QByteArray actionFunctionName = actionMethodName + QByteArray("()");
724  if (metaObj->indexOfMethod(QMetaObject::normalizedSignature(actionFunctionName.constData()).constData()) != -1) {
725  QMetaObject::invokeMethod(qmlObject()->rootObject(), actionMethodName.constData(), Qt::DirectConnection);
726  } else {
727  QMetaObject::invokeMethod(qmlObject()->rootObject(), "actionTriggered", Qt::DirectConnection, Q_ARG(QVariant, name));
728  }
729  }
730 }
731 
732 QVariantList AppletInterface::availableScreenRegion() const
733 {
734  QVariantList regVal;
735 
736  if (!applet()->containment() || !applet()->containment()->corona()) {
737  return regVal;
738  }
739 
740  QRegion reg = QRect(0, 0, width(), height());
741  int screenId = screen();
742  if (screenId > -1) {
743  reg = applet()->containment()->corona()->availableScreenRegion(screenId);
744  }
745 
746  auto it = reg.begin();
747  const auto itEnd = reg.end();
748  for (; it != itEnd; ++it) {
749  QRect rect = *it;
750  // make it relative
751  QRect geometry = applet()->containment()->corona()->screenGeometry(screenId);
752  rect.moveTo(rect.topLeft() - geometry.topLeft());
753  regVal << QVariant::fromValue(QRectF(rect));
754  }
755  return regVal;
756 }
757 
759 {
760  if (!applet()->containment() || !applet()->containment()->corona()) {
761  return QRect();
762  }
763 
764  QRect rect(0, 0, width(), height());
765 
766  int screenId = screen();
767 
768  // If corona returned an invalid screenId, try to use lastScreen value if it is valid
769  if (screenId == -1 && applet()->containment()->lastScreen() > -1) {
770  screenId = applet()->containment()->lastScreen();
771  // Is this a screen not actually valid?
772  if (screenId >= applet()->containment()->corona()->numScreens()) {
773  screenId = -1;
774  }
775  }
776 
777  if (screenId > -1) {
778  rect = applet()->containment()->corona()->availableScreenRect(screenId);
779  // make it relative
780  QRect geometry = applet()->containment()->corona()->screenGeometry(screenId);
781  rect.moveTo(rect.topLeft() - geometry.topLeft());
782  }
783 
784  return rect;
785 }
786 
787 bool AppletInterface::event(QEvent *event)
788 {
789  // QAction keyboard shortcuts cannot work with QML2 (and probably newver will
790  // since in Qt qtquick and qwidgets cannot depend from each other in any way)
791  // so do a simple keyboard shortcut matching here
792  if (event->type() == QEvent::KeyPress) {
793  QKeyEvent *ke = static_cast<QKeyEvent *>(event);
794  QKeySequence seq(ke->key() | ke->modifiers());
795 
796  QList<QAction *> actions = applet()->actions()->actions();
797  // find the wallpaper action if we are a containment
798  ContainmentInterface *ci = qobject_cast<ContainmentInterface *>(this);
799  if (ci) {
800  WallpaperInterface *wi = ci->wallpaperInterface();
801  if (wi) {
802  actions << wi->contextualActions();
803  }
804  }
805 
806  // add any actions of the corona
807  if (applet()->containment() && applet()->containment()->corona()) {
808  actions << applet()->containment()->corona()->actions()->actions();
809  }
810 
811  bool keySequenceUsed = false;
812  for (auto a : std::as_const(actions)) {
813  if (a->shortcut().isEmpty()) {
814  continue;
815  }
816 
817  if (!a->isEnabled()) {
818  continue;
819  }
820 
821  // this will happen on a normal, non emacs shortcut
822  if (seq.matches(a->shortcut()) == QKeySequence::ExactMatch) {
823  event->accept();
824  a->trigger();
825  m_oldKeyboardShortcut = 0;
826  return true;
827 
828  // first part of an emacs style shortcut?
829  } else if (seq.matches(a->shortcut()) == QKeySequence::PartialMatch) {
830  keySequenceUsed = true;
831  m_oldKeyboardShortcut = ke->key() | ke->modifiers();
832 
833  // no match at all, but it can be the second part of an emacs style shortcut
834  } else {
835  QKeySequence seq(m_oldKeyboardShortcut, ke->key() | ke->modifiers());
836 
837  if (seq.matches(a->shortcut()) == QKeySequence::ExactMatch) {
838  event->accept();
839  a->trigger();
840 
841  return true;
842  }
843  }
844  }
845 
846  if (!keySequenceUsed) {
847  m_oldKeyboardShortcut = 0;
848  }
849  }
850 
851  return AppletQuickItem::event(event);
852 }
853 
855 {
856  Q_EMIT applet()->contextualActionsAboutToShow();
857 }
858 
859 bool AppletInterface::eventFilter(QObject *watched, QEvent *event)
860 {
861  if (event->type() == QEvent::MouseButtonPress) {
862  QMouseEvent *e = static_cast<QMouseEvent *>(event);
863 
864  // pass it up to the applet
865  // well, actually we have to pass it to the *containment*
866  // because all the code for showing an applet's contextmenu is actually in Containment.
867  Plasma::Containment *c = applet()->containment();
868  if (c) {
869  const QString trigger = Plasma::ContainmentActions::eventToString(event);
870  Plasma::ContainmentActions *plugin = c->containmentActions().value(trigger);
871  if (!plugin) {
872  return false;
873  }
874 
875  ContainmentInterface *ci = c->property("_plasma_graphicObject").value<ContainmentInterface *>();
876  if (!ci) {
877  return false;
878  }
879 
880  // the plugin can be a single action or a context menu
881  // Don't have an action list? execute as single action
882  // and set the event position as action data
883  if (plugin->contextualActions().length() == 1) {
884  // but first check whether we are not a popup
885  // we don't want to randomly create applets without confirmation
886  if (static_cast<QQuickItem *>(watched)->window() != ci->window()) {
887  return true;
888  }
889 
890  QAction *action = plugin->contextualActions().at(0);
891  action->setData(e->globalPos());
892  action->trigger();
893  return true;
894  }
895 
896  QMenu *desktopMenu = new QMenu;
897  if (desktopMenu->winId()) {
898  desktopMenu->windowHandle()->setTransientParent(window());
899  }
900  prepareContextualActions();
901  ci->addAppletActions(desktopMenu, applet(), event);
902 
903  if (!desktopMenu->isEmpty()) {
904  desktopMenu->setAttribute(Qt::WA_DeleteOnClose);
905  desktopMenu->popup(e->globalPos());
906  return true;
907  }
908 
909  delete desktopMenu;
910  return false;
911  }
912  }
913 
914  return AppletQuickItem::eventFilter(watched, event);
915 }
916 
917 void AppletInterface::updateUiReadyConstraint()
918 {
919  if (!isLoading()) {
920  applet()->updateConstraints(Plasma::Types::UiReadyConstraint);
921  }
922 }
923 
924 bool AppletInterface::isLoading() const
925 {
926  return m_loading;
927 }
928 
930 {
931  return applet()->pluginMetaData();
932 }
933 
935 {
936  return this;
937 }
938 
939 bool AppletInterface::isEditMode() const
940 {
941  return applet()->containment()->corona()->isEditMode();
942 }
943 
944 #include "moc_appletinterface.cpp"
void availableScreenRegionChanged()
This signal indicates that a change in available screen geometry occurred.
void screenGeometryChanged(int id)
This signal indicates that a change in geometry for the screen occurred.
QAction * addAction(const QString &name, const QObject *receiver=nullptr, const char *member=nullptr)
QRect availableScreenRect
screen area free of panels: the coordinates are relative to the containment, it's independent from th...
QAction * action(const QString &name) const
Plasma::Types::FormFactor formFactor
FormFactor for the plasmoid.
QVariantList availableScreenRegion
The available region of this screen, panels excluded.
bool isEmpty() const const
KActionCollection * actions() const
Returns the collection of actions for this Applet.
Definition: applet.cpp:705
ItemStatus
Status of an applet.
Definition: plasma.h:270
bool configurationRequired() const
Definition: applet.cpp:551
QRegion::const_iterator begin() const const
ConstraintHints
This enumeration lists the various hints that an applet can pass to its constraint regarding the way ...
Definition: plasma.h:58
QPoint topLeft() const const
BackgroundHints
Description on how draw a background for the applet.
Definition: plasma.h:298
QVariant fromValue(const T &value)
Plasma::Types::BackgroundHints userBackgroundHints
The containment (and/or the user) may decide to use another kind of background instead (if supported ...
Q_EMITQ_EMIT
QObject configuration
Configuration object: each config key will be a writable property of this object.
T value() const const
void availableScreenRectChanged()
This signal indicates that a change in available screen geometry occurred.
QQuickItem toolTipItem
This allows to set fully custom QML item as the tooltip.
QQuickWindow * window() const const
QList< QUrl > associatedApplicationUrls
Sets the associated application of this plasmoid, if the plasmoid is representing the "compact" view ...
int length() const const
void configurationRequiredChanged(bool needsConfig, const QString &reason)
Emitted when setConfigurationRequired was called.
QIcon fromTheme(const QString &name)
QString pluginName
Plugin name of the plasmoid.
Q_INVOKABLE QString file(const QString &fileName)
FIXME: remove? Retrieve the path of a file from the Plasmoid package.
void configNeedsSaving()
Emitted when an applet has changed values in its configuration and wishes for them to be saved at the...
Containment * containment() const
Definition: applet.cpp:731
void statusChanged(Plasma::Types::ItemStatus status)
Emitted when the applet status changes.
Plasma::Types::BackgroundHints backgroundHints
How the applet wants its background to be drawn.
QString writableLocation(QStandardPaths::StandardLocation type)
void contextualActionsAboutToShow()
Emitted just before the contextual actions are about to show For instance just before the context men...
Q_INVOKABLE QString downloadPath() const
void busyChanged(bool busy)
Emitted when the busy status has changed.
void setShortcut(const QKeySequence &shortcut)
FormFactor
The FormFactor enumeration describes how a Plasma::Applet should arrange itself.
Definition: plasma.h:72
void setAttribute(Qt::WidgetAttribute attribute, bool on)
T & first()
QString title
User friendly title for the plasmoid: it's the localized applet name by default.
bool exists() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
@ Mutable
The item can be modified in any way.
Definition: plasma.h:236
QString currentActivity
Current activity name the plasmoid is in.
void activated()
Emitted when the applet's activation action is triggered.
void effectiveBackgroundHintsChanged()
Emitted when the effective background hints have changed.
void editModeChanged(bool edit)
emitted when the editMode state changes
This class is exposed to wallpapers as the attached property "wallpaper".
QByteArray normalizedSignature(const char *method)
The base ContainmentActions class.
void destroyedChanged(bool destroyed)
Emitted when the applet has been scheduled for destruction or the destruction has been undone.
QRect screenGeometry
Provides access to the geometry of the applet is in.
void destroyed(QObject *obj)
QString toolTipSubText
Description for the plasmoid tooltip or other means of quick information: it comes from the pluginifo...
bool isEmpty() const const
Plasma::Types::ItemStatus status
Status of the plasmoid: useful to instruct the shell if this plasmoid is requesting attention,...
This class is exposed to containments QML as the attached property Plasmoid.
void userBackgroundHintsChanged()
Emitted when the user background hints have changed.
void setIcon(const QIcon &icon)
Qt::KeyboardModifiers modifiers() const const
int toolTipTextFormat
how to handle the text format of the tooltip subtext:
Q_INVOKABLE void prepareContextualActions()
Should be called before retrieving any action to ensure contents are up to date.
QQuickItem * parentItem() const const
ShortcutFocusReason
Plasma::Types::ConstraintHints constraintHints
The hints that the applet gives to its constraint, such as asking to fill all the available space ign...
void userConfiguringChanged(bool configuring)
emitted when the config ui appears or disappears
bool hideOnWindowDeactivate
Whether the dialog should be hidden when the dialog loses focus.
AppletInterface self
Returns the Plasmoid object itself.
QString icon
Icon to represent the plasmoid.
void setActionGroup(QActionGroup *group)
void iconChanged(const QString &icon)
Emitted when the icon name for the applet has changed.
bool isEmpty() const const
QByteArray toUtf8() const const
void immutabilityChanged(Plasma::Types::ImmutabilityType immutable)
Emitted when the immutability changes.
const T & at(int i) const const
Q_SCRIPTABLE CaptureState status()
void setText(const QString &text)
QFuture< void > filter(Sequence &sequence, KeepFunctor filterFunction)
DirectConnection
virtual QVariant rootObject()
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
int indexOfMethod(const char *method) const const
bool failedToLaunch() const
If for some reason, the applet fails to get up on its feet (the library couldn't be loaded,...
Definition: applet.cpp:546
KPluginMetaData metaData
The metadata of the applet.
void trigger()
bool configurationRequired
If true the applet requires manual configuration from the user.
void contextualActionsAboutToShow()
Emitted just before the contextual actions are about to show For instance just before the context men...
Plasma::Types::ImmutabilityType immutability
The immutability of the Corona.
static QVector< KPluginMetaData > findPlugins(const QString &directory, std::function< bool(const KPluginMetaData &)> filter, KPluginMetaDataOption option)
Q_INVOKABLE void setAction(const QString &name, const QString &text, const QString &icon=QString(), const QString &shortcut=QString())
Add an action to the Plasmoid contextual menu.
void setData(const QVariant &userData)
void activated()
Emitted when activation is requested due to, for example, a global keyboard shortcut.
Plasma::Types::BackgroundHints effectiveBackgroundHints
The effective background hints the applet has, internally decided how to mix with userBackgroundHints...
Q_INVOKABLE void setConfigurationRequired(bool needsConfiguring, const QString &reason=QString())
Set this to true if the plasmoid needs to be configured in order to work.
QWindow * windowHandle() const const
bool userConfiguring
True when the user is configuring, for instance when the configuration dialog is open.
void triggered(bool checked)
void popup(const QPoint &p, QAction *atAction)
uint id
Applet id: is unique in the whole Plasma session and will never change across restarts.
int key() const const
const char * constData() const const
This class is exposed to applets in QML as the attached property Plasmoid.
QString associatedApplication
Sets the associated application of this plasmoid, if the plasmoid is representing the "compact" view ...
bool isValid(QStringView ifopt)
void setObjectName(const QString &name)
QPoint globalPos() const const
Location
The Location enumeration describes where on screen an element, such as an Applet or its managing cont...
Definition: plasma.h:158
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
QString toolTipMainText
Main title for the plasmoid tooltip or other means of quick information: it's the same as the title p...
@ UiReadyConstraint
The ui has been completely loaded.
Definition: plasma.h:47
ImmutabilityType
Defines the immutability of items like applets, corona and containments they can be free to modify,...
Definition: plasma.h:235
Plasma::Types::Location location
Location for the plasmoid.
WId winId() const const
void moveTo(int x, int y)
bool immutable
Whether the Corona is immutable.
static QString eventToString(QEvent *event)
Turns a mouse or wheel event into a string suitable for a ContainmentActions.
int apiVersion
The QML root object defined in the applet main.qml will be direct child of an AppletInterface instanc...
void titleChanged(const QString &title)
Emitted when the title has changed.
QRegion::const_iterator end() const const
QString configurationRequiredReason
Reason why the manual user configuration is required.
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
void setSeparator(bool b)
void setFocus(bool)
Plasma::Types::ContainmentDisplayHints containmentDisplayHints
Type of the containment we're in.
The base class for plugins that provide backgrounds and applet grouping containers.
Definition: containment.h:45
virtual QList< QAction * > contextualActions()
Implement this to provide a list of actions that can be added to another menu for example,...
QObject nativeInterface
An interface to the native C++ plasmoid, if implemented.
QHash< QString, ContainmentActions * > & containmentActions()
QKeySequence globalShortcut
The global shortcut to activate the plasmoid.
void backgroundHintsChanged()
Emitted when the background hints have changed.
The base Applet class.
Definition: applet.h:71
WA_DeleteOnClose
void screenChanged(int newScreen)
This signal indicates that a containment has been associated (or dissociated) with a physical screen.
Q_INVOKABLE QStringList downloadedFiles() const
QVariant property(const char *name) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Sep 26 2023 04:05:56 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.