Plasma-framework

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 "containmentitem.h"
12#include "dropmenu.h"
13#include "private/appletquickitem_p.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 if (dropJob) {
365 dropJob->setParent(m_dropMenu);
366 }
367
368 // const QMimeData *mimeData = data;
369
370 qDebug() << "Arrived mimeData" << mimeData->urls() << mimeData->formats() << "at" << x << ", " << y;
371
372 // Catch drops from a Task Manager and convert to usable URL.
373 if (!mimeData->hasUrls() && mimeData->hasFormat(QStringLiteral("text/x-orgkdeplasmataskmanager_taskurl"))) {
374 QList<QUrl> urls = {QUrl(QString::fromUtf8(mimeData->data(QStringLiteral("text/x-orgkdeplasmataskmanager_taskurl"))))};
375 mimeData->setUrls(urls);
376 }
377
378 if (mimeData->hasFormat(QStringLiteral("text/x-plasmoidservicename"))) {
379 QString data = QString::fromUtf8(mimeData->data(QStringLiteral("text/x-plasmoidservicename")));
380 const QStringList appletNames = data.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
381 for (const QString &appletName : appletNames) {
382 qDebug() << "adding" << appletName;
383 metaObject()->invokeMethod(this,
384 "createApplet",
386 Q_ARG(QString, appletName),
387 Q_ARG(QVariantList, QVariantList()),
388 Q_ARG(QRectF, QRectF(x, y, -1, -1)));
389 }
390 delete m_dropMenu.data();
391 } else if (mimeData->hasUrls()) {
392 // TODO: collect the mimetypes of available script engines and offer
393 // to create widgets out of the matching URLs, if any
394 const QList<QUrl> urls = KUrlMimeData::urlsFromMimeData(mimeData);
395 if (urls.isEmpty()) {
396 delete m_dropMenu;
397 return;
398 }
399 m_dropMenu->setUrls(urls);
400
401 if (!urls.at(0).isLocalFile()) {
403 }
404
405 QMimeDatabase db;
406 QMimeType firstMimetype = db.mimeTypeForUrl(urls.at(0));
407 for (const QUrl &url : urls) {
408 if (firstMimetype != db.mimeTypeForUrl(url)) {
409 m_dropMenu->setMultipleMimetypes(true);
410 break;
411 }
412 }
413
414 // It may be a directory or a file, let's stat
416 KIO::MimetypeJob *job = KIO::mimetype(m_dropMenu->urls().at(0), flags);
417 job->setParent(m_dropMenu.data());
418
419 QObject::connect(job, &KJob::result, this, &ContainmentItem::dropJobResult);
420 QObject::connect(job, &KIO::MimetypeJob::mimeTypeFound, this, &ContainmentItem::mimeTypeRetrieved);
421
422 } else {
423 bool deleteDropMenu = true;
424
425 const QStringList formats = mimeData->formats();
427 QHash<QString, QString> pluginFormats;
428
429 for (const QString &format : formats) {
430 const auto plugins = Plasma::PluginLoader::self()->listAppletMetaDataForMimeType(format);
431
432 for (const auto &plugin : plugins) {
433 if (seenPlugins.contains(plugin.pluginId())) {
434 continue;
435 }
436
437 seenPlugins.insert(plugin.pluginId(), plugin);
438 pluginFormats.insert(plugin.pluginId(), format);
439 }
440 }
441 // qDebug() << "Mimetype ..." << formats << seenPlugins.keys() << pluginFormats.values();
442
443 QString selectedPlugin;
444
445 if (seenPlugins.isEmpty()) {
446 // do nothing
447 // directly create if only one offer only if the containment didn't pass an existing plugin
448 } else if (seenPlugins.count() == 1) {
449 selectedPlugin = seenPlugins.constBegin().key();
450 Plasma::Applet *applet = createApplet(selectedPlugin, QVariantList(), QRect(x, y, -1, -1));
451 setAppletArgs(applet, pluginFormats[selectedPlugin], mimeData->data(pluginFormats[selectedPlugin]));
452
453 } else {
454 QHash<QAction *, QString> actionsToPlugins;
455 for (const auto &info : std::as_const(seenPlugins)) {
456 QAction *action;
457 if (!info.iconName().isEmpty()) {
458 action = new QAction(QIcon::fromTheme(info.iconName()), info.name(), m_dropMenu);
459 } else {
460 action = new QAction(info.name(), m_dropMenu);
461 }
462 m_dropMenu->addAction(action);
463 action->setData(info.pluginId());
464 connect(action, &QAction::triggered, this, [this, x, y, mimeData, action]() {
465 const QString selectedPlugin = action->data().toString();
466 Plasma::Applet *applet = createApplet(selectedPlugin, QVariantList(), QRect(x, y, -1, -1));
467 setAppletArgs(applet, selectedPlugin, mimeData->data(selectedPlugin));
468 });
469
470 actionsToPlugins.insert(action, info.pluginId());
471 }
472 m_dropMenu->show();
473 deleteDropMenu = false;
474 }
475
476 if (deleteDropMenu) {
477 // in case m_dropMenu has not been shown
478 delete m_dropMenu.data();
479 }
480 }
481}
482
483void ContainmentItem::clearDataForMimeJob(KIO::Job *job)
484{
485 QObject::disconnect(job, nullptr, this, nullptr);
486 job->kill();
487
488 m_dropMenu->show();
489
490 if (!m_dropMenu->urls().at(0).isLocalFile()) {
492 }
493}
494
495void ContainmentItem::dropJobResult(KJob *job)
496{
497 if (job->error()) {
498 qDebug() << "ERROR" << job->error() << ' ' << job->errorString();
499 clearDataForMimeJob(dynamic_cast<KIO::Job *>(job));
500 }
501}
502
503void ContainmentItem::mimeTypeRetrieved(KIO::Job *job, const QString &mimetype)
504{
505 qDebug() << "Mimetype Job returns." << mimetype;
506
507 KIO::TransferJob *tjob = dynamic_cast<KIO::TransferJob *>(job);
508 if (!tjob) {
509 qDebug() << "job should be a TransferJob, but isn't";
510 clearDataForMimeJob(job);
511 return;
512 }
513
515 if (mimetype.isEmpty() && appletList.isEmpty()) {
516 clearDataForMimeJob(job);
517 qDebug() << "No applets found matching the url (" << tjob->url() << ") or the mimetype (" << mimetype << ")";
518 return;
519 } else {
520 qDebug() << "Received a suitable dropEvent at " << m_dropMenu->dropPoint();
521 qDebug() << "Bailing out. Cannot find associated dropEvent related to the TransferJob";
522
523 qDebug() << "Creating menu for: " << mimetype;
524
526
527 QList<KPluginMetaData> wallpaperList;
528
529 if (m_containment->containmentType() != Plasma::Containment::Type::Panel
530 && m_containment->containmentType() != Plasma::Containment::Type::CustomPanel) {
531 if (m_wallpaperItem && m_wallpaperItem->supportsMimetype(mimetype)) {
532 wallpaperList << m_wallpaperItem->kPackage().metadata();
533 } else {
534 wallpaperList = WallpaperItem::listWallpaperMetadataForMimetype(mimetype);
535 }
536 }
537
538 const bool isPlasmaPackage = (mimetype == QLatin1String("application/x-plasma"));
539
540 if ((!appletList.isEmpty() || !wallpaperList.isEmpty() || isPlasmaPackage) && !m_dropMenu->isMultipleMimetypes()) {
541 QAction *installPlasmaPackageAction = nullptr;
542 if (isPlasmaPackage) {
543 QAction *action = new QAction(i18n("Plasma Package"), m_dropMenu);
544 action->setSeparator(true);
545 m_dropMenu->addAction(action);
546
547 installPlasmaPackageAction = new QAction(QIcon::fromTheme(QStringLiteral("application-x-plasma")), i18n("Install"), m_dropMenu);
548 m_dropMenu->addAction(installPlasmaPackageAction);
549
550 const QString &packagePath = tjob->url().toLocalFile();
551 connect(installPlasmaPackageAction, &QAction::triggered, this, [this, packagePath]() {
552 using namespace KPackage;
553
554 PackageJob *job = PackageJob::update(QStringLiteral("Plasma/Applet"), packagePath);
555 connect(job, &KJob::finished, this, [this, packagePath, job]() {
556 auto fail = [](const QString &text) {
557 KNotification::event(QStringLiteral("plasmoidInstallationFailed"),
558 i18n("Package Installation Failed"),
559 text,
560 QStringLiteral("dialog-error"),
562 QStringLiteral("plasma_workspace"));
563 };
564
565 // if the applet is already installed, just add it to the containment
566 if (job->error() != KJob::NoError && job->error() != PackageJob::PackageAlreadyInstalledError
567 && job->error() != PackageJob::NewerVersionAlreadyInstalledError) {
568 fail(job->errorText());
569 return;
570 }
571
572 const Package package = job->package();
573 if (!package.isValid() || !package.metadata().isValid()) {
574 fail(i18n("The package you just dropped is invalid."));
575 return;
576 }
577
578 createApplet(package.metadata().pluginId(), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
579 });
580 });
581 }
582
583 QAction *action = new QAction(i18n("Widgets"), m_dropMenu);
584 action->setSeparator(true);
585 m_dropMenu->addAction(action);
586
587 for (const auto &info : std::as_const(appletList)) {
588 const QString actionText = i18nc("Add widget", "Add %1", info.name());
589 QAction *action = new QAction(actionText, m_dropMenu);
590 if (!info.iconName().isEmpty()) {
591 action->setIcon(QIcon::fromTheme(info.iconName()));
592 }
593 m_dropMenu->addAction(action);
594 action->setData(info.pluginId());
595 const QUrl url = tjob->url();
596 connect(action, &QAction::triggered, this, [this, action, mimetype, url]() {
597 Plasma::Applet *applet = createApplet(action->data().toString(), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
598 setAppletArgs(applet, mimetype, url);
599 });
600 }
601 {
602 QAction *action = new QAction(i18nc("Add icon widget", "Add Icon"), m_dropMenu);
603 m_dropMenu->addAction(action);
604 action->setData(QStringLiteral("org.kde.plasma.icon"));
605 const QUrl url = tjob->url();
606 connect(action, &QAction::triggered, this, [this, action, mimetype, url]() {
607 Plasma::Applet *applet = createApplet(action->data().toString(), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
608 setAppletArgs(applet, mimetype, url);
609 });
610 }
611
612 QHash<QAction *, QString> actionsToWallpapers;
613 if (!wallpaperList.isEmpty()) {
614 QAction *action = new QAction(i18n("Wallpaper"), m_dropMenu);
615 action->setSeparator(true);
616 m_dropMenu->addAction(action);
617
619 for (const auto &info : std::as_const(appletList)) {
620 sorted.insert(info.name(), info);
621 }
622
623 for (const KPluginMetaData &info : std::as_const(wallpaperList)) {
624 const QString actionText = i18nc("Set wallpaper", "Set %1", info.name());
625 QAction *action = new QAction(actionText, m_dropMenu);
626 if (!info.iconName().isEmpty()) {
627 action->setIcon(QIcon::fromTheme(info.iconName()));
628 }
629 m_dropMenu->addAction(action);
630 actionsToWallpapers.insert(action, info.pluginId());
631 const QUrl url = tjob->url();
632 connect(action, &QAction::triggered, this, [this, info, url]() {
633 // Change wallpaper plugin if it's not the current one
634 if (containment()->wallpaperPlugin() != info.pluginId()) {
635 containment()->setWallpaperPlugin(info.pluginId());
636 }
637
638 // set wallpapery stuff
639 if (m_wallpaperItem && url.isValid()) {
640 m_wallpaperItem->requestOpenUrl(url);
641 }
642 });
643 }
644 }
645 } else {
646 // case in which we created the menu ourselves, just the "fetching type entry, directly create the icon applet
647 if (!m_dropMenu->isDropjobMenu()) {
648 Plasma::Applet *applet = createApplet(QStringLiteral("org.kde.plasma.icon"), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
649 setAppletArgs(applet, mimetype, tjob->url());
650 } else {
651 QAction *action;
652 QAction *sep = new QAction(i18n("Widgets"), m_dropMenu);
653 sep->setSeparator(true);
654 m_dropMenu->addAction(sep);
655 // we can at least create an icon as a link to the URL
656 action = new QAction(i18nc("Add icon widget", "Add Icon"), m_dropMenu);
657 m_dropMenu->addAction(action);
658
659 const QUrl url = tjob->url();
660 connect(action, &QAction::triggered, this, [this, mimetype, url]() {
661 Plasma::Applet *applet = createApplet(QStringLiteral("org.kde.plasma.icon"), QVariantList(), QRect(m_dropMenu->dropPoint(), QSize(-1, -1)));
662 setAppletArgs(applet, mimetype, url);
663 });
664 }
665 }
666 clearDataForMimeJob(tjob);
667 }
668}
669
670void ContainmentItem::appletAddedForward(Plasma::Applet *applet, const QRectF &geometryHint)
671{
672 if (!applet) {
673 return;
674 }
675 PlasmoidItem *appletGraphicObject = qobject_cast<PlasmoidItem *>(AppletQuickItem::itemForApplet(applet));
676 m_plasmoidItems.append(appletGraphicObject);
677 connect(appletGraphicObject, &QObject::destroyed, this, [this, appletGraphicObject]() {
678 m_plasmoidItems.removeAll(appletGraphicObject);
679 });
680
681 QPointF removalPosition = appletGraphicObject->m_positionBeforeRemoval;
682 QPointF position = appletGraphicObject->position();
683
684 if (geometryHint.x() > 0 || geometryHint.y() > 0) {
685 position = geometryHint.topLeft();
686 if (geometryHint.width() > 0 && geometryHint.height() > 0) {
687 appletGraphicObject->setSize(geometryHint.size());
688 }
689 } else if (removalPosition.x() > 0.0 && removalPosition.y() > 0.0) {
690 position = removalPosition;
691 } else if (position.isNull() && m_containment->containmentType() == Plasma::Containment::Type::Desktop) {
692 // If no position was provided, and we're adding an applet to the desktop,
693 // add the applet to the center. This avoids always placing new applets
694 // in the top left corner, which is likely to be covered by something.
695 position = QPointF{width() / 2.0 - appletGraphicObject->width() / 2.0, //
696 height() / 2.0 - appletGraphicObject->height() / 2.0};
697 }
698
699 appletGraphicObject->setX(position.x());
700 appletGraphicObject->setY(position.y());
701}
702
703void ContainmentItem::appletRemovedForward(Plasma::Applet *applet)
704{
705 if (!AppletQuickItem::hasItemForApplet(applet)) {
706 return;
707 }
708 PlasmoidItem *appletGraphicObject = qobject_cast<PlasmoidItem *>(AppletQuickItem::itemForApplet(applet));
709 if (appletGraphicObject) {
710 m_plasmoidItems.removeAll(appletGraphicObject);
711 appletGraphicObject->m_positionBeforeRemoval = appletGraphicObject->mapToItem(this, QPointF());
712 }
713}
714
715void ContainmentItem::loadWallpaper()
716{
717 if (!m_containment->isContainment()) {
718 return;
719 }
720
721 if (m_containment->containmentType() != Plasma::Containment::Type::Desktop && m_containment->containmentType() != Plasma::Containment::Type::Custom) {
722 if (!isLoading()) {
724 }
725 return;
726 }
727
728 auto *oldWallpaper = m_wallpaperItem;
729
730 if (!m_containment->wallpaperPlugin().isEmpty()) {
731 m_wallpaperItem = WallpaperItem::loadWallpaper(this);
732 }
733
734 if (m_wallpaperItem) {
735 m_wallpaperItem->setZ(-1000);
736 // Qml seems happier if the parent gets set in this way
737 m_wallpaperItem->setProperty("parent", QVariant::fromValue(this));
738
739 if (isLoading()) {
740 connect(
741 m_wallpaperItem,
742 &WallpaperItem::isLoadingChanged,
743 this,
744 [this]() {
745 if (!isLoading()) {
747 }
748 },
750 } else {
752 }
753
754 // set anchors
755 QQmlExpression expr(qmlObject()->engine()->rootContext(), m_wallpaperItem, QStringLiteral("parent"));
756 QQmlProperty prop(m_wallpaperItem, QStringLiteral("anchors.fill"));
757 prop.write(expr.evaluate());
758 }
759 m_containment->setProperty("wallpaperGraphicsObject", QVariant::fromValue(m_wallpaperItem));
760 delete oldWallpaper;
761
762 Q_EMIT wallpaperItemChanged();
763}
764
765// PROTECTED--------------------
766
767void ContainmentItem::mouseReleaseEvent(QMouseEvent *event)
768{
769 event->setAccepted(m_containment->containmentActions().contains(Plasma::ContainmentActions::eventToString(event)));
770}
771
772void ContainmentItem::mousePressEvent(QMouseEvent *event)
773
774{
775 // even if the menu is executed synchronously, other events may be processed
776 // by the qml incubator when plasma is loading, so we need to guard there
777 if (m_contextMenu) {
778 m_contextMenu->close();
779 for (const auto actions = m_contextMenu->actions(); auto action : actions) {
780 if (action->menu()) {
781 action->menu()->disconnect(m_contextMenu.get());
782 }
783 }
784 m_contextMenu->disconnect(m_containment);
785 m_contextMenu->clear();
786 }
787
789 Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
790
791 if (!plugin) {
792 event->setAccepted(false);
793 return;
794 }
795
796 const auto contextualActions = plugin->contextualActions();
797 if (contextualActions.empty()) {
798 event->setAccepted(false);
799 return;
800 }
801
802 // the plugin can be a single action or a context menu
803 // Don't have an action list? execute as single action
804 // and set the event position as action data
805 if (contextualActions.length() == 1) {
806 QAction *action = contextualActions.at(0);
807 action->setData(event->pos());
808 action->trigger();
809 event->accept();
810 return;
811 }
812
813 // FIXME: very inefficient appletAt() implementation
814 Plasma::Applet *applet = nullptr;
815 for (QObject *appletObject : std::as_const(m_plasmoidItems)) {
816 if (PlasmoidItem *ai = qobject_cast<PlasmoidItem *>(appletObject)) {
817 if (ai->isVisible() && ai->contains(ai->mapFromItem(this, event->position()))) {
818 applet = ai->applet();
819 break;
820 } else {
821 ai = nullptr;
822 }
823 }
824 }
825 // qDebug() << "Invoking menu for applet" << applet;
826
827 if (!m_contextMenu) {
828 m_contextMenu.reset(new QMenu);
829 m_contextMenu->setAttribute(Qt::WA_TranslucentBackground);
830 // this is a workaround where Qt now creates the menu widget
831 // in .exec before oxygen can polish it and set the following attribute
832 // end workaround
833 if (m_contextMenu->winId()) {
834 m_contextMenu->windowHandle()->setTransientParent(window());
835 }
836 m_contextMenu->setAttribute(Qt::WA_DeleteOnClose, false);
837 KAcceleratorManager::manage(m_contextMenu.get());
838 }
839
840 Q_EMIT m_containment->contextualActionsAboutToShow();
841
842 if (applet) {
844 addAppletActions(m_contextMenu.get(), applet, event);
845 } else {
846 addContainmentActions(m_contextMenu.get(), event);
847 }
848
849 // this is a workaround where Qt will fail to realize a mouse has been released
850
851 // this happens if a window which does not accept focus spawns a new window that takes focus and X grab
852 // whilst the mouse is depressed
853 // https://bugreports.qt.io/browse/QTBUG-59044
854 // this causes the next click to go missing
855
856 // by releasing manually we avoid that situation
857 auto ungrabMouseHack = [this]() {
858 if (window() && window()->mouseGrabberItem()) {
860 }
861 };
862
863 // pre 5.8.0 QQuickWindow code is "item->grabMouse(); sendEvent(item, mouseEvent)"
864 // post 5.8.0 QQuickWindow code is sendEvent(item, mouseEvent); item->grabMouse()
865 if (QVersionNumber::fromString(QLatin1String(qVersion())) > QVersionNumber(5, 8, 0)) {
866 QTimer::singleShot(0, this, ungrabMouseHack);
867 } else {
868 ungrabMouseHack();
869 }
870 // end workaround
871
872 QPoint pos = event->globalPosition().toPoint();
873 if (window() && m_containment->containmentType() == Plasma::Containment::Type::Panel) {
874 m_contextMenu->adjustSize();
875
876 if (QScreen *screen = window()->screen()) {
877 const QRect geo = screen->availableGeometry();
878
879 pos = QPoint(qBound(geo.left(), pos.x(), geo.right() + 1 - m_contextMenu->width()),
880 qBound(geo.top(), pos.y(), geo.bottom() + 1 - m_contextMenu->height()));
881 }
882 }
883
884 if (m_contextMenu->isEmpty()) {
885 m_contextMenu.reset();
886 event->accept();
887 return;
888 }
889
890 // Bug 344205 keep panel visible while menu is open
891 const auto oldStatus = m_containment->status();
892 m_containment->setStatus(Plasma::Types::RequiresAttentionStatus);
893
894 connect(m_contextMenu.get(), &QMenu::aboutToHide, m_containment, [this, oldStatus] {
895 m_containment->setStatus(oldStatus);
896 });
897
898 for (auto action : m_contextMenu->actions()) {
899 if (action->menu()) {
900 connect(action->menu(), &QMenu::aboutToShow, m_contextMenu.get(), [this, action] {
901 if (action->menu()->windowHandle()) {
902 // Need to add the transient parent otherwise Qt will create a new toplevel
903 action->menu()->windowHandle()->setTransientParent(m_contextMenu->windowHandle());
904 }
905 });
906 }
907 }
908
909 m_contextMenu->popup(pos);
910 event->setAccepted(true);
911}
912
913void ContainmentItem::wheelEvent(QWheelEvent *event)
914{
916 Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
917
918 if (!plugin) {
919 event->setAccepted(false);
920 return;
921 }
922
923 if (std::abs(event->angleDelta().x()) > std::abs(event->angleDelta().y())) {
924 m_wheelDelta += event->angleDelta().x();
925 } else {
926 m_wheelDelta += event->angleDelta().y();
927 }
928
929 // Angle delta 120 for common "one click"
930 // See: https://doc.qt.io/qt-5/qml-qtquick-wheelevent.html#angleDelta-prop
931 while (m_wheelDelta >= 120) {
932 m_wheelDelta -= 120;
933 plugin->performPreviousAction();
934 }
935 while (m_wheelDelta <= -120) {
936 m_wheelDelta += 120;
937 plugin->performNextAction();
938 }
939}
940
941void ContainmentItem::keyPressEvent(QKeyEvent *event)
942{
944 if (event->isAccepted()) {
945 return;
946 }
947
948 if (event->key() == Qt::Key_Menu) {
949 QPointF localPos;
950 auto focusedItem = window()->activeFocusItem();
951 if (focusedItem) {
952 localPos = focusedItem->mapToItem(this, QPointF(0, 0));
953 }
954
956 mousePressEvent(&me);
957 event->accept();
958 }
959}
960
961void ContainmentItem::addAppletActions(QMenu *desktopMenu, Plasma::Applet *applet, QEvent *event)
962{
963 const auto listActions = applet->contextualActions();
964 for (QAction *action : listActions) {
965 if (action) {
966 desktopMenu->addAction(action);
967 }
968 }
969
970 if (!applet->failedToLaunch()) {
971 QAction *configureApplet = applet->internalAction(QStringLiteral("configure"));
972 if (configureApplet && configureApplet->isEnabled()) {
973 desktopMenu->addAction(configureApplet);
974 }
975 QAction *appletAlternatives = applet->internalAction(QStringLiteral("alternatives"));
976 if (appletAlternatives && appletAlternatives->isEnabled()) {
977 desktopMenu->addAction(appletAlternatives);
978 }
979 }
980
981 desktopMenu->addSeparator();
982 if (m_containment->containmentType() == Plasma::Containment::Type::Desktop) {
983 auto action = m_containment->corona()->action(QStringLiteral("edit mode"));
984 if (action) {
985 desktopMenu->addAction(action);
986 }
987 } else {
988 addContainmentActions(desktopMenu, event);
989 }
990
991 if (m_containment->immutability() == Plasma::Types::Mutable
992 && (m_containment->containmentType() != Plasma::Containment::Type::Panel || m_containment->isUserConfiguring())) {
993 QAction *closeApplet = applet->internalAction(QStringLiteral("remove"));
994 // qDebug() << "checking for removal" << closeApplet;
995 if (closeApplet) {
996 if (!desktopMenu->isEmpty()) {
997 desktopMenu->addSeparator();
998 }
999
1000 // qDebug() << "adding close action" << closeApplet->isEnabled() << closeApplet->isVisible();
1001 desktopMenu->addAction(closeApplet);
1002 }
1003 }
1004}
1005
1006void ContainmentItem::addContainmentActions(QMenu *desktopMenu, QEvent *event)
1007{
1008 if (m_containment->corona()->immutability() != Plasma::Types::Mutable //
1009 && !KAuthorized::authorizeAction(QStringLiteral("plasma/containment_actions"))) {
1010 // qDebug() << "immutability";
1011 return;
1012 }
1013
1014 // this is what ContainmentPrivate::prepareContainmentActions was
1016 Plasma::ContainmentActions *plugin = m_containment->containmentActions().value(trigger);
1017
1018 if (!plugin) {
1019 return;
1020 }
1021
1022 if (plugin->containment() != m_containment) {
1023 plugin->setContainment(m_containment);
1024
1025 // now configure it
1026 KConfigGroup cfg(m_containment->corona()->config(), QStringLiteral("ActionPlugins"));
1027 cfg = KConfigGroup(&cfg, QString::number((int)m_containment->containmentType()));
1028 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
1029 plugin->restore(pluginConfig);
1030 }
1031
1032 QList<QAction *> actions = plugin->contextualActions();
1033
1034 if (actions.isEmpty()) {
1035 // it probably didn't bother implementing the function. give the user a chance to set
1036 // a better plugin. note that if the user sets no-plugin this won't happen...
1037 /* clang-format off */
1038 if ((m_containment->containmentType() != Plasma::Containment::Type::Panel
1039 && m_containment->containmentType() != Plasma::Containment::Type::CustomPanel)
1040 && m_containment->internalAction(QStringLiteral("configure"))) { /* clang-format on */
1041 desktopMenu->addAction(m_containment->internalAction(QStringLiteral("configure")));
1042 }
1043 } else {
1044 desktopMenu->addActions(actions);
1045 }
1046
1047 return;
1048}
1049
1050bool ContainmentItem::isLoading() const
1051{
1052 return m_wallpaperItem && m_wallpaperItem->isLoading();
1053}
1054
1055void ContainmentItem::itemChange(ItemChange change, const ItemChangeData &value)
1056{
1057 if (!m_containment) {
1058 // This can happen only if the client QML code declares a PlasmoidItem somewhere else than the root object
1059 PlasmoidItem::itemChange(change, value);
1060 return;
1061 }
1062 if (change == QQuickItem::ItemSceneChange) {
1063 // we have a window: create the representations if needed
1064 if (value.window && !m_containment->wallpaperPlugin().isEmpty()) {
1065 loadWallpaper();
1066 } else if (m_wallpaperItem) {
1067 deleteWallpaperItem();
1068 Q_EMIT wallpaperItemChanged();
1069 }
1070 }
1071
1072 PlasmoidItem::itemChange(change, value);
1073}
1074
1075void ContainmentItem::deleteWallpaperItem()
1076{
1077 m_containment->setProperty("wallpaperGraphicsObject", QVariant());
1078 m_wallpaperItem->deleteLater();
1079 m_wallpaperItem = nullptr;
1080}
1081
1082#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)
QString errorText() const
bool kill(KJob::KillVerbosity verbosity=KJob::Quietly)
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
void updateConstraints(Constraints constraints=AllConstraints)
Called when any of the geometry constraints have been updated.
Definition applet.cpp:269
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:654
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:465
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 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()
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
void setParent(QObject *parent)
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 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
typedef const_iterator
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 May 17 2024 11:54:11 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.