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 QAction *closeApplet = applet->d->actions->action(
"remove");
735 if (!desktopMenu.isEmpty()) {
736 desktopMenu.addSeparator();
740 desktopMenu.addAction(closeApplet);
745 Applet* ContainmentPrivate::appletAt(
const QPointF &point)
749 QGraphicsItem *item = q->scene()->itemAt(point);
755 if (item->isWidget()) {
758 if (applet->isContainment()) {
764 AppletHandle *handle =
dynamic_cast<AppletHandle*
>(item);
767 applet = handle->applet();
770 item = item->parentItem();
777 if (d->formFactor == formFactor) {
787 d->positionPanel(
true);
790 QMetaObject::invokeMethod(d->toolBox.data(),
"reposition");
794 KConfigGroup c =
config();
795 c.writeEntry(
"formfactor", (
int)formFactor);
801 if (d->location == location) {
805 bool emitGeomChange =
false;
809 emitGeomChange =
true;
814 emitGeomChange =
true;
819 foreach (
Applet *applet, d->applets) {
823 if (emitGeomChange) {
831 KConfigGroup c =
config();
832 c.writeEntry(
"location", (
int)location);
843 foreach (
Applet *applet, d->applets) {
844 applet->d->cleanUpAndDelete();
851 const QRectF &appletGeometry)
853 return d->addApplet(name, args, appletGeometry);
863 kDebug() <<
"adding null applet!?!";
867 if (d->applets.contains(applet)) {
868 kDebug() <<
"already have this applet!";
878 if (currentContainment && currentContainment !=
this) {
880 if (currentContainment->d->focusedApplet == applet) {
881 currentContainment->d->focusedApplet = 0;
884 disconnect(applet, 0, currentContainment, 0);
885 KConfigGroup oldConfig = applet->
config();
886 currentContainment->d->applets.removeAll(applet);
887 applet->setParentItem(
this);
888 applet->setParent(
this);
892 KConfigGroup c =
config().group(
"Applets").group(QString::number(applet->
id()));
893 oldConfig.reparent(&c);
894 applet->d->resetConfigurationObject();
896 disconnect(applet, SIGNAL(
activate()), currentContainment, SIGNAL(
activate()));
898 applet->setParentItem(
this);
899 applet->setParent(
this);
902 d->applets << applet;
910 if (pos != QPointF(-1, -1)) {
914 if (!delayInit && !currentContainment) {
915 applet->
restore(*applet->d->mainConfigGroup());
919 connect(anim, SIGNAL(finished()),
this, SLOT(appletAppearAnimationComplete()));
923 anim->setDirection(QAbstractAnimation::Backward);
924 anim->start(QAbstractAnimation::DeleteWhenStopped);
926 d->appletAppeared(applet);
930 applet->setFlag(QGraphicsItem::ItemIsMovable,
true);
937 if (!currentContainment) {
945 applet->d->scheduleModificationNotification();
956 d->setScreen(newScreen, newDesktop);
959 void ContainmentPrivate::setScreen(
int newScreen,
int newDesktop,
bool preventInvalidDesktops)
971 Corona *corona = q->corona();
980 if (newScreen < -1) {
985 if (newDesktop < -1 || (preventInvalidDesktops && newDesktop > KWindowSystem::numberOfDesktops() - 1)) {
991 Containment *swapScreensWith(0);
994 if (isDesktopContainment) {
997 if (screen < 0 && newScreen > -1) {
998 QObject::connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), toolBox.data(), SLOT(reposition()), Qt::UniqueConnection);
999 }
else if (newScreen < 0) {
1000 QObject::disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), toolBox.data(), SLOT(reposition()));
1004 if (newScreen > -1) {
1007 if (currently && currently != q) {
1008 kDebug() <<
"currently is on screen" << currently->
screen()
1009 <<
"desktop" << currently->desktop()
1010 <<
"and is" << currently->activity()
1012 currently->setScreen(-1, currently->desktop());
1013 swapScreensWith = currently;
1018 if (newScreen < numScreens && newScreen > -1 && isDesktopContainment) {
1022 int oldDesktop = desktop;
1023 desktop = newDesktop;
1025 int oldScreen = screen;
1030 if (oldScreen != newScreen || oldDesktop != newDesktop) {
1036 KConfigGroup c = q->
config();
1037 c.writeEntry(
"screen", screen);
1038 c.writeEntry(
"desktop", desktop);
1039 if (newScreen != -1) {
1040 lastScreen = newScreen;
1041 lastDesktop = newDesktop;
1042 c.writeEntry(
"lastScreen", lastScreen);
1043 c.writeEntry(
"lastDesktop", lastDesktop);
1045 emit q->configNeedsSaving();
1046 emit q->screenChanged(oldScreen, newScreen, q);
1049 if (swapScreensWith) {
1051 swapScreensWith->setScreen(oldScreen, oldDesktop);
1054 checkRemoveAction();
1056 if (newScreen >= 0) {
1068 return d->lastScreen;
1078 return d->lastDesktop;
1082 const QString &parentApp)
1089 const QString &category,
1090 const QString &parentApp)
1094 if (parentApp.isEmpty()) {
1095 constraint.append(
"(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
1097 constraint.append(
"[X-KDE-ParentApp] == '").append(parentApp).append(
"'");
1100 if (!type.isEmpty()) {
1101 if (!constraint.isEmpty()) {
1102 constraint.append(
" and ");
1105 constraint.append(
"'").append(type).append(
"' ~in [X-Plasma-ContainmentCategories]");
1108 if (!category.isEmpty()) {
1109 if (!constraint.isEmpty()) {
1110 constraint.append(
" and ");
1113 constraint.append(
"[X-KDE-PluginInfo-Category] == '").append(category).append(
"'");
1114 if (category ==
"Miscellaneous") {
1115 constraint.append(
" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
1119 KService::List offers = KServiceTypeTrader::self()->query(
"Plasma/Containment", constraint);
1121 return KPluginInfo::fromServices(offers);
1126 const QString constraint = QString(
"'%1' in [X-Plasma-DropMimeTypes]").arg(mimetype);
1128 const KService::List offers = KServiceTypeTrader::self()->query(
"Plasma/Containment", constraint);
1129 return KPluginInfo::fromServices(offers);
1135 QSet<QString> types;
1137 foreach (
const KPluginInfo &containmentInfo, containmentInfos) {
1138 QStringList theseTypes = containmentInfo.service()->property(
"X-Plasma-ContainmentCategories").toStringList();
1139 foreach (
const QString &
type, theseTypes) {
1144 return types.toList();
1151 (event->mimeData()->hasFormat(static_cast<Corona*>(scene())->appletMimeType()) ||
1152 KUrl::List::canDecode(event->mimeData()) ||
1153 event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())));
1155 if (!event->isAccepted()) {
1157 QStringList formats =
event->mimeData()->formats();
1159 foreach (
const QString &format, formats) {
1161 if (!appletList.isEmpty()) {
1162 event->setAccepted(
true);
1167 if (!event->isAccepted()) {
1168 foreach (
const QString &format, formats) {
1170 if (!wallpaperList.isEmpty()) {
1171 event->setAccepted(
true);
1178 if (event->isAccepted()) {
1179 if (d->dropZoneStarted) {
1182 if (!d->showDropZoneDelayTimer) {
1183 d->showDropZoneDelayTimer =
new QTimer(
this);
1184 d->showDropZoneDelayTimer->setInterval(300);
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();
1198 if (d->showDropZoneDelayTimer) {
1199 d->showDropZoneDelayTimer->stop();
1202 if (event->pos().y() < 1 ||
event->pos().y() > size().height() ||
1203 event->pos().x() < 1 ||
event->pos().x() > size().width()) {
1205 d->dropZoneStarted =
false;
1209 void ContainmentPrivate::showDropZoneDelayed()
1211 dropZoneStarted =
true;
1212 q->showDropZone(dropPoints.value(0).toPoint());
1213 dropPoints.remove(0);
1218 QGraphicsItem *item = scene()->itemAt(event->scenePos());
1219 event->setAccepted(item ==
this || item == d->toolBox.data() || !item);
1221 if (!event->isAccepted()) {
1222 if (d->showDropZoneDelayTimer) {
1223 d->showDropZoneDelayTimer->stop();
1233 d->dropData(event->scenePos(),
event->screenPos(), event);
1235 Applet::dropEvent(event);
1239 void ContainmentPrivate::dropData(QPointF scenePos, QPoint screenPos, QGraphicsSceneDragDropEvent *dropEvent)
1241 if (q->immutability() !=
Mutable) {
1245 QPointF pos = q->mapFromScene(scenePos);
1246 const QMimeData *mimeData = 0;
1249 mimeData = dropEvent->mimeData();
1251 QClipboard *clipboard = QApplication::clipboard();
1252 mimeData = clipboard->mimeData(QClipboard::Selection);
1258 kDebug() <<
"no mime data";
1264 QString appletMimetype(q->corona() ? q->corona()->appletMimeType() : QString());
1266 if (!appletMimetype.isEmpty() && mimeData->hasFormat(appletMimetype)) {
1267 QString data = mimeData->data(appletMimetype);
1268 const QStringList appletNames = data.split(
'\n', QString::SkipEmptyParts);
1269 foreach (
const QString &appletName, appletNames) {
1271 QRectF geom(pos, QSize(0, 0));
1272 q->addApplet(appletName, QVariantList(), geom);
1275 dropEvent->acceptProposedAction();
1277 }
else if (mimeData->hasFormat(ExtenderItemMimeData::mimeType())) {
1278 kDebug() <<
"mimetype plasma/extenderitem is dropped, creating internal:extender";
1280 const ExtenderItemMimeData *extenderData = qobject_cast<
const ExtenderItemMimeData*>(mimeData);
1282 ExtenderItem *item = extenderData->extenderItem();
1283 QRectF geometry(pos - extenderData->pointerOffset(), item->size());
1284 kDebug() <<
"desired geometry: " << geometry;
1285 Applet *applet = qobject_cast<ExtenderApplet *>(item->extender() ? item->extender()->applet() : 0);
1287 qreal left, top, right, bottom;
1288 applet->getContentsMargins(&left, &top, &right, &bottom);
1289 applet->setPos(geometry.topLeft() - QPointF(
int(left),
int(top)));
1292 applet = addApplet(
"internal:extender", QVariantList(), geometry, 0,
true);
1295 appletAppeared(applet);
1296 applet->flushPendingConstraintsEvents();
1297 applet->d->scheduleModificationNotification();
1298 applet->adjustSize();
1301 item->setExtender(applet->extender());
1303 }
else if (KUrl::List::canDecode(mimeData)) {
1306 const KUrl::List urls = KUrl::List::fromMimeData(mimeData);
1307 foreach (
const KUrl &url, urls) {
1311 dropPoints[job] = dropEvent->pos();
1313 dropPoints[job] = scenePos;
1318 #ifndef PLASMA_NO_KIO
1320 KMimeType::Ptr mime = KMimeType::findByUrl(url);
1321 QString mimeName = mime->name();
1322 QRectF geom(pos, QSize());
1325 kDebug() <<
"can decode" << mimeName << args;
1328 KIO::JobFlags flags = KIO::HideProgressInfo;
1329 KIO::MimetypeJob *job = KIO::mimetype(url, flags);
1331 dropPoints[job] = dropEvent->pos();
1333 dropPoints[job] = scenePos;
1336 QObject::connect(job, SIGNAL(result(
KJob*)), q, SLOT(dropJobResult(
KJob*)));
1337 QObject::connect(job, SIGNAL(mimetype(KIO::Job*,QString)),
1338 q, SLOT(mimeTypeRetrieved(KIO::Job*,QString)));
1340 KMenu *choices =
new KMenu(
"Content dropped");
1341 choices->addAction(KIcon(
"process-working"), i18n(
"Fetching file type..."));
1343 choices->popup(dropEvent->screenPos());
1345 choices->popup(screenPos);
1348 dropMenus[job] = choices;
1354 dropEvent->acceptProposedAction();
1357 QStringList formats = mimeData->formats();
1358 QHash<QString, KPluginInfo> seenPlugins;
1359 QHash<QString, QString> pluginFormats;
1361 foreach (
const QString &format, formats) {
1364 foreach (
const KPluginInfo &plugin, plugins) {
1365 if (seenPlugins.contains(plugin.pluginName())) {
1369 seenPlugins.insert(plugin.pluginName(), plugin);
1370 pluginFormats.insert(plugin.pluginName(), format);
1375 QString selectedPlugin;
1377 if (seenPlugins.isEmpty()) {
1379 }
else if (seenPlugins.count() == 1) {
1380 selectedPlugin = seenPlugins.constBegin().key();
1383 QHash<QAction *, QString> actionsToPlugins;
1384 foreach (
const KPluginInfo &info, seenPlugins) {
1386 if (!info.icon().isEmpty()) {
1387 action = choices.addAction(KIcon(info.icon()), info.name());
1389 action = choices.addAction(info.name());
1392 actionsToPlugins.insert(action, info.pluginName());
1395 QAction *choice = choices.exec(screenPos);
1397 selectedPlugin = actionsToPlugins[choice];
1401 if (!selectedPlugin.isEmpty()) {
1407 QClipboard *clipboard = QApplication::clipboard();
1408 mimeData = clipboard->mimeData(QClipboard::Selection);
1411 KTemporaryFile tempFile;
1412 if (mimeData && tempFile.open()) {
1414 tempFile.setAutoRemove(
false);
1417 QDataStream stream(&tempFile);
1418 QByteArray data = mimeData->data(pluginFormats[selectedPlugin]);
1419 stream.writeRawData(data, data.size());
1422 QRectF geom(pos, QSize());
1424 args << tempFile.fileName();
1428 q->addApplet(selectedPlugin, args, geom);
1434 void ContainmentPrivate::clearDataForMimeJob(KIO::Job *job)
1436 #ifndef PLASMA_NO_KIO
1437 QObject::disconnect(job, 0, q, 0);
1438 dropPoints.remove(job);
1439 KMenu *choices = dropMenus.take(job);
1442 #endif // PLASMA_NO_KIO
1447 QPointF pos = dropPoints.take(job);
1450 kDebug() <<
"remote applet access failed: " << job->errorText();
1455 kDebug() <<
"how did we end up here? if applet is null, the job->error should be nonzero";
1459 q->addApplet(job->
applet(), pos);
1462 void ContainmentPrivate::dropJobResult(
KJob *job)
1464 #ifndef PLASMA_NO_KIO
1465 KIO::TransferJob* tjob =
dynamic_cast<KIO::TransferJob*
>(job);
1467 kDebug() <<
"job is not a KIO::TransferJob, won't handle the drop...";
1468 clearDataForMimeJob(tjob);
1472 kDebug() <<
"ERROR" << tjob->error() <<
' ' << tjob->errorString();
1476 mimeTypeRetrieved(qobject_cast<KIO::Job *>(job), QString());
1477 #endif // PLASMA_NO_KIO
1480 void ContainmentPrivate::mimeTypeRetrieved(KIO::Job *job,
const QString &mimetype)
1482 #ifndef PLASMA_NO_KIO
1483 kDebug() <<
"Mimetype Job returns." << mimetype;
1484 KIO::TransferJob* tjob =
dynamic_cast<KIO::TransferJob*
>(job);
1486 kDebug() <<
"job should be a TransferJob, but isn't";
1487 clearDataForMimeJob(job);
1491 if (mimetype.isEmpty() && !appletList.count()) {
1492 clearDataForMimeJob(job);
1493 kDebug() <<
"No applets found matching the url (" << tjob->url() <<
") or the mimetype (" << mimetype <<
")";
1498 if (dropPoints.keys().contains(tjob)) {
1499 posi = dropPoints[tjob];
1500 kDebug() <<
"Received a suitable dropEvent at" << posi;
1502 kDebug() <<
"Bailing out. Cannot find associated dropEvent related to the TransferJob";
1503 clearDataForMimeJob(job);
1507 KMenu *choices = dropMenus.value(tjob);
1509 kDebug() <<
"Bailing out. No QMenu found for this job.";
1510 clearDataForMimeJob(job);
1515 args << tjob->url().url() << mimetype;
1517 kDebug() <<
"Creating menu for:" << mimetype << posi << args;
1520 KPluginInfo::List wallpaperList;
1521 if (drawWallpaper) {
1522 if (wallpaper && wallpaper->supportsMimetype(mimetype)) {
1523 wallpaperList << wallpaper->d->wallpaperDescription;
1529 if (!appletList.isEmpty() || !wallpaperList.isEmpty()) {
1531 QHash<QAction *, QString> actionsToApplets;
1532 choices->addTitle(i18n(
"Widgets"));
1533 foreach (
const KPluginInfo &info, appletList) {
1534 kDebug() << info.name();
1536 if (!info.icon().isEmpty()) {
1537 action = choices->addAction(KIcon(info.icon()), info.name());
1539 action = choices->addAction(info.name());
1542 actionsToApplets.insert(action, info.pluginName());
1543 kDebug() << info.pluginName();
1545 actionsToApplets.insert(choices->addAction(i18n(
"Icon")),
"icon");
1547 QHash<QAction *, QString> actionsToWallpapers;
1548 if (!wallpaperList.isEmpty()) {
1549 choices->addTitle(i18n(
"Wallpaper"));
1551 QMap<QString, KPluginInfo> sorted;
1552 foreach (
const KPluginInfo &info, appletList) {
1553 sorted.insert(info.name(), info);
1556 foreach (
const KPluginInfo &info, wallpaperList) {
1558 if (!info.icon().isEmpty()) {
1559 action = choices->addAction(KIcon(info.icon()), info.name());
1561 action = choices->addAction(info.name());
1564 actionsToWallpapers.insert(action, info.pluginName());
1568 QAction *choice = choices->exec();
1573 if (!mimetype.isEmpty() && !tjob->error()) {
1575 KIO::Scheduler::publishSlaveOnHold();
1577 QString plugin = actionsToApplets.value(choice);
1578 if (plugin.isEmpty()) {
1580 plugin = actionsToWallpapers.value(choice);
1581 if (!wallpaper || plugin != wallpaper->pluginName()) {
1582 kDebug() <<
"Wallpaper dropped:" << tjob->url();
1583 q->setWallpaper(plugin);
1587 kDebug() <<
"Wallpaper dropped:" << tjob->url();
1588 wallpaper->setUrls(KUrl::List() << tjob->url());
1591 addApplet(actionsToApplets[choice], args, QRectF(posi, QSize()));
1594 clearDataForMimeJob(job);
1599 addApplet(
"icon", args, QRectF(posi, QSize()));
1603 clearDataForMimeJob(job);
1604 #endif // PLASMA_NO_KIO
1607 #ifndef KDE_NO_DEPRECATED
1610 return d->toolBox.data();
1616 if (d->toolBox.data()) {
1617 d->toolBox.data()->deleteLater();
1624 return d->toolBox.data();
1632 if (d->isPanelContainment()) {
1635 QMetaObject::invokeMethod(
corona(),
"layoutContainments");
1639 d->wallpaper->setBoundingRect(QRectF(QPointF(0, 0), size()));
1648 if (event->key() == Qt::Key_Tab) {
1649 if (!d->applets.isEmpty()) {
1650 kDebug() <<
"let's give focus to...." << (
QObject*)d->applets.first();
1651 d->applets.first()->setFocus(Qt::TabFocusReason);
1659 if (d->appletAt(event->scenePos())) {
1663 if (d->wallpaper && d->wallpaper->isInitialized()) {
1664 QGraphicsItem *item = scene()->itemAt(event->scenePos());
1667 d->wallpaper->wheelEvent(event);
1669 if (event->isAccepted()) {
1677 if (d->prepareContainmentActions(trigger, event->screenPos())) {
1678 d->actionPlugins()->value(trigger)->contextEvent(event);
1682 Applet::wheelEvent(event);
1696 (change == QGraphicsItem::ItemSceneHasChanged ||
1697 change == QGraphicsItem::ItemPositionHasChanged)) {
1705 QMetaObject::invokeMethod(
corona(),
"layoutContainments");
1716 QAction *action = this->
action(name);
1718 action->setEnabled(enable);
1719 action->setVisible(enable);
1727 d->toolBox.data()->addTool(action);
1734 d->toolBox.data()->removeTool(action);
1749 return (d->toolBox && d->toolBox.data()->isShowing());
1754 if (d->toolBox && !d->toolBox.data()->isShowing()) {
1755 d->toolBox.data()->setShowing(
true);
1762 if (d->toolBox && d->toolBox.data()->isShowing()) {
1763 d->toolBox.data()->setShowing(
false);
1771 if (d->focusedApplet) {
1772 d->focusedApplet->addAssociatedWidget(widget);
1775 foreach (
const Applet *applet, d->applets) {
1776 if (applet->d->activationAction) {
1777 widget->addAction(applet->d->activationAction);
1785 if (d->focusedApplet) {
1786 d->focusedApplet->removeAssociatedWidget(widget);
1789 foreach (
const Applet *applet, d->applets) {
1790 if (applet->d->activationAction) {
1791 widget->removeAction(applet->d->activationAction);
1799 if (drawWallpaper) {
1800 KConfigGroup cfg =
config();
1805 delete d->wallpaper;
1812 return d->drawWallpaper;
1817 KConfigGroup cfg =
config();
1818 bool newPlugin =
true;
1819 bool newMode =
true;
1821 if (d->drawWallpaper) {
1824 if (d->wallpaper->pluginName() !=
pluginName) {
1825 delete d->wallpaper;
1830 newMode = d->wallpaper->renderingMode().name() != mode;
1835 if (!pluginName.isEmpty() && !d->wallpaper) {
1840 d->wallpaper->setParent(
this);
1841 d->wallpaper->setBoundingRect(QRectF(QPointF(0, 0), size()));
1842 d->wallpaper->setRenderingMode(mode);
1845 cfg.writeEntry(
"wallpaperplugin", pluginName);
1848 if (d->wallpaper->isInitialized()) {
1849 KConfigGroup wallpaperConfig = KConfigGroup(&cfg,
"Wallpaper");
1850 wallpaperConfig = KConfigGroup(&wallpaperConfig, pluginName);
1851 d->wallpaper->restore(wallpaperConfig);
1855 cfg.writeEntry(
"wallpaperpluginmode", mode);
1862 if (!d->wallpaper) {
1863 cfg.deleteEntry(
"wallpaperplugin");
1864 cfg.deleteEntry(
"wallpaperpluginmode");
1867 if (newPlugin || newMode) {
1868 if (newPlugin && d->wallpaper) {
1869 connect(d->wallpaper, SIGNAL(
configureRequested()),
this, SLOT(requestConfiguration()));
1879 return d->wallpaper;
1887 if (d->actionPlugins()->contains(trigger)) {
1888 plugin = d->actionPlugins()->value(trigger);
1890 d->actionPlugins()->remove(trigger);
1895 if (pluginName.isEmpty()) {
1896 cfg.deleteEntry(trigger);
1897 }
else if (plugin) {
1902 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
1903 plugin->
restore(pluginConfig);
1906 switch (d->containmentActionsSource) {
1907 case ContainmentPrivate::Activity:
1909 case ContainmentPrivate::Local:
1916 cfg.writeEntry(trigger, pluginName);
1917 d->actionPlugins()->insert(trigger, plugin);
1920 cfg.deleteEntry(trigger);
1929 return d->actionPlugins()->keys();
1948 foreach (
Applet *a, applets) {
1952 KConfigGroup c = q->config();
1958 if (!act.isEmpty()) {
1959 c.writeEntry(
"activityId", act);
1962 if (!act.isEmpty()) {
1963 c.writeEntry(
"activity", act);
1967 toolBox.data()->update();
1969 emit q->configNeedsSaving();
1970 emit q->contextChanged(con);
1975 return d->context()->currentActivity();
1980 return d->context();
1983 Context *ContainmentPrivate::context()
1994 KActionCollection* ContainmentPrivate::actions()
1996 return static_cast<Applet*
>(q)->d->actions;
2001 if (focusedApplet == applet) {
2005 QList<QWidget *> widgets = actions()->associatedWidgets();
2006 if (focusedApplet) {
2007 foreach (
QWidget *w, widgets) {
2008 focusedApplet->removeAssociatedWidget(w);
2012 if (applet && applets.contains(applet)) {
2014 focusedApplet = applet;
2015 foreach (
QWidget *w, widgets) {
2019 if (!focusedApplet->hasFocus()) {
2020 focusedApplet->setFocus(Qt::ShortcutFocusReason);
2029 if (d->applets.isEmpty()) {
2032 int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) + 1 : 0;
2033 if (index >= d->applets.size()) {
2036 kDebug() <<
"index" << index;
2037 d->focusApplet(d->applets.at(index));
2042 if (d->applets.isEmpty()) {
2045 int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) - 1 : -1;
2047 index = d->applets.size() - 1;
2049 kDebug() <<
"index" << index;
2050 d->focusApplet(d->applets.at(index));
2068 void ContainmentPrivate::configChanged()
2070 if (drawWallpaper) {
2071 KConfigGroup group = q->config();
2077 void ContainmentPrivate::requestConfiguration()
2079 emit q->configureRequested(q);
2085 if (appletStatus == q->status()) {
2086 emit q->newStatus(appletStatus);
2090 if (appletStatus < q->status()) {
2093 foreach (Applet *applet, applets) {
2094 if (applet->status() > appletStatus) {
2095 appletStatus = applet->status();
2100 q->setStatus(appletStatus);
2111 const QString title = i18nc(
"@title:window %1 is the name of the containment",
"Remove %1",
name());
2112 KGuiItem
remove = KStandardGuiItem::remove();
2113 remove.setText(title);
2114 if (KMessageBox::warningContinueCancel(
view(),
2115 i18nc(
"%1 is the name of the containment",
"Do you really want to remove this %1?",
name()),
2116 title,
remove) != KMessageBox::Continue) {
2124 void ContainmentPrivate::createToolBox()
2126 if (!toolBox && KAuthorized::authorizeKAction(
"plasma/containment_context_menu")) {
2130 QObject::connect(toolBox.data(), SIGNAL(toggled()), q, SIGNAL(toolBoxToggled()));
2131 QObject::connect(toolBox.data(), SIGNAL(toggled()), q, SLOT(updateToolBoxVisibility()));
2138 void ContainmentPrivate::positionToolBox()
2140 QMetaObject::invokeMethod(toolBox.data(),
"reposition");
2143 void ContainmentPrivate::updateToolBoxVisibility()
2145 emit q->toolBoxVisibilityChanged(toolBox.data()->isShowing());
2148 void ContainmentPrivate::triggerShowAddWidgets()
2150 emit q->showAddWidgetsInterface(QPointF());
2153 void ContainmentPrivate::containmentConstraintsEvent(Plasma::Constraints constraints)
2155 if (!q->isContainment()) {
2162 checkRemoveAction();
2163 const bool unlocked = q->immutability() ==
Mutable;
2164 q->setAcceptDrops(unlocked);
2165 q->enableAction(
"add widgets", unlocked);
2168 foreach (Applet *a, applets) {
2169 a->setImmutability(q->immutability());
2185 foreach (Applet *applet, applets) {
2186 applet->updateConstraints(appletConstraints);
2199 q->addToolBoxAction(q->action(
"remove"));
2200 checkRemoveAction();
2204 Applet *ContainmentPrivate::addApplet(
const QString &name,
const QVariantList &args,
2205 const QRectF &appletGeometry, uint
id,
bool delayInit)
2207 if (!q->isContainment()) {
2211 if (!delayInit && q->immutability() !=
Mutable) {
2212 kDebug() <<
"addApplet for" << name <<
"requested, but we're currently immutable!";
2218 v->setCursor(Qt::BusyCursor);
2227 kDebug() <<
"Applet" << name <<
"could not be loaded.";
2228 applet =
new Applet(0, QString(),
id);
2229 applet->setFailedToLaunch(
true, i18n(
"Could not find requested component: %1", name));
2234 q->addApplet(applet, appletGeometry.topLeft(), delayInit);
2238 bool ContainmentPrivate::regionIsEmpty(
const QRectF ®ion, Applet *ignoredApplet)
const
2240 foreach (Applet *applet, applets) {
2241 if (applet != ignoredApplet && applet->geometry().intersects(region)) {
2250 applets.removeAll(applet);
2251 if (focusedApplet == applet) {
2255 emit q->appletRemoved(applet);
2256 emit q->configNeedsSaving();
2259 void ContainmentPrivate::appletAppearAnimationComplete()
2261 Animation *anim = qobject_cast<Animation *>(q->sender());
2263 Applet *applet = qobject_cast<Applet*>(anim->targetWidget());
2265 appletAppeared(applet);
2270 void ContainmentPrivate::appletAppeared(Applet *applet)
2273 KConfigGroup *cg = applet->d->mainConfigGroup();
2275 emit q->configNeedsSaving();
2278 void ContainmentPrivate::positionPanel(
bool force)
2281 kDebug() <<
"no scene yet";
2286 if (ContainmentPrivate::s_positioningPanels) {
2294 const QPointF p = q->pos();
2297 p.y() + q->size().height() < -INTER_CONTAINMENT_MARGIN &&
2298 q->scene()->collidingItems(q).isEmpty()) {
2304 QPointF newPos = preferredPanelPos(q->corona());
2306 ContainmentPrivate::s_positioningPanels =
true;
2308 ContainmentPrivate::s_positioningPanels =
false;
2312 bool ContainmentPrivate::isPanelContainment()
const
2317 QPointF ContainmentPrivate::preferredPos(Corona *corona)
const
2321 if (isPanelContainment()) {
2323 return preferredPanelPos(corona);
2328 while (QGraphicsItem *i = corona->itemAt(pos, t)) {
2329 pos.setX(i->scenePos().x() + i->boundingRect().width() + 10);
2336 QPointF ContainmentPrivate::preferredPanelPos(Corona *corona)
const
2342 qreal bottom = horiz ? 0 : VERTICAL_STACKING_OFFSET;
2343 qreal lastHeight = 0;
2348 foreach (
const Containment *other, corona->containments()) {
2350 !other->d->isPanelContainment() ||
2357 qreal y = other->pos().y();
2359 lastHeight = other->size().height();
2363 qreal width = other->size().width();
2364 qreal x = other->pos().x() + width;
2367 bottom = x + lastHeight;
2376 bottom -= lastHeight + INTER_CONTAINMENT_MARGIN;
2378 kDebug() <<
"moved to" << QPointF(0, bottom - q->size().height());
2379 newPos = QPointF(0, bottom - q->size().height());
2381 bottom += lastHeight + INTER_CONTAINMENT_MARGIN;
2383 kDebug() <<
"moved to" << QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
2384 newPos = QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
2391 bool ContainmentPrivate::prepareContainmentActions(
const QString &trigger,
const QPoint &screenPos, KMenu *menu)
2393 ContainmentActions *plugin = actionPlugins()->value(trigger);
2397 plugin->setContainment(q);
2399 if (!plugin->isInitialized()) {
2400 KConfigGroup cfg = q->containmentActionsConfig();
2401 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
2402 plugin->restore(pluginConfig);
2405 if (plugin->configurationRequired()) {
2406 KMenu *localMenu = menu ? menu :
new KMenu();
2408 localMenu->addTitle(i18n(
"This plugin needs to be configured"));
2409 localMenu->addAction(q->action(
"configure"));
2412 localMenu->exec(screenPos);
2418 QList<QAction*> actions = plugin->contextualActions();
2419 if (actions.isEmpty()) {
2422 if (!isPanelContainment() && q->action(
"configure")) {
2423 menu->addAction(q->action(
"configure"));
2426 menu->addActions(actions);
2436 switch (d->containmentActionsSource) {
2437 case ContainmentPrivate::Local:
2439 cfg = KConfigGroup(&cfg,
"ActionPlugins");
2441 case ContainmentPrivate::Activity:
2443 cfg = KConfigGroup(&cfg, d->context()->currentActivityId());
2444 cfg = KConfigGroup(&cfg,
"ActionPlugins");
2447 cfg = KConfigGroup(
corona()->
config(),
"ActionPlugins");
2452 QHash<QString, ContainmentActions*> * ContainmentPrivate::actionPlugins()
2454 switch (containmentActionsSource) {
2458 return &localActionPlugins;
2460 return &globalActionPlugins;
2466 #include "containment.moc"