Libplasma

containmentitem.cpp
1/*
2 SPDX-FileCopyrightText: 2008 Chani Armitage <chani@kde.org>
3 SPDX-FileCopyrightText: 2008, 2009 Aaron Seigo <aseigo@kde.org>
4 SPDX-FileCopyrightText: 2010 Marco Martin <mart@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include <algorithm>
10
11#include "appletquickitem_p.h"
12#include "containmentitem.h"
13#include "dropmenu.h"
14#include "sharedqmlengine.h"
15#include "wallpaperitem.h"
16
17#include <QApplication>
18#include <QClipboard>
19#include <QMimeData>
20#include <QQmlExpression>
21#include <QQmlProperty>
22#include <QScreen>
23#include <QVersionNumber>
24
25#include <KAcceleratorManager>
26#include <KAuthorized>
27#include <KLocalizedString>
28#include <KNotification>
29#include <KUrlMimeData>
30#include <QDebug>
31#include <QMimeDatabase>
32
33#include <KIO/DropJob>
34#include <KIO/MimetypeJob>
35#include <KIO/TransferJob>
36
37#include <Plasma/ContainmentActions>
38#include <Plasma/Corona>
39#include <Plasma/PluginLoader>
40#include <plasma.h>
41
42#include <KPackage/Package>
43#include <KPackage/PackageJob>
44#include <KPackage/PackageLoader>
45
46ContainmentItem::ContainmentItem(QQuickItem *parent)
47 : PlasmoidItem(parent)
48 , m_wallpaperItem(nullptr)
49 , m_wheelDelta(0)
50{
51 setAcceptedMouseButtons(Qt::AllButtons);
52}
53
54void ContainmentItem::classBegin()
55{
57 m_containment = static_cast<Plasma::Containment *>(applet());
58 if (!m_containment) {
59 // This can happen only if the client QML code declares a PlasmoidItem somewhere else than the root object
60 return;
61 }
62
63 connect(m_containment.data(), &Plasma::Containment::appletAboutToBeRemoved, this, &ContainmentItem::appletRemovedForward);
64 connect(m_containment.data(), &Plasma::Containment::appletAboutToBeAdded, this, &ContainmentItem::appletAddedForward);
65
66 connect(m_containment->corona(), &Plasma::Corona::editModeChanged, this, &ContainmentItem::editModeChanged);
67}
68
69void ContainmentItem::init()
70{
71 PlasmoidItem::init();
72 if (!m_containment) {
73 // This can happen only if the client QML code declares a PlasmoidItem somewhere else than the root object
74 return;
75 }
76
77 for (auto *applet : m_containment->applets()) {
78 auto appletGraphicObject = AppletQuickItem::itemForApplet(applet);
79 m_plasmoidItems.append(appletGraphicObject);
80 connect(appletGraphicObject, &QObject::destroyed, this, [this, appletGraphicObject]() {
81 m_plasmoidItems.removeAll(appletGraphicObject);
82 });
83 }
84 if (!m_plasmoidItems.isEmpty()) {
85 Q_EMIT appletsChanged();
86 }
87
88 // Create the ToolBox
89 if (m_containment && m_containment->isContainment()) {
91 if (m_containment->containmentType() == Plasma::Containment::Type::Desktop) {
92 defaults = KConfigGroup(KSharedConfig::openConfig(m_containment->corona()->kPackage().filePath("defaults")), QStringLiteral("Desktop"));
93 } else if (m_containment->containmentType() == Plasma::Containment::Type::Panel) {
94 defaults = KConfigGroup(KSharedConfig::openConfig(m_containment->corona()->kPackage().filePath("defaults")), QStringLiteral("Panel"));
95 }
96
97 if (defaults.isValid()) {
98 KPackage::Package pkg = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Generic"));
99 pkg.setDefaultPackageRoot(QStringLiteral("plasma/packages"));
100
101 if (defaults.isValid()) {
102 pkg.setPath(defaults.readEntry("ToolBox", "org.kde.desktoptoolbox"));
103 } else {
104 pkg.setPath(QStringLiteral("org.kde.desktoptoolbox"));
105 }
106
107 if (pkg.metadata().isValid() && !pkg.metadata().isHidden()) {
108 if (pkg.isValid()) {
109 QObject *containmentGraphicObject = qmlObject()->rootObject();
110
111 QVariantHash toolboxProperties;
112 toolboxProperties[QStringLiteral("parent")] = QVariant::fromValue(this);
113 QObject *toolBoxObject = qmlObject()->createObjectFromSource(pkg.fileUrl("mainscript"), nullptr, toolboxProperties);
114 if (toolBoxObject && containmentGraphicObject) {
115 connect(this, &QObject::destroyed, [toolBoxObject]() {
116 delete toolBoxObject;
117 });
118 containmentGraphicObject->setProperty("toolBox", QVariant::fromValue(toolBoxObject));
119 }
120 } else {
121 qWarning() << "Could not load toolbox package." << pkg.path();
122 }
123 } else {
124 qWarning() << "Toolbox not loading, toolbox package is either invalid or disabled.";
125 }
126 }
127 }
128
129 connect(m_containment.data(), &Plasma::Containment::wallpaperPluginChanged, this, &ContainmentItem::loadWallpaper);
130
131 connect(m_containment, &Plasma::Containment::internalActionsChanged, this, &ContainmentItem::actionsChanged);
132 connect(m_containment, &Plasma::Containment::contextualActionsChanged, this, &ContainmentItem::actionsChanged);
133}
134
135PlasmaQuick::AppletQuickItem *ContainmentItem::itemFor(Plasma::Applet *applet) const
136{
137 if (!applet) {
138 return nullptr;
139 }
140 if (applet->containment() == m_containment) {
141 return AppletQuickItem::itemForApplet(applet);
142 } else {
143 return nullptr;
144 }
145}
146
147Plasma::Applet *ContainmentItem::createApplet(const QString &plugin, const QVariantList &args, const QRectF &geom)
148{
149 return m_containment->createApplet(plugin, args, geom);
150}
151
152void ContainmentItem::setAppletArgs(Plasma::Applet *applet, const QString &mimetype, const QVariant &data)
153{
154 if (!applet) {
155 return;
156 }
157
158 PlasmoidItem *plasmoidItem = qobject_cast<PlasmoidItem *>(AppletQuickItem::itemForApplet(applet));
159
160 if (plasmoidItem) {
161 Q_EMIT plasmoidItem->externalData(mimetype, data);
162 }
163}
164
166{
167 QObject *desktop = nullptr;
168 const auto lst = m_containment->corona()->containments();
169 for (Plasma::Containment *c : lst) {
170 ContainmentItem *contInterface = qobject_cast<ContainmentItem *>(AppletQuickItem::itemForApplet(c));
171
172 if (contInterface && contInterface->isVisible()) {
173 QWindow *w = contInterface->window();
174 if (w && w->geometry().contains(QPoint(window()->x(), window()->y()) + QPoint(x, y))) {
175 if (c->containmentType() == Plasma::Containment::Type::CustomEmbedded) {
176 continue;
177 }
178 if (c->containmentType() == Plasma::Containment::Type::Desktop) {
179 desktop = contInterface;
180 } else {
181 return contInterface;
182 }
183 }
184 }
185 }
186 return desktop;
187}
188
190{
191 PlasmoidItem *appletItem = qobject_cast<PlasmoidItem *>(AppletQuickItem::itemForApplet(applet));
192 if (!appletItem || !appletItem->window() || !window()) {
193 return QPointF();
194 }
195
196 // x,y in absolute screen coordinates of current view
197 QPointF pos = appletItem->mapToScene(QPointF(x, y));
198 pos = QPointF(pos + appletItem->window()->geometry().topLeft());
199 // return the coordinate in the relative view's coords
200 return pos - window()->geometry().topLeft();
201}
202
204{
205 PlasmoidItem *appletItem = qobject_cast<PlasmoidItem *>(AppletQuickItem::itemForApplet(applet));
206 if (!appletItem || !appletItem->window() || !window()) {
207 return QPointF();
208 }
209
210 // x,y in absolute screen coordinates of current view
211 QPointF pos(x, y);
212 pos = QPointF(pos + window()->geometry().topLeft());
213 // the coordinate in the relative view's coords
214 pos = pos - appletItem->window()->geometry().topLeft();
215 // make it relative to applet coords
216 return pos - appletItem->mapToScene(QPointF(0, 0));
217}
218
220{
221 QRegion reg;
222 int screenId = screen();
223 if (screenId > -1 && m_containment->corona()) {
224 reg = m_containment->corona()->availableScreenRegion(screenId);
225 }
226
227 if (!reg.isEmpty()) {
228 // make it relative
229 QRect geometry = m_containment->corona()->screenGeometry(screenId);
230 reg.translate(-geometry.topLeft());
231 } else {
232 reg = QRect(0, 0, width(), height());
233 }
234
235 const QRect rect(qBound(reg.boundingRect().left(), x, reg.boundingRect().right() + 1 - w),
236 qBound(reg.boundingRect().top(), y, reg.boundingRect().bottom() + 1 - h),
237 w,
238 h);
239 QRect tempRect(rect);
240
241 // To place the rectangle, the idea is the following:
242 // Each QRegion is the union of some disjoint rectangles. We can imagine
243 // drawing a vertical line at the left and right sides of each rectangle, and
244 // an horizontal line at the top and bottom sides of each rectangle. We thus
245 // construct a grid (or partition) where each cell is either entirely within
246 // the QRegion or entirely outside.
247 // We now start "snapping" the given rectangle to all intersections of horizontal
248 // and vertical lines, until we find a place where the rectangle fits entirely.
249 // We test by snapping at all possible corners of the rectangle, to test
250 // all possibilities.
251 // We do this beginning from the closes grid element to the rect, and then
252 // we increase the distance. This allows us to find the smallest distance we
253 // have to displace the rectangle to fit in the QRegion.
254 // Note that we employ some performance optimizations, such as only left-snapping
255 // to vertical lines drawn from left-corners of rectangles, only right-snapping
256 // to vertical lines drawn from right-corners, and so on.
257
258 // We start by reading the left, right, top and bottom values of all QRegion rects.
259 QSet<int> leftAlignedGrid = {rect.left()};
260 QSet<int> rightAlignedGrid = {rect.right()};
261 QSet<int> topAlignedGrid = {rect.top()};
262 QSet<int> bottomAlignedGrid = {rect.bottom()};
263 for (QRegion::const_iterator it = reg.begin(); it != reg.end(); ++it) {
264 QRect r = *it;
265 leftAlignedGrid.insert(r.left());
266 rightAlignedGrid.insert(r.right());
267 topAlignedGrid.insert(r.top());
268 bottomAlignedGrid.insert(r.bottom());
269 }
270
271 // We then join them together, sorting them so that they
272 // are from the closes to the furthest away from the rectangle.
273 QList<int> horizontalGrid = (leftAlignedGrid + rightAlignedGrid).values();
274 std::sort(horizontalGrid.begin(), horizontalGrid.end(), [&leftAlignedGrid, &rightAlignedGrid, rect](int a, int b) {
275 if (leftAlignedGrid.contains(a)) {
276 a = std::abs(a - rect.left());
277 } else {
278 a = std::abs(a - rect.right());
279 }
280 if (leftAlignedGrid.contains(b)) {
281 b = std::abs(b - rect.left());
282 } else {
283 b = std::abs(b - rect.right());
284 }
285 return a < b;
286 });
287 QList<int> verticalGrid = (topAlignedGrid + bottomAlignedGrid).values();
288 std::sort(verticalGrid.begin(), verticalGrid.end(), [&topAlignedGrid, &bottomAlignedGrid, rect](int a, int b) {
289 if (topAlignedGrid.contains(a)) {
290 a = std::abs(a - rect.top());
291 } else {
292 a = std::abs(a - rect.bottom());
293 }
294 if (topAlignedGrid.contains(b)) {
295 b = std::abs(b - rect.top());
296 } else {
297 b = std::abs(b - rect.bottom());
298 }
299 return a < b;
300 });
301
302 // We then move the rect to each grid intersection, and check
303 // if the rect fits in the QRegion. If so, we return it.
304 for (int horizontal : horizontalGrid) {
305 for (int vertical : verticalGrid) {
306 // Technically speaking a value could be in both left/right or
307 // top/bottom-aligned lists and we should check both possibilities;
308 // Instead, I'm only checking the first one to keep the code simple,
309 // since such occourrence is unlikely.
310 if (leftAlignedGrid.contains(horizontal)) {
311 tempRect.moveLeft(horizontal);
312 } else {
313 tempRect.moveRight(horizontal);
314 }
315 if (topAlignedGrid.contains(vertical)) {
316 tempRect.moveTop(vertical);
317 } else {
318 tempRect.moveBottom(vertical);
319 }
320 if (reg.intersected(tempRect) == tempRect) {
321 return tempRect.topLeft();
322 }
323 }
324 }
325
326 // The rectangle can't fit in the QRegion in any possible way. We
327 // return the given value.
328 return rect.topLeft();
329}
330
332{
333 if (globalPos.isNull()) {
334 return;
335 }
336
338 mousePressEvent(&me);
339}
340
341void ContainmentItem::processMimeData(QObject *mimeDataProxy, int x, int y, KIO::DropJob *dropJob)
342{
343 QMimeData *mime = qobject_cast<QMimeData *>(mimeDataProxy);
344 if (mime) {
345 processMimeData(mime, x, y, dropJob);
346 } else {
347 processMimeData(mimeDataProxy->property("mimeData").value<QMimeData *>(), x, y, dropJob);
348 }
349}
350
351void ContainmentItem::processMimeData(QMimeData *mimeData, int x, int y, KIO::DropJob *dropJob)
352{
353 if (!mimeData) {
354 return;
355 }
356
357 if (m_dropMenu) {
358 if (dropJob) {
359 dropJob->kill();
360 }
361 return;
362 }
363 m_dropMenu = QPointer<DropMenu>(new DropMenu(dropJob, mapToGlobal(QPoint(x, y)).toPoint(), this));
364
365 // const QMimeData *mimeData = data;
366
367 qDebug() << "Arrived mimeData" << mimeData->urls() << mimeData->formats() << "at" << x << ", " << y;
368
369 // Catch drops from a Task Manager and convert to usable URL.
370 if (!mimeData->hasUrls() && mimeData->hasFormat(QStringLiteral("text/x-orgkdeplasmataskmanager_taskurl"))) {
371 QList<QUrl> urls = {QUrl(QString::fromUtf8(mimeData->data(QStringLiteral("text/x-orgkdeplasmataskmanager_taskurl"))))};
372 mimeData->setUrls(urls);
373 }
374 if (mimeData->hasFormat(QStringLiteral("text/x-plasmoidinstanceid"))) {
375 QString data = QString::fromUtf8(mimeData->data(QStringLiteral("text/x-plasmoidinstanceid")));
376 const QStringList splitData = data.split(QLatin1Char(':'), Qt::SkipEmptyParts);
377 if (splitData.count() != 2)
378 return;
379
380 bool ok1, ok2;
381 uint containmentId = splitData[0].toInt(&ok1);
382 uint appletId = splitData[1].toInt(&ok2);
383 if (!ok1 || !ok2)
384 return;
385
386 auto corona = m_containment->corona();
387 auto containments = corona->containments();
388 for (auto containment : containments) {
389 if (containment->id() == containmentId) {
390 for (auto applet : containment->applets()) {
391 if (applet->id() == appletId) {
392 PlasmaQuick::AppletQuickItem *appletItem = PlasmaQuick::AppletQuickItem::itemForApplet(applet);
393 // Set parent to null and free up from old container only if we are dropping on a different containment
394 if (applet->containment() != m_containment) {
395 appletItem->setParentItem(nullptr);
396 }
397 m_containment->addApplet(applet, QRect(x, y, -1, -1));
398 break;
399 }
400 }
401 break;
402 }
403 }
404 delete m_dropMenu.data();
405 } else if (mimeData->hasFormat(QStringLiteral("text/x-plasmoidservicename"))) {
406 QString data = QString::fromUtf8(mimeData->data(QStringLiteral("text/x-plasmoidservicename")));
407 const QStringList appletNames = data.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
408 for (const QString &appletName : appletNames) {
409 qDebug() << "adding" << appletName;
410 metaObject()->invokeMethod(this,
411 "createApplet",
413 Q_ARG(QString, appletName),
414 Q_ARG(QVariantList, QVariantList()),
415 Q_ARG(QRectF, QRectF(x, y, -1, -1)));
416 }
417 delete m_dropMenu.data();
418 } else if (mimeData->hasUrls()) {
419 // TODO: collect the mimetypes of available script engines and offer
420 // to create widgets out of the matching URLs, if any
421 const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(mimeData);
422 if (urls.isEmpty()) {
423 delete m_dropMenu;
424 return;
425 }
426 m_dropMenu->setUrls(urls);
427
428 if (!urls.at(0).isLocalFile()) {
430 }
431
432 QMimeDatabase db;
433 QMimeType firstMimetype = db.mimeTypeForUrl(urls.at(0));
434 for (const QUrl &url : urls) {
435 if (firstMimetype != db.mimeTypeForUrl(url)) {
436 m_dropMenu->setMultipleMimetypes(true);
437 break;
438 }
439 }
440
441 // It may be a directory or a file, let's stat
443 KIO::MimetypeJob *job = KIO::mimetype(m_dropMenu->urls().at(0), flags);
444
445 QObject::connect(job, &KJob::result, this, &ContainmentItem::dropJobResult);
446 QObject::connect(job, &KIO::MimetypeJob::mimeTypeFound, this, &ContainmentItem::mimeTypeRetrieved);
447
448 } else {
449 bool deleteDropMenu = true;
450
451 const QStringList formats = mimeData->formats();
453 QHash<QString, QString> pluginFormats;
454
455 for (const QString &format : formats) {
456 const auto plugins = Plasma::PluginLoader::self()->listAppletMetaDataForMimeType(format);
457
458 for (const auto &plugin : plugins) {
459 if (seenPlugins.contains(plugin.pluginId())) {
460 continue;
461 }
462
463 seenPlugins.insert(plugin.pluginId(), plugin);
464 pluginFormats.insert(plugin.pluginId(), format);
465 }
466 }
467 // qDebug() << "Mimetype ..." << formats << seenPlugins.keys() << pluginFormats.values();
468
469 QString selectedPlugin;
470
471 if (seenPlugins.isEmpty()) {
472 // do nothing
473 // directly create if only one offer only if the containment didn't pass an existing plugin
474 } else if (seenPlugins.count() == 1) {
475 selectedPlugin = seenPlugins.constBegin().key();
476 Plasma::Applet *applet = createApplet(selectedPlugin, QVariantList(), QRect(x, y, -1, -1));
477 setAppletArgs(applet, pluginFormats[selectedPlugin], mimeData->data(pluginFormats[selectedPlugin]));
478
479 } else {
480 QHash<QAction *, QString> actionsToPlugins;
481 for (const auto &info : std::as_const(seenPlugins)) {
482 QAction *action;
483 if (!info.iconName().isEmpty()) {
484 action = new QAction(QIcon::fromTheme(info.iconName()), info.name(), m_dropMenu);
485 } else {
486 action = new QAction(info.name(), m_dropMenu);
487 }
488 m_dropMenu->addAction(action);
489 action->setData(info.pluginId());
490 connect(action, &QAction::triggered, this, [this, x, y, mimeData, action]() {
491 const QString selectedPlugin = action->data().toString();
492 Plasma::Applet *applet = createApplet(selectedPlugin, QVariantList(), QRect(x, y, -1, -1));
493 setAppletArgs(applet, selectedPlugin, mimeData->data(selectedPlugin));
494 });
495
496 actionsToPlugins.insert(action, info.pluginId());
497 }
498 m_dropMenu->show();
499 deleteDropMenu = false;
500 }
501
502 if (deleteDropMenu) {
503 // in case m_dropMenu has not been shown
504 delete m_dropMenu.data();
505 }
506 }
507}
508
509void ContainmentItem::clearDataForMimeJob(KIO::Job *job)
510{
511 QObject::disconnect(job, nullptr, this, nullptr);
512 job->kill();
513
514 m_dropMenu->show();
515
516 if (!m_dropMenu->urls().at(0).isLocalFile()) {
518 }
519}
520
521void ContainmentItem::dropJobResult(KJob *job)
522{
523 if (job->error()) {
524 qDebug() << "ERROR" << job->error() << ' ' << job->errorString();
525 clearDataForMimeJob(dynamic_cast<KIO::Job *>(job));
526 }
527}
528
529void ContainmentItem::mimeTypeRetrieved(KIO::Job *job, const QString &mimetype)
530{
531 qDebug() << "Mimetype Job returns." << mimetype;
532
533 KIO::TransferJob *tjob = dynamic_cast<KIO::TransferJob *>(job);
534 if (!tjob) {
535 qDebug() << "job should be a TransferJob, but isn't";
536 clearDataForMimeJob(job);
537 return;
538 }
539
541 if (mimetype.isEmpty() && appletList.isEmpty()) {
542 clearDataForMimeJob(job);
543 qDebug() << "No applets found matching the url (" << tjob->url() << ") or the mimetype (" << mimetype << ")";
544 return;
545 } else {
546 qDebug() << "Received a suitable dropEvent at " << m_dropMenu->dropPoint();
547 qDebug() << "Bailing out. Cannot find associated dropEvent related to the TransferJob";
548
549 qDebug() << "Creating menu for: " << mimetype;
550
552
553 QList<KPluginMetaData> wallpaperList;
554
555 if (m_containment->containmentType() != Plasma::Containment::Type::Panel
556 && m_containment->containmentType() != Plasma::Containment::Type::CustomPanel) {
557 if (m_wallpaperItem && m_wallpaperItem->supportsMimetype(mimetype)) {
558 wallpaperList << m_wallpaperItem->kPackage().metadata();
559 } else {
560 wallpaperList = WallpaperItem::listWallpaperMetadataForMimetype(mimetype);
561 }
562 }
563
564 const bool isPlasmaPackage = (mimetype == QLatin1String("application/x-plasma"));
565
566 if ((!appletList.isEmpty() || !wallpaperList.isEmpty() || isPlasmaPackage) && !m_dropMenu->isMultipleMimetypes()) {
567 QAction *installPlasmaPackageAction = nullptr;
568 if (isPlasmaPackage) {
569 QAction *action = new QAction(i18n("Plasma Package"), m_dropMenu);
570 action->setSeparator(true);
571 m_dropMenu->addAction(action);
572
573 installPlasmaPackageAction = new QAction(QIcon::fromTheme(QStringLiteral("application-x-plasma")), i18n("Install"), m_dropMenu);
574 m_dropMenu->addAction(installPlasmaPackageAction);
575
576 const QString &packagePath = tjob->url().toLocalFile();
577 connect(installPlasmaPackageAction, &QAction::triggered, this, [this, packagePath]() {
578 using namespace KPackage;
579
580 PackageJob *job = PackageJob::update(QStringLiteral("Plasma/Applet"), packagePath);
581 connect(job, &KJob::finished, this, [this, packagePath, job]() {
582 auto fail = [](const QString &text) {
583 KNotification::event(QStringLiteral("plasmoidInstallationFailed"),
584 i18n("Package Installation Failed"),
585 text,
586 QStringLiteral("dialog-error"),
588 QStringLiteral("plasma_workspace"));
589 };
590
591 // if the applet is already installed, just add it to the containment
592 if (job->error() != KJob::NoError && job->error() != PackageJob::PackageAlreadyInstalledError
593 && job->error() != PackageJob::NewerVersionAlreadyInstalledError) {
594 fail(job->errorText());
595 return;
596 }
597
598 const Package package = job->package();
599 if (!package.isValid() || !package.metadata().isValid()) {
600 fail(i18n("The package you just dropped is invalid."));
601 return;
602 }
603
604 createApplet(package.metadata().pluginId(), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
605 });
606 });
607 }
608
609 QAction *action = new QAction(i18n("Widgets"), m_dropMenu);
610 action->setSeparator(true);
611 m_dropMenu->addAction(action);
612
613 for (const auto &info : std::as_const(appletList)) {
614 const QString actionText = i18nc("Add widget", "Add %1", info.name());
615 QAction *action = new QAction(actionText, m_dropMenu);
616 if (!info.iconName().isEmpty()) {
617 action->setIcon(QIcon::fromTheme(info.iconName()));
618 }
619 m_dropMenu->addAction(action);
620 action->setData(info.pluginId());
621 const QUrl url = tjob->url();
622 connect(action, &QAction::triggered, this, [this, action, mimetype, url]() {
623 Plasma::Applet *applet = createApplet(action->data().toString(), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
624 setAppletArgs(applet, mimetype, url);
625 });
626 }
627 {
628 QAction *action = new QAction(i18nc("Add icon widget", "Add Icon"), m_dropMenu);
629 m_dropMenu->addAction(action);
630 action->setData(QStringLiteral("org.kde.plasma.icon"));
631 const QUrl url = tjob->url();
632 connect(action, &QAction::triggered, this, [this, action, mimetype, url]() {
633 Plasma::Applet *applet = createApplet(action->data().toString(), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
634 setAppletArgs(applet, mimetype, url);
635 });
636 }
637
638 QHash<QAction *, QString> actionsToWallpapers;
639 if (!wallpaperList.isEmpty()) {
640 QAction *action = new QAction(i18n("Wallpaper"), m_dropMenu);
641 action->setSeparator(true);
642 m_dropMenu->addAction(action);
643
645 for (const auto &info : std::as_const(appletList)) {
646 sorted.insert(info.name(), info);
647 }
648
649 for (const KPluginMetaData &info : std::as_const(wallpaperList)) {
650 const QString actionText = i18nc("Set wallpaper", "Set %1", info.name());
651 QAction *action = new QAction(actionText, m_dropMenu);
652 if (!info.iconName().isEmpty()) {
653 action->setIcon(QIcon::fromTheme(info.iconName()));
654 }
655 m_dropMenu->addAction(action);
656 actionsToWallpapers.insert(action, info.pluginId());
657 const QUrl url = tjob->url();
658 connect(action, &QAction::triggered, this, [this, info, url]() {
659 // Change wallpaper plugin if it's not the current one
660 if (containment()->wallpaperPlugin() != info.pluginId()) {
661 containment()->setWallpaperPlugin(info.pluginId());
662 }
663
664 // set wallpapery stuff
665 if (m_wallpaperItem && url.isValid()) {
666 m_wallpaperItem->requestOpenUrl(url);
667 }
668 });
669 }
670 }
671 // case in which we created the menu ourselves, just the "fetching type entry, directly create the icon applet
672 } else if (!m_dropMenu->isDropjobMenu()) {
673 Plasma::Applet *applet = createApplet(QStringLiteral("org.kde.plasma.icon"), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
674 setAppletArgs(applet, mimetype, tjob->url());
675 }
676 clearDataForMimeJob(tjob);
677 }
678}
679
680void ContainmentItem::appletAddedForward(Plasma::Applet *applet, const QRectF &geometryHint)
681{
682 if (!applet) {
683 return;
684 }
685 PlasmoidItem *appletGraphicObject = qobject_cast<PlasmoidItem *>(AppletQuickItem::itemForApplet(applet));
686 m_plasmoidItems.append(appletGraphicObject);
687 connect(appletGraphicObject, &QObject::destroyed, this, [this, appletGraphicObject]() {
688 m_plasmoidItems.removeAll(appletGraphicObject);
689 });
690
691 QPointF removalPosition = appletGraphicObject->m_positionBeforeRemoval;
692 QPointF position = appletGraphicObject->position();
693
694 if (geometryHint.x() > 0 || geometryHint.y() > 0) {
695 position = geometryHint.topLeft();
696 if (geometryHint.width() > 0 && geometryHint.height() > 0) {
697 appletGraphicObject->setSize(geometryHint.size());
698 }
699 } else if (removalPosition.x() > 0.0 && removalPosition.y() > 0.0) {
700 position = removalPosition;
701 } else if (position.isNull() && m_containment->containmentType() == Plasma::Containment::Type::Desktop) {
702 // If no position was provided, and we're adding an applet to the desktop,
703 // add the applet to the center. This avoids always placing new applets
704 // in the top left corner, which is likely to be covered by something.
705 position = QPointF{width() / 2.0 - appletGraphicObject->width() / 2.0, //
706 height() / 2.0 - appletGraphicObject->height() / 2.0};
707 }
708
709 appletGraphicObject->setX(position.x());
710 appletGraphicObject->setY(position.y());
711}
712
713void ContainmentItem::appletRemovedForward(Plasma::Applet *applet)
714{
715 if (!AppletQuickItem::hasItemForApplet(applet)) {
716 return;
717 }
718 PlasmoidItem *appletGraphicObject = qobject_cast<PlasmoidItem *>(AppletQuickItem::itemForApplet(applet));
719 if (appletGraphicObject) {
720 m_plasmoidItems.removeAll(appletGraphicObject);
721 if (appletGraphicObject->parentItem()) {
722 appletGraphicObject->m_positionBeforeRemoval = appletGraphicObject->mapToItem(this, QPointF());
723 }
724 }
725}
726
727void ContainmentItem::loadWallpaper()
728{
729 if (!m_containment->isContainment()) {
730 return;
731 }
732
733 if (m_containment->containmentType() != Plasma::Containment::Type::Desktop && m_containment->containmentType() != Plasma::Containment::Type::Custom) {
734 if (!isLoading()) {
736 }
737 return;
738 }
739
740 auto *oldWallpaper = m_wallpaperItem;
741
742 if (!m_containment->wallpaperPlugin().isEmpty()) {
743 m_wallpaperItem = WallpaperItem::loadWallpaper(this);
744 }
745
746 if (m_wallpaperItem) {
747 m_wallpaperItem->setZ(-1000);
748 // Qml seems happier if the parent gets set in this way
749 m_wallpaperItem->setProperty("parent", QVariant::fromValue(this));
750
751 if (isLoading()) {
752 connect(
753 m_wallpaperItem,
754 &WallpaperItem::isLoadingChanged,
755 this,
756 [this]() {
757 if (!isLoading()) {
759 }
760 },
762 } else {
764 }
765
766 // set anchors
767 QQmlExpression expr(qmlObject()->engine()->rootContext(), m_wallpaperItem, QStringLiteral("parent"));
768 QQmlProperty prop(m_wallpaperItem, QStringLiteral("anchors.fill"));
769 prop.write(expr.evaluate());
770 }
771 m_containment->setProperty("wallpaperGraphicsObject", QVariant::fromValue(m_wallpaperItem));
772 delete oldWallpaper;
773
774 Q_EMIT wallpaperItemChanged();
775}
776
777// PROTECTED--------------------
778
779void ContainmentItem::mouseReleaseEvent(QMouseEvent *event)
780{
781 event->setAccepted(m_containment->containmentActions().contains(Plasma::ContainmentActions::eventToString(event)));
782}
783
784void ContainmentItem::mousePressEvent(QMouseEvent *event)
785
786{
787 // even if the menu is executed synchronously, other events may be processed
788 // by the qml incubator when plasma is loading, so we need to guard there
789 if (m_contextMenu) {
790 m_contextMenu->close();
791 for (const auto actions = m_contextMenu->actions(); auto action : actions) {
792 if (action->menu()) {
793 action->menu()->disconnect(m_contextMenu.get());
794 }
795 }
796 m_contextMenu->disconnect(m_containment);
797 m_contextMenu->clear();
798 }
799
801 Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
802
803 if (!plugin) {
804 event->setAccepted(false);
805 return;
806 }
807
808 const auto contextualActions = plugin->contextualActions();
809 if (contextualActions.empty()) {
810 event->setAccepted(false);
811 return;
812 }
813
814 // the plugin can be a single action or a context menu
815 // Don't have an action list? execute as single action
816 // and set the event position as action data
817 if (contextualActions.length() == 1) {
818 QAction *action = contextualActions.at(0);
819 action->setData(event->pos());
820 action->trigger();
821 event->accept();
822 return;
823 }
824
825 // FIXME: very inefficient appletAt() implementation
826 Plasma::Applet *applet = nullptr;
827 for (QObject *appletObject : std::as_const(m_plasmoidItems)) {
828 if (PlasmoidItem *ai = qobject_cast<PlasmoidItem *>(appletObject)) {
829 if (ai->isVisible() && ai->contains(ai->mapFromItem(this, event->position()))) {
830 applet = ai->applet();
831 break;
832 } else {
833 ai = nullptr;
834 }
835 }
836 }
837 // qDebug() << "Invoking menu for applet" << applet;
838
839 if (!m_contextMenu) {
840 m_contextMenu.reset(new QMenu);
841 m_contextMenu->setAttribute(Qt::WA_TranslucentBackground);
842 // this is a workaround where Qt now creates the menu widget
843 // in .exec before oxygen can polish it and set the following attribute
844 // end workaround
845 if (m_contextMenu->winId()) {
846 m_contextMenu->windowHandle()->setTransientParent(window());
847 }
848 m_contextMenu->setAttribute(Qt::WA_DeleteOnClose, false);
849 KAcceleratorManager::manage(m_contextMenu.get());
850 }
851
852 Q_EMIT m_containment->contextualActionsAboutToShow();
853
854 if (applet) {
856 addAppletActions(m_contextMenu.get(), applet, event);
857 } else {
858 addContainmentActions(m_contextMenu.get(), event);
859 }
860
861 // this is a workaround where Qt will fail to realize a mouse has been released
862
863 // this happens if a window which does not accept focus spawns a new window that takes focus and X grab
864 // whilst the mouse is depressed
865 // https://bugreports.qt.io/browse/QTBUG-59044
866 // this causes the next click to go missing
867
868 // by releasing manually we avoid that situation
869 auto ungrabMouseHack = [this]() {
870 if (window() && window()->mouseGrabberItem()) {
872 }
873 };
874
875 // pre 5.8.0 QQuickWindow code is "item->grabMouse(); sendEvent(item, mouseEvent)"
876 // post 5.8.0 QQuickWindow code is sendEvent(item, mouseEvent); item->grabMouse()
877 if (QVersionNumber::fromString(QLatin1String(qVersion())) > QVersionNumber(5, 8, 0)) {
878 QTimer::singleShot(0, this, ungrabMouseHack);
879 } else {
880 ungrabMouseHack();
881 }
882 // end workaround
883
884 QPoint pos = event->globalPosition().toPoint();
885 if (window() && m_containment->containmentType() == Plasma::Containment::Type::Panel) {
886 m_contextMenu->adjustSize();
887
888 if (QScreen *screen = window()->screen()) {
889 const QRect geo = screen->availableGeometry();
890
891 pos = QPoint(qBound(geo.left(), pos.x(), geo.right() + 1 - m_contextMenu->width()),
892 qBound(geo.top(), pos.y(), geo.bottom() + 1 - m_contextMenu->height()));
893 }
894 }
895
896 if (m_contextMenu->isEmpty()) {
897 m_contextMenu.reset();
898 event->accept();
899 return;
900 }
901
902 // Bug 344205 keep panel visible while menu is open
903 const auto oldStatus = m_containment->status();
904 m_containment->setStatus(Plasma::Types::RequiresAttentionStatus);
905
906 connect(m_contextMenu.get(), &QMenu::aboutToHide, m_containment, [this, oldStatus] {
907 m_containment->setStatus(oldStatus);
908 });
909
910 for (auto action : m_contextMenu->actions()) {
911 if (action->menu()) {
912 connect(action->menu(), &QMenu::aboutToShow, m_contextMenu.get(), [this, action] {
913 if (action->menu()->windowHandle()) {
914 // Need to add the transient parent otherwise Qt will create a new toplevel
915 action->menu()->windowHandle()->setTransientParent(m_contextMenu->windowHandle());
916 }
917 });
918 }
919 }
920
921 m_contextMenu->popup(pos);
922 event->setAccepted(true);
923}
924
925void ContainmentItem::wheelEvent(QWheelEvent *event)
926{
928 Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
929
930 if (!plugin) {
931 event->setAccepted(false);
932 return;
933 }
934
935 if (std::abs(event->angleDelta().x()) > std::abs(event->angleDelta().y())) {
936 m_wheelDelta += event->angleDelta().x();
937 } else {
938 m_wheelDelta += event->angleDelta().y();
939 }
940
941 // Angle delta 120 for common "one click"
942 // See: https://doc.qt.io/qt-5/qml-qtquick-wheelevent.html#angleDelta-prop
943 while (m_wheelDelta >= 120) {
944 m_wheelDelta -= 120;
945 plugin->performPreviousAction();
946 }
947 while (m_wheelDelta <= -120) {
948 m_wheelDelta += 120;
949 plugin->performNextAction();
950 }
951}
952
953void ContainmentItem::keyPressEvent(QKeyEvent *event)
954{
956 if (event->isAccepted()) {
957 return;
958 }
959
960 if (event->key() == Qt::Key_Menu) {
961 QPointF localPos;
962 auto focusedItem = window()->activeFocusItem();
963 if (focusedItem) {
964 localPos = focusedItem->mapToItem(this, QPointF(0, 0));
965 }
966
968 mousePressEvent(&me);
969 event->accept();
970 }
971}
972
973void ContainmentItem::addAppletActions(QMenu *desktopMenu, Plasma::Applet *applet, QEvent *event)
974{
975 const auto listActions = applet->contextualActions();
976 for (QAction *action : listActions) {
977 if (action) {
978 desktopMenu->addAction(action);
979 }
980 }
981
982 if (!applet->failedToLaunch()) {
983 QAction *configureApplet = applet->internalAction(QStringLiteral("configure"));
984 if (configureApplet && configureApplet->isEnabled()) {
985 desktopMenu->addAction(configureApplet);
986 }
987 QAction *appletAlternatives = applet->internalAction(QStringLiteral("alternatives"));
988 if (appletAlternatives && appletAlternatives->isEnabled()) {
989 desktopMenu->addAction(appletAlternatives);
990 }
991 }
992
993 desktopMenu->addSeparator();
994 if (m_containment->containmentType() == Plasma::Containment::Type::Desktop) {
995 auto action = m_containment->corona()->action(QStringLiteral("edit mode"));
996 if (action) {
997 desktopMenu->addAction(action);
998 }
999 } else {
1000 addContainmentActions(desktopMenu, event);
1001 }
1002
1003 if (m_containment->immutability() == Plasma::Types::Mutable
1004 && (m_containment->containmentType() != Plasma::Containment::Type::Panel || m_containment->isUserConfiguring())) {
1005 QAction *closeApplet = applet->internalAction(QStringLiteral("remove"));
1006 // qDebug() << "checking for removal" << closeApplet;
1007 if (closeApplet) {
1008 if (!desktopMenu->isEmpty()) {
1009 desktopMenu->addSeparator();
1010 }
1011
1012 // qDebug() << "adding close action" << closeApplet->isEnabled() << closeApplet->isVisible();
1013 desktopMenu->addAction(closeApplet);
1014 }
1015 }
1016}
1017
1018void ContainmentItem::addContainmentActions(QMenu *desktopMenu, QEvent *event)
1019{
1020 if (m_containment->corona()->immutability() != Plasma::Types::Mutable //
1021 && !KAuthorized::authorizeAction(QStringLiteral("plasma/containment_actions"))) {
1022 // qDebug() << "immutability";
1023 return;
1024 }
1025
1026 // this is what ContainmentPrivate::prepareContainmentActions was
1028 Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
1029
1030 if (!plugin) {
1031 return;
1032 }
1033
1034 if (plugin->containment() != m_containment) {
1035 plugin->setContainment(m_containment);
1036
1037 // now configure it
1038 KConfigGroup cfg(m_containment->corona()->config(), QStringLiteral("ActionPlugins"));
1039 cfg = KConfigGroup(&cfg, QString::number((int)m_containment->containmentType()));
1040 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
1041 plugin->restore(pluginConfig);
1042 }
1043
1044 QList<QAction *> actions = plugin->contextualActions();
1045
1046 if (actions.isEmpty()) {
1047 // it probably didn't bother implementing the function. give the user a chance to set
1048 // a better plugin. note that if the user sets no-plugin this won't happen...
1049 /* clang-format off */
1050 if ((m_containment->containmentType() != Plasma::Containment::Type::Panel
1051 && m_containment->containmentType() != Plasma::Containment::Type::CustomPanel)
1052 && m_containment->internalAction(QStringLiteral("configure"))) { /* clang-format on */
1053 desktopMenu->addAction(m_containment->internalAction(QStringLiteral("configure")));
1054 }
1055 } else {
1056 desktopMenu->addActions(actions);
1057 }
1058
1059 return;
1060}
1061
1062bool ContainmentItem::isLoading() const
1063{
1064 return m_wallpaperItem && m_wallpaperItem->isLoading();
1065}
1066
1067void ContainmentItem::itemChange(ItemChange change, const ItemChangeData &value)
1068{
1069 if (!m_containment) {
1070 // This can happen only if the client QML code declares a PlasmoidItem somewhere else than the root object
1071 PlasmoidItem::itemChange(change, value);
1072 return;
1073 }
1074 if (change == QQuickItem::ItemSceneChange) {
1075 // we have a window: create the representations if needed
1076 if (value.window && !m_containment->wallpaperPlugin().isEmpty()) {
1077 loadWallpaper();
1078 } else if (m_wallpaperItem) {
1079 deleteWallpaperItem();
1080 Q_EMIT wallpaperItemChanged();
1081 }
1082 }
1083
1084 PlasmoidItem::itemChange(change, value);
1085}
1086
1087void ContainmentItem::deleteWallpaperItem()
1088{
1089 m_containment->setProperty("wallpaperGraphicsObject", QVariant());
1090 m_wallpaperItem->deleteLater();
1091 m_wallpaperItem = nullptr;
1092}
1093
1094#include "moc_containmentitem.cpp"
This class is exposed to containments QML as the attached property Plasmoid.
Q_INVOKABLE QObject * containmentItemAt(int x, int y)
Search for a containment at those coordinates.
Q_INVOKABLE QPointF adjustToAvailableScreenRegion(int x, int y, int w, int h) const
Given a geometry, it adjusts it moving it completely inside of the boundaries of availableScreenRegio...
Q_INVOKABLE AppletQuickItem * itemFor(Plasma::Applet *applet) const
Returns the corresponding PlasmoidItem of one of its applets.
Q_INVOKABLE QPointF mapToApplet(Plasma::Applet *applet, int x, int y)
Map coordinates from relative to this containment to relative to the given applet.
Q_INVOKABLE void processMimeData(QMimeData *data, int x, int y, KIO::DropJob *dropJob=nullptr)
Process the mime data arrived to a particular coordinate, either with a drag and drop or paste with m...
Q_INVOKABLE void openContextMenu(const QPointF &globalPos)
Opens the context menu of the Corona.
Q_INVOKABLE QPointF mapFromApplet(Plasma::Applet *applet, int x, int y)
Map coordinates from relative to the given applet to relative to this containment.
static void manage(QWidget *widget, bool programmers_mode=false)
static Q_INVOKABLE bool authorizeAction(const QString &action)
const QUrl & url() const
void mimeTypeFound(KIO::Job *job, const QString &mimeType)
virtual QString errorString() const
int error() const
void result(KJob *job)
void finished(KJob *job)
static KNotification * event(const QString &eventId, const QString &text=QString(), const QPixmap &pixmap=QPixmap(), const NotificationFlags &flags=CloseOnTimeout, const QString &componentName=QString())
Package loadPackage(const QString &packageFormat, const QString &packagePath=QString())
static PackageLoader * self()
void setPath(const QString &path)
QUrl fileUrl(const QByteArray &key, const QString &filename=QString()) const
bool isValid() const
const QString path() const
void setDefaultPackageRoot(const QString &packageRoot)
KPluginMetaData metadata() const
bool isHidden() const
bool isValid() const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QObject * createObjectFromSource(const QUrl &source, QQmlContext *context=nullptr, const QVariantHash &initialProperties=QVariantHash())
Creates and returns an object based on the provided url to a Qml file with the same QQmlEngine and th...
The base Applet class.
Definition applet.h:64
uint id
Applet id: is unique in the whole Plasma session and will never change across restarts.
Definition applet.h:69
void updateConstraints(Constraints constraints=AllConstraints)
Called when any of the geometry constraints have been updated.
Definition applet.cpp:266
QQmlListProperty< QAction > contextualActions
Actions to be added in the plasmoid context menu.
Definition applet.h:195
void contextualActionsChanged(const QList< QAction * > &actions)
Emitted when the list of contextual actions has changed.
Q_INVOKABLE QAction * internalAction(const QString &name) const
Definition applet.cpp:662
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:462
void internalActionsChanged(const QList< QAction * > &actions)
Emitted when the list of internal actions has changed.
@ UiReadyConstraint
The ui has been completely loaded.
Definition applet.h:220
Plasma::Containment * containment
The Containment managing this applet.
Definition applet.h:189
void contextualActionsAboutToShow()
Emitted just before the contextual actions are about to show For instance just before the context men...
The base ContainmentActions class.
virtual QList< QAction * > contextualActions()
Implement this to provide a list of actions that can be added to another menu for example,...
virtual void restore(const KConfigGroup &config)
This method should be called once the plugin is loaded or settings are changed.
virtual void performPreviousAction()
Called when a "previous" action is triggered (e.g.
virtual void performNextAction()
Called when a "next" action is triggered (e.g.
void setContainment(Containment *newContainment)
newContainment the containment the plugin should be associated with.
static QString eventToString(QEvent *event)
Turns a mouse or wheel event into a string suitable for a ContainmentActions.
The base class for plugins that provide backgrounds and applet grouping containers.
Definition containment.h:47
@ Panel
A desktop panel.
@ CustomPanel
A customized desktop panel.
@ CustomEmbedded
A customized containment embedded in another applet.
@ Custom
A containment that is neither a desktop nor a panel but something application specific.
@ Desktop
A desktop containment.
void wallpaperPluginChanged()
Emitted when the wallpaper plugin is changed.
void appletAboutToBeRemoved(Plasma::Applet *applet)
This signal is emitted right before appletRemoved, it can be used to do a preliminary setup on the ap...
void appletAboutToBeAdded(Plasma::Applet *applet, const QRectF &geometryHint)
This signal is emitted right before appletAdded, it can be used to do a preliminary setup on the appl...
void setWallpaperPlugin(const QString &pluginName)
Sets wallpaper plugin.
QList< Plasma::Applet * > applets
List of applets this containment has: the containments KF6: this should be AppletQuickItem *.
Definition containment.h:54
void editModeChanged(bool edit)
emitted when the editMode state changes
QList< KPluginMetaData > listAppletMetaDataForUrl(const QUrl &url)
Returns a list of all known applets associated with a certain URL.
QList< KPluginMetaData > listAppletMetaDataForMimeType(const QString &mimetype)
Returns a list of all known applets associated with a certain mimetype.
static PluginLoader * self()
Return the active plugin loader.
@ Mutable
The item can be modified in any way.
Definition plasma.h:100
@ RequiresAttentionStatus
The Item needs persistent attention.
Definition plasma.h:117
Import Statement
void externalData(const QString &mimetype, const QVariant &data)
somebody else, usually the containment sent some data to the applet
static WallpaperItem * loadWallpaper(ContainmentItem *ContainmentItem)
Instantiate the WallpaperItem for a given containment, using the proper plugin.
static QList< KPluginMetaData > listWallpaperMetadataForMimetype(const QString &mimetype, const QString &formFactor=QString())
Returns a list of all known wallpapers that can accept the given mimetype.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
KIOCORE_EXPORT MimetypeJob * mimetype(const QUrl &url, JobFlags flags=DefaultFlags)
HideProgressInfo
GeoCoordinates geo(const QVariant &location)
KGuiItem defaults()
KCOREADDONS_EXPORT QList< QUrl > urlsFromMimeData(const QMimeData *mimeData, DecodeOptions decodeOptions=PreferKdeUrls, MetaDataMap *metaData=nullptr)
QVariant data() const const
bool isEnabled() const const
void setIcon(const QIcon &icon)
QMenu * menu() const const
void setData(const QVariant &data)
void setSeparator(bool b)
void trigger()
void triggered(bool checked)
MouseButtonRelease
void restoreOverrideCursor()
void setOverrideCursor(const QCursor &cursor)
const Key & key() const const
const_iterator constBegin() const const
bool contains(const Key &key) const const
qsizetype count() const const
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
QIcon fromTheme(const QString &name)
QString name() const const
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
iterator begin()
qsizetype count() const const
iterator end()
bool isEmpty() const const
qsizetype removeAll(const AT &t)
iterator insert(const Key &key, const T &value)
QAction * addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
void aboutToHide()
void aboutToShow()
QAction * addSeparator()
bool isEmpty() const const
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
QByteArray data(const QString &mimeType) const const
virtual QStringList formats() const const
virtual bool hasFormat(const QString &mimeType) const const
bool hasUrls() const const
void setUrls(const QList< QUrl > &urls)
QList< QUrl > urls() const const
QMimeType mimeTypeForUrl(const QUrl &url) const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
void destroyed(QObject *obj)
bool disconnect(const QMetaObject::Connection &connection)
virtual const QMetaObject * metaObject() const const
QVariant property(const char *name) const const
T qobject_cast(QObject *object)
bool setProperty(const char *name, QVariant &&value)
int x() const const
int y() const const
T * data() const const
bool isNull() const const
qreal x() const const
qreal y() const const
void ungrabMouse()
virtual void classBegin() override
Flags flags() const const
virtual void itemChange(ItemChange change, const ItemChangeData &value)
virtual void keyPressEvent(QKeyEvent *event)
QPointF mapToGlobal(const QPointF &point) const const
QPointF mapToItem(const QQuickItem *item, const QPointF &point) const const
QPointF mapToScene(const QPointF &point) const const
void setParentItem(QQuickItem *parent)
void setSize(const QSizeF &size)
bool isVisible() const const
QQuickWindow * window() const const
void setZ(qreal)
QQuickItem * mouseGrabberItem() const const
int bottom() const const
bool contains(const QPoint &point, bool proper) const const
int left() const const
int right() const const
int top() const const
QPoint topLeft() const const
qreal height() const const
QSizeF size() const const
QPointF topLeft() const const
qreal width() const const
qreal x() const const
qreal y() const const
const_iterator begin() const const
QRect boundingRect() const const
const_iterator end() const const
bool isEmpty() const const
void translate(const QPoint &point)
bool contains(const QSet< T > &other) const const
iterator insert(const T &value)
QString fromUtf8(QByteArrayView str)
QString number(double n, char format, int precision)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QueuedConnection
WaitCursor
Key_Menu
NoModifier
AllButtons
SkipEmptyParts
WA_TranslucentBackground
bool isValid() const const
QString toLocalFile() const const
QVariant fromValue(T &&value)
QString toString() const const
T value() const const
QVersionNumber fromString(QAnyStringView string, qsizetype *suffixIndex)
void addActions(const QList< QAction * > &actions)
QRect geometry() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:09:37 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.