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

KDE's Doxygen guidelines are available online.