23 #include "private/containment_p.h"
25 #include "config-plasma.h"
27 #include <QApplication>
30 #include <QGraphicsSceneContextMenuEvent>
31 #include <QGraphicsView>
34 #include <QStyleOptionGraphicsItem>
35 #include <QGraphicsLayout>
36 #include <QGraphicsLinearLayout>
39 #include <kauthorized.h>
42 #include <kmessagebox.h>
43 #include <kmimetype.h>
44 #include <kservicetypetrader.h>
45 #include <kstandarddirs.h>
46 #include <ktemporaryfile.h>
47 #include <kwindowsystem.h>
50 #include "kio/jobclasses.h"
52 #include "kio/scheduler.h"
69 #include "private/applet_p.h"
70 #include "private/containmentactionspluginsconfig_p.h"
71 #include "private/extenderitemmimedata_p.h"
72 #include "private/extenderapplet_p.h"
73 #include "private/wallpaper_p.h"
81 bool ContainmentPrivate::s_positioningPanels =
false;
82 QHash<QString, ContainmentActions*> ContainmentPrivate::globalActionPlugins;
111 const QString &serviceId,
113 :
Applet(parent, serviceId, containmentId),
125 d(new ContainmentPrivate(this))
134 : Plasma::
Applet(packagePath, appletId, args),
135 d(new ContainmentPrivate(this))
147 Applet::d->isContainment =
false;
159 setFlag(QGraphicsItem::ItemIsMovable,
false);
160 setFlag(QGraphicsItem::ItemClipsChildrenToShape,
true);
161 setAcceptDrops(
true);
162 setAcceptsHoverEvents(
true);
169 ContainmentPrivate::addDefaultActions(d->actions(),
this);
174 QAction *closeApplet =
action(
"remove");
176 closeApplet->setText(i18nc(
"%1 is the name of the applet",
"Remove this %1",
name()));
179 QAction *configAction =
action(
"configure");
181 configAction->setText(i18nc(
"%1 is the name of the applet",
"%1 Settings",
name()));
184 QAction *appletBrowserAction =
action(
"add widgets");
185 if (appletBrowserAction) {
186 appletBrowserAction->setVisible(unlocked);
187 appletBrowserAction->setEnabled(unlocked);
188 connect(appletBrowserAction, SIGNAL(triggered()),
this, SLOT(triggerShowAddWidgets()));
191 QAction *act =
action(
"next applet");
196 act =
action(
"previous applet");
202 QAction *lockDesktopAction =
corona()->
action(
"lock widgets");
204 if (lockDesktopAction) {
205 d->actions()->addAction(
"lock widgets", lockDesktopAction);
213 d->actions()->addAction(
"manage activities", act);
218 d->actions()->addAction(
"configure shortcuts", act);
228 QAction *configureContainment =
action(
"configure");
229 if (configureContainment) {
236 void ContainmentPrivate::addDefaultActions(KActionCollection *actions,
Containment *c)
238 actions->setConfigGroup(
"Shortcuts-Containment");
241 KAction *appAction = qobject_cast<KAction*>(actions->action(
"remove"));
242 appAction->setShortcut(KShortcut(
"alt+d, alt+r"));
243 if (c && c->d->isPanelContainment()) {
244 appAction->setText(i18n(
"Remove this Panel"));
246 appAction->setText(i18n(
"Remove this Activity"));
249 appAction = qobject_cast<KAction*>(actions->action(
"configure"));
251 appAction->setShortcut(KShortcut(
"alt+d, alt+s"));
252 appAction->setText(i18n(
"Activity Settings"));
256 KAction *appletBrowserAction = actions->addAction(
"add widgets");
257 appletBrowserAction->setAutoRepeat(
false);
258 appletBrowserAction->setText(i18n(
"Add Widgets..."));
259 appletBrowserAction->setIcon(KIcon(
"list-add"));
260 appletBrowserAction->setShortcut(KShortcut(
"alt+d, a"));
263 KAction *action = actions->addAction(
"next applet");
264 action->setText(i18n(
"Next Widget"));
266 action->setShortcut(KShortcut(
"alt+d, n"));
269 action = actions->addAction(
"previous applet");
270 action->setText(i18n(
"Previous Widget"));
272 action->setShortcut(KShortcut(
"alt+d, p"));
279 QPointF p1 = c1.readEntry(
"geometry", QRectF()).topLeft();
280 QPointF p2 = c2.readEntry(
"geometry", QRectF()).topLeft();
282 if (!qFuzzyCompare(p1.x(), p2.x())) {
283 if (QApplication::layoutDirection() == Qt::RightToLeft) {
284 return p1.x() > p2.x();
287 return p1.x() < p2.x();
290 return qFuzzyCompare(p1.y(), p2.y()) || p1.y() < p2.y();
305 QRectF geo = group.readEntry(
"geometry",
geometry());
309 if (geo.size() != geo.size().boundedTo(maximumSize())) {
310 setMaximumSize(maximumSize().expandedTo(geo.size()));
313 if (geo.size() != geo.size().expandedTo(minimumSize())) {
314 setMinimumSize(minimumSize().boundedTo(geo.size()));
327 d->lastScreen = group.readEntry(
"lastScreen", d->lastScreen);
328 d->lastDesktop = group.readEntry(
"lastDesktop", d->lastDesktop);
329 d->setScreen(group.readEntry(
"screen", d->screen), group.readEntry(
"desktop", d->desktop),
false);
330 QString activityId = group.readEntry(
"activityId", QString());
331 if (!activityId.isEmpty()) {
332 d->context()->setCurrentActivityId(activityId);
334 setActivity(group.readEntry(
"activity", QString()));
343 QMetaObject::invokeMethod(d->toolBox.data(),
"restore", Q_ARG(KConfigGroup, group));
350 d->containmentActionsSource = ContainmentPrivate::Local;
351 cfg = KConfigGroup(&group,
"ActionPlugins");
353 QString source = group.readEntry(
"ActionPluginsSource", QString());
354 if (source ==
"Global") {
355 cfg = KConfigGroup(
corona()->
config(),
"ActionPlugins");
356 d->containmentActionsSource = ContainmentPrivate::Global;
357 }
else if (source ==
"Activity") {
359 cfg = KConfigGroup(&cfg, activityId);
360 cfg = KConfigGroup(&cfg,
"ActionPlugins");
361 d->containmentActionsSource = ContainmentPrivate::Activity;
362 }
else if (source ==
"Local") {
364 d->containmentActionsSource = ContainmentPrivate::Local;
368 cfg = KConfigGroup(
corona()->
config(),
"ActionPlugins");
370 cfg = KConfigGroup(&group,
"ActionPlugins");
372 d->containmentActionsSource = ContainmentPrivate::Global;
373 group.writeEntry(
"ActionPluginsSource",
"Global");
378 foreach (
const QString &key, cfg.keyList()) {
385 QHash<QString,QString> defaults = conf.d->plugins;
386 for (QHash<QString,QString>::const_iterator it = defaults.constBegin(),
387 end = defaults.constEnd(); it != end; ++it) {
404 if (Applet::d->
transient) {
408 KConfigGroup group = g;
409 if (!group.isValid()) {
420 group.writeEntry(
"screen", d->screen);
421 group.writeEntry(
"lastScreen", d->lastScreen);
422 group.writeEntry(
"desktop", d->desktop);
423 group.writeEntry(
"lastDesktop", d->lastDesktop);
424 group.writeEntry(
"formfactor", (
int)d->formFactor);
425 group.writeEntry(
"location", (
int)d->location);
426 group.writeEntry(
"activity", d->context()->currentActivity());
427 group.writeEntry(
"activityId", d->context()->currentActivityId());
430 QMetaObject::invokeMethod(d->toolBox.data(),
"save", Q_ARG(KConfigGroup, group));
434 group.writeEntry(
"wallpaperplugin", d->wallpaper->pluginName());
435 group.writeEntry(
"wallpaperpluginmode", d->wallpaper->renderingMode().name());
437 if (d->wallpaper->isInitialized()) {
438 KConfigGroup wallpaperConfig(&group,
"Wallpaper");
439 wallpaperConfig = KConfigGroup(&wallpaperConfig, d->wallpaper->pluginName());
440 d->wallpaper->save(wallpaperConfig);
449 KConfigGroup
applets(&group,
"Applets");
450 foreach (
const Applet *applet, d->applets) {
451 KConfigGroup appletConfig(&applets, QString::number(applet->
id()));
452 applet->
save(appletConfig);
456 void ContainmentPrivate::initApplets()
458 foreach (
Applet *applet, applets) {
459 applet->
restore(*applet->d->mainConfigGroup());
461 kDebug() <<
"!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) <<
"Applet" << applet->
name();
464 q->flushPendingConstraintsEvents();
466 foreach (Applet *applet, applets) {
467 applet->flushPendingConstraintsEvents();
470 kDebug() <<
"!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) <<
"Containment's applets initialized" << q->name();
475 KConfigGroup
applets(&group,
"Applets");
479 QList<KConfigGroup> appletConfigs;
480 foreach (
const QString &appletGroup, applets.groupList()) {
482 KConfigGroup appletConfig(&applets, appletGroup);
483 appletConfigs.append(appletConfig);
487 QMutableListIterator<KConfigGroup> it(appletConfigs);
488 while (it.hasNext()) {
489 KConfigGroup &appletConfig = it.next();
490 int appId = appletConfig.name().toUInt();
491 QString plugin = appletConfig.readEntry(
"plugin", QString());
493 if (plugin.isEmpty()) {
497 d->addApplet(plugin, QVariantList(), appletConfig.readEntry(
"geometry", QRectF()), appId,
true);
508 if (d->type == type) {
512 delete d->toolBox.data();
514 d->checkContainmentFurniture();
517 void ContainmentPrivate::checkContainmentFurniture()
519 if (q->isContainment() &&
527 return qobject_cast<
Corona*>(scene());
533 if (d->wallpaper && d->wallpaper->isInitialized()) {
534 QGraphicsItem *item = scene()->itemAt(event->scenePos());
536 d->wallpaper->mouseMoveEvent(event);
540 if (!event->isAccepted()) {
550 d->toolBox.data()->setShowing(
false);
553 if (d->appletAt(event->scenePos())) {
557 if (d->wallpaper && d->wallpaper->isInitialized() && !
event->isAccepted()) {
558 d->wallpaper->mousePressEvent(event);
561 if (event->isAccepted()) {
562 setFocus(Qt::MouseFocusReason);
563 }
else if (event->button() == Qt::RightButton &&
event->modifiers() == Qt::NoModifier) {
565 Applet::mousePressEvent(event);
568 if (d->prepareContainmentActions(trigger, event->screenPos())) {
569 d->actionPlugins()->value(trigger)->contextEvent(event);
572 if (!event->isAccepted()) {
573 Applet::mousePressEvent(event);
582 if (d->appletAt(event->scenePos())) {
588 if (d->wallpaper && d->wallpaper->isInitialized()) {
589 d->wallpaper->mouseReleaseEvent(event);
593 if (d->prepareContainmentActions(trigger, event->screenPos())) {
594 d->actionPlugins()->value(trigger)->contextEvent(event);
598 Applet::mouseReleaseEvent(event);
611 QGraphicsSceneContextMenuEvent gvevent;
612 gvevent.setScreenPos(screenPos);
613 gvevent.setScenePos(mapToScene(containmentPos));
614 gvevent.setPos(containmentPos);
615 gvevent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
616 gvevent.setWidget(
view());
622 if (!
isContainment() || !KAuthorized::authorizeKAction(
"plasma/containment_context_menu")) {
623 Applet::contextMenuEvent(event);
628 Applet *applet = d->appletAt(event->scenePos());
632 d->addAppletActions(desktopMenu, applet, event);
634 d->addContainmentActions(desktopMenu, event);
638 QMenu *menu = &desktopMenu;
640 if (desktopMenu.actions().size() == 1 && desktopMenu.actions().first()->menu()) {
642 menu = desktopMenu.actions().first()->menu();
645 if (!menu->isEmpty()) {
646 QPoint pos =
event->screenPos();
647 if (applet && d->isPanelContainment()) {
650 if (event->reason() == QGraphicsSceneContextMenuEvent::Mouse) {
654 if (pos.y() + menu->height() <
event->screenPos().y()) {
655 pos.setY(event->screenPos().y());
658 if (pos.x() + menu->width() <
event->screenPos().x()) {
659 pos.setX(event->screenPos().x());
668 Applet::contextMenuEvent(event);
672 void ContainmentPrivate::addContainmentActions(KMenu &desktopMenu, QEvent *event)
674 if (static_cast<Corona*>(q->scene())->immutability() !=
Mutable &&
675 !KAuthorized::authorizeKAction(
"plasma/containment_actions")) {
681 prepareContainmentActions(trigger, QPoint(), &desktopMenu);
684 void ContainmentPrivate::addAppletActions(KMenu &desktopMenu, Applet *applet, QEvent *event)
686 foreach (QAction *action, applet->contextualActions()) {
688 desktopMenu.addAction(action);
692 if (!applet->d->failed) {
693 QAction *configureApplet = applet->d->actions->action(
"configure");
694 if (configureApplet && configureApplet->isEnabled()) {
695 desktopMenu.addAction(configureApplet);
698 QAction *runAssociatedApplication = applet->d->actions->action(
"run associated application");
699 if (runAssociatedApplication && runAssociatedApplication->isEnabled()) {
700 desktopMenu.addAction(runAssociatedApplication);
704 KMenu *containmentMenu =
new KMenu(i18nc(
"%1 is the name of the containment",
"%1 Options", q->name()), &desktopMenu);
705 addContainmentActions(*containmentMenu, event);
706 if (!containmentMenu->isEmpty()) {
709 QListIterator<QAction *> actionsIt(containmentMenu->actions());
710 while (enabled < 3 && actionsIt.hasNext()) {
711 QAction *action = actionsIt.next();
712 if (action->isVisible() && !action->isSeparator()) {
720 foreach (QAction *action, containmentMenu->actions()) {
721 if (action->isVisible() && !action->isSeparator()) {
722 desktopMenu.addAction(action);
726 desktopMenu.addMenu(containmentMenu);
731 if (q->immutability() ==
Mutable &&
732 !q->property(
"hideCloseAppletInContextMenu").toBool()) {
733 QAction *closeApplet = applet->d->actions->action(
"remove");
736 if (!desktopMenu.isEmpty()) {
737 desktopMenu.addSeparator();
741 desktopMenu.addAction(closeApplet);
746 Applet* ContainmentPrivate::appletAt(
const QPointF &point)
750 QGraphicsItem *item = q->scene()->itemAt(point);
756 if (item->isWidget()) {
759 if (applet->isContainment()) {
765 AppletHandle *handle =
dynamic_cast<AppletHandle*
>(item);
768 applet = handle->applet();
771 item = item->parentItem();
778 if (d->formFactor == formFactor) {
788 d->positionPanel(
true);
791 QMetaObject::invokeMethod(d->toolBox.data(),
"reposition");
795 KConfigGroup c =
config();
796 c.writeEntry(
"formfactor", (
int)formFactor);
802 if (d->location == location) {
806 bool emitGeomChange =
false;
810 emitGeomChange =
true;
815 emitGeomChange =
true;
820 foreach (
Applet *applet, d->applets) {
824 if (emitGeomChange) {
832 KConfigGroup c =
config();
833 c.writeEntry(
"location", (
int)location);
844 foreach (
Applet *applet, d->applets) {
845 applet->d->cleanUpAndDelete();
852 const QRectF &appletGeometry)
854 return d->addApplet(name, args, appletGeometry);
864 kDebug() <<
"adding null applet!?!";
868 if (d->applets.contains(applet)) {
869 kDebug() <<
"already have this applet!";
879 if (currentContainment && currentContainment !=
this) {
881 if (currentContainment->d->focusedApplet == applet) {
882 currentContainment->d->focusedApplet = 0;
885 disconnect(applet, 0, currentContainment, 0);
886 KConfigGroup oldConfig = applet->
config();
887 currentContainment->d->applets.removeAll(applet);
888 applet->setParentItem(
this);
889 applet->setParent(
this);
893 KConfigGroup c =
config().group(
"Applets").group(QString::number(applet->
id()));
894 oldConfig.reparent(&c);
895 applet->d->resetConfigurationObject();
897 disconnect(applet, SIGNAL(
activate()), currentContainment, SIGNAL(
activate()));
899 applet->setParentItem(
this);
900 applet->setParent(
this);
903 d->applets << applet;
911 if (pos != QPointF(-1, -1)) {
915 if (!delayInit && !currentContainment) {
916 applet->
restore(*applet->d->mainConfigGroup());
920 connect(anim, SIGNAL(finished()),
this, SLOT(appletAppearAnimationComplete()));
924 anim->setDirection(QAbstractAnimation::Backward);
925 anim->start(QAbstractAnimation::DeleteWhenStopped);
927 d->appletAppeared(applet);
931 applet->setFlag(QGraphicsItem::ItemIsMovable,
true);
938 if (!currentContainment) {
946 applet->d->scheduleModificationNotification();
957 d->setScreen(newScreen, newDesktop);
960 void ContainmentPrivate::setScreen(
int newScreen,
int newDesktop,
bool preventInvalidDesktops)
972 Corona *corona = q->corona();
981 if (newScreen < -1) {
986 if (newDesktop < -1 || (preventInvalidDesktops && newDesktop > KWindowSystem::numberOfDesktops() - 1)) {
992 Containment *swapScreensWith(0);
995 if (isDesktopContainment) {
998 if (screen < 0 && newScreen > -1) {
999 QObject::connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), toolBox.data(), SLOT(reposition()), Qt::UniqueConnection);
1000 }
else if (newScreen < 0) {
1001 QObject::disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), toolBox.data(), SLOT(reposition()));
1005 if (newScreen > -1) {
1008 if (currently && currently != q) {
1009 kDebug() <<
"currently is on screen" << currently->
screen()
1010 <<
"desktop" << currently->desktop()
1011 <<
"and is" << currently->activity()
1013 currently->setScreen(-1, currently->desktop());
1014 swapScreensWith = currently;
1019 if (newScreen < numScreens && newScreen > -1 && isDesktopContainment) {
1023 int oldDesktop = desktop;
1024 desktop = newDesktop;
1026 int oldScreen = screen;
1031 if (oldScreen != newScreen || oldDesktop != newDesktop) {
1037 KConfigGroup c = q->
config();
1038 c.writeEntry(
"screen", screen);
1039 c.writeEntry(
"desktop", desktop);
1040 if (newScreen != -1) {
1041 lastScreen = newScreen;
1042 lastDesktop = newDesktop;
1043 c.writeEntry(
"lastScreen", lastScreen);
1044 c.writeEntry(
"lastDesktop", lastDesktop);
1046 emit q->configNeedsSaving();
1047 emit q->screenChanged(oldScreen, newScreen, q);
1050 if (swapScreensWith) {
1052 swapScreensWith->setScreen(oldScreen, oldDesktop);
1055 checkRemoveAction();
1057 if (newScreen >= 0) {
1069 return d->lastScreen;
1079 return d->lastDesktop;
1083 const QString &parentApp)
1090 const QString &category,
1091 const QString &parentApp)
1095 if (parentApp.isEmpty()) {
1096 constraint.append(
"(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
1098 constraint.append(
"[X-KDE-ParentApp] == '").append(parentApp).append(
"'");
1101 if (!type.isEmpty()) {
1102 if (!constraint.isEmpty()) {
1103 constraint.append(
" and ");
1106 constraint.append(
"'").append(type).append(
"' ~in [X-Plasma-ContainmentCategories]");
1109 if (!category.isEmpty()) {
1110 if (!constraint.isEmpty()) {
1111 constraint.append(
" and ");
1114 constraint.append(
"[X-KDE-PluginInfo-Category] == '").append(category).append(
"'");
1115 if (category ==
"Miscellaneous") {
1116 constraint.append(
" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
1120 KService::List offers = KServiceTypeTrader::self()->query(
"Plasma/Containment", constraint);
1122 return KPluginInfo::fromServices(offers);
1127 const QString constraint = QString(
"'%1' in [X-Plasma-DropMimeTypes]").arg(mimetype);
1129 const KService::List offers = KServiceTypeTrader::self()->query(
"Plasma/Containment", constraint);
1130 return KPluginInfo::fromServices(offers);
1136 QSet<QString> types;
1138 foreach (
const KPluginInfo &containmentInfo, containmentInfos) {
1139 QStringList theseTypes = containmentInfo.service()->property(
"X-Plasma-ContainmentCategories").toStringList();
1140 foreach (
const QString &
type, theseTypes) {
1145 return types.toList();
1151 (event->mimeData()->hasFormat(static_cast<Corona*>(scene())->appletMimeType()) ||
1152 KUrl::List::canDecode(event->mimeData()) ||
1153 event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())));
1156 if (!event->isAccepted()) {
1158 QStringList formats =
event->mimeData()->formats();
1160 foreach (
const QString &format, formats) {
1162 if (!appletList.isEmpty()) {
1163 event->setAccepted(
true);
1168 if (!event->isAccepted()) {
1169 foreach (
const QString &format, formats) {
1171 if (!wallpaperList.isEmpty()) {
1172 event->setAccepted(
true);
1179 if (event->isAccepted()) {
1180 if (d->dropZoneStarted) {
1183 if (!d->showDropZoneDelayTimer) {
1184 d->showDropZoneDelayTimer =
new QTimer(
this);
1185 d->showDropZoneDelayTimer->setSingleShot(
true);
1186 connect(d->showDropZoneDelayTimer, SIGNAL(timeout()),
this, SLOT(showDropZoneDelayed()));
1189 d->dropPoints.insert(0, event->pos());
1190 d->showDropZoneDelayTimer->start(300);
1197 if (event->pos().y() < 1 ||
event->pos().y() > size().height() ||
1198 event->pos().x() < 1 ||
event->pos().x() > size().width()) {
1199 if (d->showDropZoneDelayTimer) {
1200 d->showDropZoneDelayTimer->stop();
1204 d->dropZoneStarted =
false;
1208 void ContainmentPrivate::showDropZoneDelayed()
1210 dropZoneStarted =
true;
1211 q->showDropZone(dropPoints.value(0).toPoint());
1212 dropPoints.remove(0);
1217 QGraphicsItem *item = scene()->itemAt(event->scenePos());
1220 if (!event->isAccepted()) {
1221 if (d->showDropZoneDelayTimer) {
1222 d->showDropZoneDelayTimer->stop();
1232 d->dropZoneStarted =
false;
1234 d->dropData(event->scenePos(),
event->screenPos(), event);
1236 Applet::dropEvent(event);
1240 void ContainmentPrivate::dropData(QPointF scenePos, QPoint screenPos, QGraphicsSceneDragDropEvent *dropEvent)
1242 if (q->immutability() !=
Mutable) {
1246 QPointF pos = q->mapFromScene(scenePos);
1247 const QMimeData *mimeData = 0;
1250 mimeData = dropEvent->mimeData();
1252 QClipboard *clipboard = QApplication::clipboard();
1253 mimeData = clipboard->mimeData(QClipboard::Selection);
1259 kDebug() <<
"no mime data";
1265 QString appletMimetype(q->corona() ? q->corona()->appletMimeType() : QString());
1267 if (!appletMimetype.isEmpty() && mimeData->hasFormat(appletMimetype)) {
1268 QString data = mimeData->data(appletMimetype);
1269 const QStringList appletNames = data.split(
'\n', QString::SkipEmptyParts);
1270 foreach (
const QString &appletName, appletNames) {
1272 QRectF geom(pos, QSize(0, 0));
1273 q->addApplet(appletName, QVariantList(), geom);
1276 dropEvent->acceptProposedAction();
1278 }
else if (mimeData->hasFormat(ExtenderItemMimeData::mimeType())) {
1279 kDebug() <<
"mimetype plasma/extenderitem is dropped, creating internal:extender";
1281 const ExtenderItemMimeData *extenderData = qobject_cast<
const ExtenderItemMimeData*>(mimeData);
1283 ExtenderItem *item = extenderData->extenderItem();
1284 QRectF geometry(pos - extenderData->pointerOffset(), item->size());
1285 kDebug() <<
"desired geometry: " << geometry;
1286 Applet *applet = qobject_cast<ExtenderApplet *>(item->extender() ? item->extender()->applet() : 0);
1288 qreal left, top, right, bottom;
1289 applet->getContentsMargins(&left, &top, &right, &bottom);
1290 applet->setPos(geometry.topLeft() - QPointF(
int(left),
int(top)));
1293 applet = addApplet(
"internal:extender", QVariantList(), geometry, 0,
true);
1296 appletAppeared(applet);
1297 applet->flushPendingConstraintsEvents();
1298 applet->d->scheduleModificationNotification();
1299 applet->adjustSize();
1302 item->setExtender(applet->extender());
1304 }
else if (KUrl::List::canDecode(mimeData)) {
1307 const KUrl::List urls = KUrl::List::fromMimeData(mimeData);
1308 foreach (
const KUrl &url, urls) {
1312 dropPoints[job] = dropEvent->pos();
1314 dropPoints[job] = scenePos;
1319 #ifndef PLASMA_NO_KIO
1321 KMimeType::Ptr mime = KMimeType::findByUrl(url);
1322 QString mimeName = mime->name();
1323 QRectF geom(pos, QSize());
1326 kDebug() <<
"can decode" << mimeName << args;
1329 KIO::JobFlags flags = KIO::HideProgressInfo;
1330 KIO::MimetypeJob *job = KIO::mimetype(url, flags);
1332 dropPoints[job] = dropEvent->pos();
1334 dropPoints[job] = scenePos;
1337 QObject::connect(job, SIGNAL(result(
KJob*)), q, SLOT(dropJobResult(
KJob*)));
1338 QObject::connect(job, SIGNAL(mimetype(KIO::Job*,QString)),
1339 q, SLOT(mimeTypeRetrieved(KIO::Job*,QString)));
1341 KMenu *choices =
new KMenu(
"Content dropped");
1342 choices->addAction(KIcon(
"process-working"), i18n(
"Fetching file type..."));
1344 choices->popup(dropEvent->screenPos());
1346 choices->popup(screenPos);
1349 dropMenus[job] = choices;
1355 dropEvent->acceptProposedAction();
1358 QStringList formats = mimeData->formats();
1359 QHash<QString, KPluginInfo> seenPlugins;
1360 QHash<QString, QString> pluginFormats;
1362 foreach (
const QString &format, formats) {
1365 foreach (
const KPluginInfo &plugin, plugins) {
1366 if (seenPlugins.contains(plugin.pluginName())) {
1370 seenPlugins.insert(plugin.pluginName(), plugin);
1371 pluginFormats.insert(plugin.pluginName(), format);
1376 QString selectedPlugin;
1378 if (seenPlugins.isEmpty()) {
1380 }
else if (seenPlugins.count() == 1) {
1381 selectedPlugin = seenPlugins.constBegin().key();
1384 QHash<QAction *, QString> actionsToPlugins;
1385 foreach (
const KPluginInfo &info, seenPlugins) {
1387 if (!info.icon().isEmpty()) {
1388 action = choices.addAction(KIcon(info.icon()), info.name());
1390 action = choices.addAction(info.name());
1393 actionsToPlugins.insert(action, info.pluginName());
1396 QAction *choice = choices.exec(screenPos);
1398 selectedPlugin = actionsToPlugins[choice];
1402 if (!selectedPlugin.isEmpty()) {
1408 QClipboard *clipboard = QApplication::clipboard();
1409 mimeData = clipboard->mimeData(QClipboard::Selection);
1412 KTemporaryFile tempFile;
1413 if (mimeData && tempFile.open()) {
1415 tempFile.setAutoRemove(
false);
1418 QDataStream stream(&tempFile);
1419 QByteArray data = mimeData->data(pluginFormats[selectedPlugin]);
1420 stream.writeRawData(data, data.size());
1423 QRectF geom(pos, QSize());
1425 args << tempFile.fileName();
1429 q->addApplet(selectedPlugin, args, geom);
1435 void ContainmentPrivate::clearDataForMimeJob(KIO::Job *job)
1437 #ifndef PLASMA_NO_KIO
1438 QObject::disconnect(job, 0, q, 0);
1439 dropPoints.remove(job);
1440 KMenu *choices = dropMenus.take(job);
1443 #endif // PLASMA_NO_KIO
1448 QPointF pos = dropPoints.take(job);
1451 kDebug() <<
"remote applet access failed: " << job->errorText();
1456 kDebug() <<
"how did we end up here? if applet is null, the job->error should be nonzero";
1460 q->addApplet(job->
applet(), pos);
1463 void ContainmentPrivate::dropJobResult(
KJob *job)
1465 #ifndef PLASMA_NO_KIO
1466 KIO::TransferJob* tjob =
dynamic_cast<KIO::TransferJob*
>(job);
1468 kDebug() <<
"job is not a KIO::TransferJob, won't handle the drop...";
1469 clearDataForMimeJob(tjob);
1473 kDebug() <<
"ERROR" << tjob->error() <<
' ' << tjob->errorString();
1477 mimeTypeRetrieved(qobject_cast<KIO::Job *>(job), QString());
1478 #endif // PLASMA_NO_KIO
1481 void ContainmentPrivate::mimeTypeRetrieved(KIO::Job *job,
const QString &mimetype)
1483 #ifndef PLASMA_NO_KIO
1484 kDebug() <<
"Mimetype Job returns." << mimetype;
1485 KIO::TransferJob* tjob =
dynamic_cast<KIO::TransferJob*
>(job);
1487 kDebug() <<
"job should be a TransferJob, but isn't";
1488 clearDataForMimeJob(job);
1492 if (mimetype.isEmpty() && !appletList.count()) {
1493 clearDataForMimeJob(job);
1494 kDebug() <<
"No applets found matching the url (" << tjob->url() <<
") or the mimetype (" << mimetype <<
")";
1499 if (dropPoints.keys().contains(tjob)) {
1500 posi = dropPoints[tjob];
1501 kDebug() <<
"Received a suitable dropEvent at" << posi;
1503 kDebug() <<
"Bailing out. Cannot find associated dropEvent related to the TransferJob";
1504 clearDataForMimeJob(job);
1508 KMenu *choices = dropMenus.value(tjob);
1510 kDebug() <<
"Bailing out. No QMenu found for this job.";
1511 clearDataForMimeJob(job);
1516 args << tjob->url().url() << mimetype;
1518 kDebug() <<
"Creating menu for:" << mimetype << posi << args;
1521 KPluginInfo::List wallpaperList;
1522 if (drawWallpaper) {
1523 if (wallpaper && wallpaper->supportsMimetype(mimetype)) {
1524 wallpaperList << wallpaper->d->wallpaperDescription;
1530 if (!appletList.isEmpty() || !wallpaperList.isEmpty()) {
1532 QHash<QAction *, QString> actionsToApplets;
1533 choices->addTitle(i18n(
"Widgets"));
1534 foreach (
const KPluginInfo &info, appletList) {
1535 kDebug() << info.name();
1537 if (!info.icon().isEmpty()) {
1538 action = choices->addAction(KIcon(info.icon()), info.name());
1540 action = choices->addAction(info.name());
1543 actionsToApplets.insert(action, info.pluginName());
1544 kDebug() << info.pluginName();
1546 actionsToApplets.insert(choices->addAction(i18n(
"Icon")),
"icon");
1548 QHash<QAction *, QString> actionsToWallpapers;
1549 if (!wallpaperList.isEmpty()) {
1550 choices->addTitle(i18n(
"Wallpaper"));
1552 QMap<QString, KPluginInfo> sorted;
1553 foreach (
const KPluginInfo &info, appletList) {
1554 sorted.insert(info.name(), info);
1557 foreach (
const KPluginInfo &info, wallpaperList) {
1559 if (!info.icon().isEmpty()) {
1560 action = choices->addAction(KIcon(info.icon()), info.name());
1562 action = choices->addAction(info.name());
1565 actionsToWallpapers.insert(action, info.pluginName());
1569 QAction *choice = choices->exec();
1574 if (!mimetype.isEmpty() && !tjob->error()) {
1576 KIO::Scheduler::publishSlaveOnHold();
1578 QString plugin = actionsToApplets.value(choice);
1579 if (plugin.isEmpty()) {
1581 plugin = actionsToWallpapers.value(choice);
1582 if (!wallpaper || plugin != wallpaper->pluginName()) {
1583 kDebug() <<
"Wallpaper dropped:" << tjob->url();
1584 q->setWallpaper(plugin);
1588 kDebug() <<
"Wallpaper dropped:" << tjob->url();
1589 wallpaper->setUrls(KUrl::List() << tjob->url());
1592 addApplet(actionsToApplets[choice], args, QRectF(posi, QSize()));
1595 clearDataForMimeJob(job);
1600 addApplet(
"icon", args, QRectF(posi, QSize()));
1604 clearDataForMimeJob(job);
1605 #endif // PLASMA_NO_KIO
1608 #ifndef KDE_NO_DEPRECATED
1611 return d->toolBox.data();
1617 if (d->toolBox.data()) {
1618 d->toolBox.data()->deleteLater();
1625 return d->toolBox.data();
1633 if (d->isPanelContainment()) {
1636 QMetaObject::invokeMethod(
corona(),
"layoutContainments");
1640 d->wallpaper->setBoundingRect(QRectF(QPointF(0, 0), size()));
1649 if (event->key() == Qt::Key_Tab) {
1650 if (!d->applets.isEmpty()) {
1651 kDebug() <<
"let's give focus to...." << (
QObject*)d->applets.first();
1652 d->applets.first()->setFocus(Qt::TabFocusReason);
1660 if (d->appletAt(event->scenePos())) {
1664 if (d->wallpaper && d->wallpaper->isInitialized()) {
1665 QGraphicsItem *item = scene()->itemAt(event->scenePos());
1668 d->wallpaper->wheelEvent(event);
1670 if (event->isAccepted()) {
1678 if (d->prepareContainmentActions(trigger, event->screenPos())) {
1679 d->actionPlugins()->value(trigger)->contextEvent(event);
1683 Applet::wheelEvent(event);
1697 (change == QGraphicsItem::ItemSceneHasChanged ||
1698 change == QGraphicsItem::ItemPositionHasChanged)) {
1706 QMetaObject::invokeMethod(
corona(),
"layoutContainments");
1717 QAction *action = this->
action(name);
1719 action->setEnabled(enable);
1720 action->setVisible(enable);
1728 d->toolBox.data()->addTool(action);
1735 d->toolBox.data()->removeTool(action);
1750 return (d->toolBox && d->toolBox.data()->isShowing());
1755 if (d->toolBox && !d->toolBox.data()->isShowing()) {
1756 d->toolBox.data()->setShowing(
true);
1763 if (d->toolBox && d->toolBox.data()->isShowing()) {
1764 d->toolBox.data()->setShowing(
false);
1772 if (d->focusedApplet) {
1773 d->focusedApplet->addAssociatedWidget(widget);
1776 foreach (
const Applet *applet, d->applets) {
1777 if (applet->d->activationAction) {
1778 widget->addAction(applet->d->activationAction);
1786 if (d->focusedApplet) {
1787 d->focusedApplet->removeAssociatedWidget(widget);
1790 foreach (
const Applet *applet, d->applets) {
1791 if (applet->d->activationAction) {
1792 widget->removeAction(applet->d->activationAction);
1800 if (drawWallpaper) {
1801 KConfigGroup cfg =
config();
1806 delete d->wallpaper;
1813 return d->drawWallpaper;
1818 KConfigGroup cfg =
config();
1819 bool newPlugin =
true;
1820 bool newMode =
true;
1822 if (d->drawWallpaper) {
1825 if (d->wallpaper->pluginName() !=
pluginName) {
1826 delete d->wallpaper;
1831 newMode = d->wallpaper->renderingMode().name() != mode;
1836 if (!pluginName.isEmpty() && !d->wallpaper) {
1841 d->wallpaper->setParent(
this);
1842 d->wallpaper->setBoundingRect(QRectF(QPointF(0, 0), size()));
1843 d->wallpaper->setRenderingMode(mode);
1846 cfg.writeEntry(
"wallpaperplugin", pluginName);
1849 if (d->wallpaper->isInitialized()) {
1850 KConfigGroup wallpaperConfig = KConfigGroup(&cfg,
"Wallpaper");
1851 wallpaperConfig = KConfigGroup(&wallpaperConfig, pluginName);
1852 d->wallpaper->restore(wallpaperConfig);
1856 cfg.writeEntry(
"wallpaperpluginmode", mode);
1863 if (!d->wallpaper) {
1864 cfg.deleteEntry(
"wallpaperplugin");
1865 cfg.deleteEntry(
"wallpaperpluginmode");
1868 if (newPlugin || newMode) {
1869 if (newPlugin && d->wallpaper) {
1870 connect(d->wallpaper, SIGNAL(
configureRequested()),
this, SLOT(requestConfiguration()));
1880 return d->wallpaper;
1888 if (d->actionPlugins()->contains(trigger)) {
1889 plugin = d->actionPlugins()->value(trigger);
1891 d->actionPlugins()->remove(trigger);
1896 if (pluginName.isEmpty()) {
1897 cfg.deleteEntry(trigger);
1898 }
else if (plugin) {
1903 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
1904 plugin->
restore(pluginConfig);
1907 switch (d->containmentActionsSource) {
1908 case ContainmentPrivate::Activity:
1910 case ContainmentPrivate::Local:
1917 cfg.writeEntry(trigger, pluginName);
1918 d->actionPlugins()->insert(trigger, plugin);
1921 cfg.deleteEntry(trigger);
1930 return d->actionPlugins()->keys();
1949 foreach (
Applet *a, applets) {
1953 KConfigGroup c = q->config();
1959 if (!act.isEmpty()) {
1960 c.writeEntry(
"activityId", act);
1963 if (!act.isEmpty()) {
1964 c.writeEntry(
"activity", act);
1968 toolBox.data()->update();
1970 emit q->configNeedsSaving();
1971 emit q->contextChanged(con);
1976 return d->context()->currentActivity();
1981 return d->context();
1984 Context *ContainmentPrivate::context()
1995 KActionCollection* ContainmentPrivate::actions()
1997 return static_cast<Applet*
>(q)->d->actions;
2002 if (focusedApplet == applet) {
2006 QList<QWidget *> widgets = actions()->associatedWidgets();
2007 if (focusedApplet) {
2008 foreach (
QWidget *w, widgets) {
2009 focusedApplet->removeAssociatedWidget(w);
2013 if (applet && applets.contains(applet)) {
2015 focusedApplet = applet;
2016 foreach (
QWidget *w, widgets) {
2020 if (!focusedApplet->hasFocus()) {
2021 focusedApplet->setFocus(Qt::ShortcutFocusReason);
2030 if (d->applets.isEmpty()) {
2033 int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) + 1 : 0;
2034 if (index >= d->applets.size()) {
2037 kDebug() <<
"index" << index;
2038 d->focusApplet(d->applets.at(index));
2043 if (d->applets.isEmpty()) {
2046 int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) - 1 : -1;
2048 index = d->applets.size() - 1;
2050 kDebug() <<
"index" << index;
2051 d->focusApplet(d->applets.at(index));
2069 void ContainmentPrivate::configChanged()
2071 if (drawWallpaper) {
2072 KConfigGroup group = q->config();
2078 void ContainmentPrivate::requestConfiguration()
2080 emit q->configureRequested(q);
2086 if (appletStatus == q->status()) {
2087 emit q->newStatus(appletStatus);
2091 if (appletStatus < q->status()) {
2094 foreach (Applet *applet, applets) {
2095 if (applet->status() > appletStatus) {
2096 appletStatus = applet->status();
2101 q->setStatus(appletStatus);
2112 const QString title = i18nc(
"@title:window %1 is the name of the containment",
"Remove %1",
name());
2113 KGuiItem
remove = KStandardGuiItem::remove();
2114 remove.setText(title);
2115 if (KMessageBox::warningContinueCancel(
view(),
2116 i18nc(
"%1 is the name of the containment",
"Do you really want to remove this %1?",
name()),
2117 title,
remove) != KMessageBox::Continue) {
2125 void ContainmentPrivate::createToolBox()
2127 if (!toolBox && KAuthorized::authorizeKAction(
"plasma/containment_context_menu")) {
2131 QObject::connect(toolBox.data(), SIGNAL(toggled()), q, SIGNAL(toolBoxToggled()));
2132 QObject::connect(toolBox.data(), SIGNAL(toggled()), q, SLOT(updateToolBoxVisibility()));
2139 void ContainmentPrivate::positionToolBox()
2141 QMetaObject::invokeMethod(toolBox.data(),
"reposition");
2144 void ContainmentPrivate::updateToolBoxVisibility()
2146 emit q->toolBoxVisibilityChanged(toolBox.data()->isShowing());
2149 void ContainmentPrivate::triggerShowAddWidgets()
2151 emit q->showAddWidgetsInterface(QPointF());
2154 void ContainmentPrivate::containmentConstraintsEvent(Plasma::Constraints constraints)
2156 if (!q->isContainment()) {
2163 checkRemoveAction();
2164 const bool unlocked = q->immutability() ==
Mutable;
2165 q->setAcceptDrops(unlocked);
2166 q->enableAction(
"add widgets", unlocked);
2169 foreach (Applet *a, applets) {
2170 a->setImmutability(q->immutability());
2186 foreach (Applet *applet, applets) {
2187 applet->updateConstraints(appletConstraints);
2200 q->addToolBoxAction(q->action(
"remove"));
2201 checkRemoveAction();
2205 Applet *ContainmentPrivate::addApplet(
const QString &name,
const QVariantList &args,
2206 const QRectF &appletGeometry, uint
id,
bool delayInit)
2208 if (!q->isContainment()) {
2212 if (!delayInit && q->immutability() !=
Mutable) {
2213 kDebug() <<
"addApplet for" << name <<
"requested, but we're currently immutable!";
2219 v->setCursor(Qt::BusyCursor);
2228 kDebug() <<
"Applet" << name <<
"could not be loaded.";
2229 applet =
new Applet(0, QString(),
id);
2230 applet->setFailedToLaunch(
true, i18n(
"Could not find requested component: %1", name));
2235 q->addApplet(applet, appletGeometry.topLeft(), delayInit);
2239 bool ContainmentPrivate::regionIsEmpty(
const QRectF ®ion, Applet *ignoredApplet)
const
2241 foreach (Applet *applet, applets) {
2242 if (applet != ignoredApplet && applet->geometry().intersects(region)) {
2251 applets.removeAll(applet);
2252 if (focusedApplet == applet) {
2256 emit q->appletRemoved(applet);
2257 emit q->configNeedsSaving();
2260 void ContainmentPrivate::appletAppearAnimationComplete()
2262 Animation *anim = qobject_cast<Animation *>(q->sender());
2264 Applet *applet = qobject_cast<Applet*>(anim->targetWidget());
2266 appletAppeared(applet);
2271 void ContainmentPrivate::appletAppeared(Applet *applet)
2274 KConfigGroup *cg = applet->d->mainConfigGroup();
2276 emit q->configNeedsSaving();
2279 void ContainmentPrivate::positionPanel(
bool force)
2282 kDebug() <<
"no scene yet";
2287 if (ContainmentPrivate::s_positioningPanels) {
2295 const QPointF p = q->pos();
2298 p.y() + q->size().height() < -INTER_CONTAINMENT_MARGIN &&
2299 q->scene()->collidingItems(q).isEmpty()) {
2305 QPointF newPos = preferredPanelPos(q->corona());
2307 ContainmentPrivate::s_positioningPanels =
true;
2309 ContainmentPrivate::s_positioningPanels =
false;
2313 bool ContainmentPrivate::isPanelContainment()
const
2318 QPointF ContainmentPrivate::preferredPos(Corona *corona)
const
2322 if (isPanelContainment()) {
2324 return preferredPanelPos(corona);
2329 while (QGraphicsItem *i = corona->itemAt(pos, t)) {
2330 pos.setX(i->scenePos().x() + i->boundingRect().width() + 10);
2337 QPointF ContainmentPrivate::preferredPanelPos(Corona *corona)
const
2343 qreal bottom = horiz ? 0 : VERTICAL_STACKING_OFFSET;
2344 qreal lastHeight = 0;
2349 foreach (
const Containment *other, corona->containments()) {
2351 !other->d->isPanelContainment() ||
2358 qreal y = other->pos().y();
2360 lastHeight = other->size().height();
2364 qreal width = other->size().width();
2365 qreal x = other->pos().x() + width;
2368 bottom = x + lastHeight;
2377 bottom -= lastHeight + INTER_CONTAINMENT_MARGIN;
2379 kDebug() <<
"moved to" << QPointF(0, bottom - q->size().height());
2380 newPos = QPointF(0, bottom - q->size().height());
2382 bottom += lastHeight + INTER_CONTAINMENT_MARGIN;
2384 kDebug() <<
"moved to" << QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
2385 newPos = QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
2392 bool ContainmentPrivate::prepareContainmentActions(
const QString &trigger,
const QPoint &screenPos, KMenu *menu)
2394 ContainmentActions *plugin = actionPlugins()->value(trigger);
2398 plugin->setContainment(q);
2400 if (!plugin->isInitialized()) {
2401 KConfigGroup cfg = q->containmentActionsConfig();
2402 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
2403 plugin->restore(pluginConfig);
2406 if (plugin->configurationRequired()) {
2407 KMenu *localMenu = menu ? menu :
new KMenu();
2409 localMenu->addTitle(i18n(
"This plugin needs to be configured"));
2410 localMenu->addAction(q->action(
"configure"));
2413 localMenu->exec(screenPos);
2419 QList<QAction*> actions = plugin->contextualActions();
2420 if (actions.isEmpty()) {
2423 if (!isPanelContainment() && q->action(
"configure")) {
2424 menu->addAction(q->action(
"configure"));
2427 menu->addActions(actions);
2437 switch (d->containmentActionsSource) {
2438 case ContainmentPrivate::Local:
2440 cfg = KConfigGroup(&cfg,
"ActionPlugins");
2442 case ContainmentPrivate::Activity:
2444 cfg = KConfigGroup(&cfg, d->context()->currentActivityId());
2445 cfg = KConfigGroup(&cfg,
"ActionPlugins");
2448 cfg = KConfigGroup(
corona()->
config(),
"ActionPlugins");
2453 QHash<QString, ContainmentActions*> * ContainmentPrivate::actionPlugins()
2455 switch (containmentActionsSource) {
2459 return &localActionPlugins;
2461 return &globalActionPlugins;
2467 #include "containment.moc"