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),
126 d(new ContainmentPrivate(this))
136 : Plasma::
Applet(packagePath, appletId, args),
137 d(new ContainmentPrivate(this))
150 Applet::d->isContainment =
false;
162 setFlag(QGraphicsItem::ItemIsMovable,
false);
163 setFlag(QGraphicsItem::ItemClipsChildrenToShape,
true);
164 setAcceptDrops(
true);
165 setAcceptsHoverEvents(
true);
172 ContainmentPrivate::addDefaultActions(d->actions(),
this);
177 QAction *closeApplet =
action(
"remove");
179 closeApplet->setText(i18nc(
"%1 is the name of the applet",
"Remove this %1",
name()));
182 QAction *configAction =
action(
"configure");
184 configAction->setText(i18nc(
"%1 is the name of the applet",
"%1 Settings",
name()));
187 QAction *appletBrowserAction =
action(
"add widgets");
188 if (appletBrowserAction) {
189 appletBrowserAction->setVisible(unlocked);
190 appletBrowserAction->setEnabled(unlocked);
191 connect(appletBrowserAction, SIGNAL(triggered()),
this, SLOT(triggerShowAddWidgets()));
194 QAction *act =
action(
"next applet");
199 act =
action(
"previous applet");
205 QAction *lockDesktopAction =
corona()->
action(
"lock widgets");
207 if (lockDesktopAction) {
208 d->actions()->addAction(
"lock widgets", lockDesktopAction);
216 d->actions()->addAction(
"manage activities", act);
221 d->actions()->addAction(
"configure shortcuts", act);
231 QAction *configureContainment =
action(
"configure");
232 if (configureContainment) {
239 void ContainmentPrivate::addDefaultActions(KActionCollection *actions,
Containment *c)
241 actions->setConfigGroup(
"Shortcuts-Containment");
244 KAction *appAction = qobject_cast<KAction*>(actions->action(
"remove"));
245 appAction->setShortcut(KShortcut(
"alt+d, alt+r"));
246 if (c && c->d->isPanelContainment()) {
247 appAction->setText(i18n(
"Remove this Panel"));
249 appAction->setText(i18n(
"Remove this Activity"));
252 appAction = qobject_cast<KAction*>(actions->action(
"configure"));
254 appAction->setShortcut(KShortcut(
"alt+d, alt+s"));
255 appAction->setText(i18n(
"Activity Settings"));
259 KAction *appletBrowserAction = actions->addAction(
"add widgets");
260 appletBrowserAction->setAutoRepeat(
false);
261 appletBrowserAction->setText(i18n(
"Add Widgets..."));
262 appletBrowserAction->setIcon(KIcon(
"list-add"));
263 appletBrowserAction->setShortcut(KShortcut(
"alt+d, a"));
266 KAction *action = actions->addAction(
"next applet");
267 action->setText(i18n(
"Next Widget"));
269 action->setShortcut(KShortcut(
"alt+d, n"));
272 action = actions->addAction(
"previous applet");
273 action->setText(i18n(
"Previous Widget"));
275 action->setShortcut(KShortcut(
"alt+d, p"));
282 QPointF p1 = c1.readEntry(
"geometry", QRectF()).topLeft();
283 QPointF p2 = c2.readEntry(
"geometry", QRectF()).topLeft();
285 if (!qFuzzyCompare(p1.x(), p2.x())) {
286 if (QApplication::layoutDirection() == Qt::RightToLeft) {
287 return p1.x() > p2.x();
290 return p1.x() < p2.x();
293 return qFuzzyCompare(p1.y(), p2.y()) || p1.y() < p2.y();
308 QRectF geo = group.readEntry(
"geometry",
geometry());
312 if (geo.size() != geo.size().boundedTo(maximumSize())) {
313 setMaximumSize(maximumSize().expandedTo(geo.size()));
316 if (geo.size() != geo.size().expandedTo(minimumSize())) {
317 setMinimumSize(minimumSize().boundedTo(geo.size()));
330 d->lastScreen = group.readEntry(
"lastScreen", d->lastScreen);
331 d->lastDesktop = group.readEntry(
"lastDesktop", d->lastDesktop);
332 d->setScreen(group.readEntry(
"screen", d->screen), group.readEntry(
"desktop", d->desktop),
false);
333 QString activityId = group.readEntry(
"activityId", QString());
334 if (!activityId.isEmpty()) {
335 d->context()->setCurrentActivityId(activityId);
337 setActivity(group.readEntry(
"activity", QString()));
346 QMetaObject::invokeMethod(d->toolBox.data(),
"restore", Q_ARG(KConfigGroup, group));
353 d->containmentActionsSource = ContainmentPrivate::Local;
354 cfg = KConfigGroup(&group,
"ActionPlugins");
356 QString source = group.readEntry(
"ActionPluginsSource", QString());
357 if (source ==
"Global") {
358 cfg = KConfigGroup(
corona()->
config(),
"ActionPlugins");
359 d->containmentActionsSource = ContainmentPrivate::Global;
360 }
else if (source ==
"Activity") {
362 cfg = KConfigGroup(&cfg, activityId);
363 cfg = KConfigGroup(&cfg,
"ActionPlugins");
364 d->containmentActionsSource = ContainmentPrivate::Activity;
365 }
else if (source ==
"Local") {
367 d->containmentActionsSource = ContainmentPrivate::Local;
371 cfg = KConfigGroup(
corona()->
config(),
"ActionPlugins");
373 cfg = KConfigGroup(&group,
"ActionPlugins");
375 d->containmentActionsSource = ContainmentPrivate::Global;
376 group.writeEntry(
"ActionPluginsSource",
"Global");
381 foreach (
const QString &key, cfg.keyList()) {
388 QHash<QString,QString> defaults = conf.d->plugins;
389 for (QHash<QString,QString>::const_iterator it = defaults.constBegin(),
390 end = defaults.constEnd(); it != end; ++it) {
407 if (Applet::d->
transient) {
411 KConfigGroup group = g;
412 if (!group.isValid()) {
423 group.writeEntry(
"screen", d->screen);
424 group.writeEntry(
"lastScreen", d->lastScreen);
425 group.writeEntry(
"desktop", d->desktop);
426 group.writeEntry(
"lastDesktop", d->lastDesktop);
427 group.writeEntry(
"formfactor", (
int)d->formFactor);
428 group.writeEntry(
"location", (
int)d->location);
429 group.writeEntry(
"activity", d->context()->currentActivity());
430 group.writeEntry(
"activityId", d->context()->currentActivityId());
433 QMetaObject::invokeMethod(d->toolBox.data(),
"save", Q_ARG(KConfigGroup, group));
437 group.writeEntry(
"wallpaperplugin", d->wallpaper->pluginName());
438 group.writeEntry(
"wallpaperpluginmode", d->wallpaper->renderingMode().name());
440 if (d->wallpaper->isInitialized()) {
441 KConfigGroup wallpaperConfig(&group,
"Wallpaper");
442 wallpaperConfig = KConfigGroup(&wallpaperConfig, d->wallpaper->pluginName());
443 d->wallpaper->save(wallpaperConfig);
452 KConfigGroup
applets(&group,
"Applets");
453 foreach (
const Applet *applet, d->applets) {
454 KConfigGroup appletConfig(&applets, QString::number(applet->
id()));
455 applet->
save(appletConfig);
459 void ContainmentPrivate::initApplets()
461 foreach (
Applet *applet, applets) {
462 applet->
restore(*applet->d->mainConfigGroup());
464 kDebug() <<
"!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) <<
"Applet" << applet->
name();
467 q->flushPendingConstraintsEvents();
469 foreach (Applet *applet, applets) {
470 applet->flushPendingConstraintsEvents();
473 kDebug() <<
"!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) <<
"Containment's applets initialized" << q->name();
478 KConfigGroup
applets(&group,
"Applets");
482 QList<KConfigGroup> appletConfigs;
483 foreach (
const QString &appletGroup, applets.groupList()) {
485 KConfigGroup appletConfig(&applets, appletGroup);
486 appletConfigs.append(appletConfig);
490 QMutableListIterator<KConfigGroup> it(appletConfigs);
491 while (it.hasNext()) {
492 KConfigGroup &appletConfig = it.next();
493 int appId = appletConfig.name().toUInt();
494 QString plugin = appletConfig.readEntry(
"plugin", QString());
496 if (plugin.isEmpty()) {
500 d->addApplet(plugin, QVariantList(), appletConfig.readEntry(
"geometry", QRectF()), appId,
true);
511 if (d->type == type) {
515 delete d->toolBox.data();
517 d->checkContainmentFurniture();
520 void ContainmentPrivate::checkContainmentFurniture()
522 if (q->isContainment() &&
530 return qobject_cast<
Corona*>(scene());
536 if (d->wallpaper && d->wallpaper->isInitialized()) {
537 QGraphicsItem *item = scene()->itemAt(event->scenePos());
539 d->wallpaper->mouseMoveEvent(event);
543 if (!event->isAccepted()) {
553 d->toolBox.data()->setShowing(
false);
556 if (d->appletAt(event->scenePos())) {
560 if (d->wallpaper && d->wallpaper->isInitialized() && !
event->isAccepted()) {
561 d->wallpaper->mousePressEvent(event);
564 if (event->isAccepted()) {
565 setFocus(Qt::MouseFocusReason);
566 }
else if (event->button() == Qt::RightButton &&
event->modifiers() == Qt::NoModifier) {
568 Applet::mousePressEvent(event);
571 if (d->prepareContainmentActions(trigger, event->screenPos())) {
572 d->actionPlugins()->value(trigger)->contextEvent(event);
575 if (!event->isAccepted()) {
576 Applet::mousePressEvent(event);
585 if (d->appletAt(event->scenePos())) {
591 if (d->wallpaper && d->wallpaper->isInitialized()) {
592 d->wallpaper->mouseReleaseEvent(event);
596 if (d->prepareContainmentActions(trigger, event->screenPos())) {
597 d->actionPlugins()->value(trigger)->contextEvent(event);
601 Applet::mouseReleaseEvent(event);
614 QGraphicsSceneContextMenuEvent gvevent;
615 gvevent.setScreenPos(screenPos);
616 gvevent.setScenePos(mapToScene(containmentPos));
617 gvevent.setPos(containmentPos);
618 gvevent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
619 gvevent.setWidget(
view());
625 if (!
isContainment() || !KAuthorized::authorizeKAction(
"plasma/containment_context_menu")) {
626 Applet::contextMenuEvent(event);
631 Applet *applet = d->appletAt(event->scenePos());
635 d->addAppletActions(desktopMenu, applet, event);
637 d->addContainmentActions(desktopMenu, event);
641 QMenu *menu = &desktopMenu;
643 if (desktopMenu.actions().size() == 1 && desktopMenu.actions().first()->menu()) {
645 menu = desktopMenu.actions().first()->menu();
648 if (!menu->isEmpty()) {
649 QPoint pos =
event->screenPos();
650 if (applet && d->isPanelContainment()) {
653 if (event->reason() == QGraphicsSceneContextMenuEvent::Mouse) {
657 if (pos.y() + menu->height() <
event->screenPos().y()) {
658 pos.setY(event->screenPos().y());
661 if (pos.x() + menu->width() <
event->screenPos().x()) {
662 pos.setX(event->screenPos().x());
671 Applet::contextMenuEvent(event);
675 void ContainmentPrivate::addContainmentActions(KMenu &desktopMenu, QEvent *event)
677 if (static_cast<Corona*>(q->scene())->immutability() !=
Mutable &&
678 !KAuthorized::authorizeKAction(
"plasma/containment_actions")) {
684 prepareContainmentActions(trigger, QPoint(), &desktopMenu);
687 void ContainmentPrivate::addAppletActions(KMenu &desktopMenu, Applet *applet, QEvent *event)
689 foreach (QAction *action, applet->contextualActions()) {
691 desktopMenu.addAction(action);
695 if (!applet->d->failed) {
696 QAction *configureApplet = applet->d->actions->action(
"configure");
697 if (configureApplet && configureApplet->isEnabled()) {
698 desktopMenu.addAction(configureApplet);
701 QAction *runAssociatedApplication = applet->d->actions->action(
"run associated application");
702 if (runAssociatedApplication && runAssociatedApplication->isEnabled()) {
703 desktopMenu.addAction(runAssociatedApplication);
707 KMenu *containmentMenu =
new KMenu(i18nc(
"%1 is the name of the containment",
"%1 Options", q->name()), &desktopMenu);
708 addContainmentActions(*containmentMenu, event);
709 if (!containmentMenu->isEmpty()) {
712 QListIterator<QAction *> actionsIt(containmentMenu->actions());
713 while (enabled < 3 && actionsIt.hasNext()) {
714 QAction *action = actionsIt.next();
715 if (action->isVisible() && !action->isSeparator()) {
723 foreach (QAction *action, containmentMenu->actions()) {
724 if (action->isVisible() && !action->isSeparator()) {
725 desktopMenu.addAction(action);
729 desktopMenu.addMenu(containmentMenu);
734 if (q->immutability() ==
Mutable) {
735 QAction *closeApplet = applet->d->actions->action(
"remove");
738 if (!desktopMenu.isEmpty()) {
739 desktopMenu.addSeparator();
743 desktopMenu.addAction(closeApplet);
748 Applet* ContainmentPrivate::appletAt(
const QPointF &point)
752 QGraphicsItem *item = q->scene()->itemAt(point);
758 if (item->isWidget()) {
761 if (applet->isContainment()) {
767 AppletHandle *handle =
dynamic_cast<AppletHandle*
>(item);
770 applet = handle->applet();
773 item = item->parentItem();
780 if (d->formFactor == formFactor) {
790 d->positionPanel(
true);
793 QMetaObject::invokeMethod(d->toolBox.data(),
"reposition");
797 KConfigGroup c =
config();
798 c.writeEntry(
"formfactor", (
int)formFactor);
804 if (d->location == location) {
808 bool emitGeomChange =
false;
812 emitGeomChange =
true;
817 emitGeomChange =
true;
822 foreach (
Applet *applet, d->applets) {
826 if (emitGeomChange) {
834 KConfigGroup c =
config();
835 c.writeEntry(
"location", (
int)location);
846 foreach (
Applet *applet, d->applets) {
847 applet->d->cleanUpAndDelete();
854 const QRectF &appletGeometry)
856 return d->addApplet(name, args, appletGeometry);
866 kDebug() <<
"adding null applet!?!";
870 if (d->applets.contains(applet)) {
871 kDebug() <<
"already have this applet!";
881 if (currentContainment && currentContainment !=
this) {
883 if (currentContainment->d->focusedApplet == applet) {
884 currentContainment->d->focusedApplet = 0;
887 disconnect(applet, 0, currentContainment, 0);
888 KConfigGroup oldConfig = applet->
config();
889 currentContainment->d->applets.removeAll(applet);
890 applet->setParentItem(
this);
891 applet->setParent(
this);
895 KConfigGroup c =
config().group(
"Applets").group(QString::number(applet->
id()));
896 oldConfig.reparent(&c);
897 applet->d->resetConfigurationObject();
899 disconnect(applet, SIGNAL(
activate()), currentContainment, SIGNAL(
activate()));
901 applet->setParentItem(
this);
902 applet->setParent(
this);
905 d->applets << applet;
913 if (pos != QPointF(-1, -1)) {
917 if (!delayInit && !currentContainment) {
918 applet->
restore(*applet->d->mainConfigGroup());
922 connect(anim, SIGNAL(finished()),
this, SLOT(appletAppearAnimationComplete()));
926 anim->setDirection(QAbstractAnimation::Backward);
927 anim->start(QAbstractAnimation::DeleteWhenStopped);
929 d->appletAppeared(applet);
933 applet->setFlag(QGraphicsItem::ItemIsMovable,
true);
940 if (!currentContainment) {
948 applet->d->scheduleModificationNotification();
959 d->setScreen(newScreen, newDesktop);
962 void ContainmentPrivate::setScreen(
int newScreen,
int newDesktop,
bool preventInvalidDesktops)
974 Corona *corona = q->corona();
983 if (newScreen < -1) {
988 if (newDesktop < -1 || (preventInvalidDesktops && newDesktop > KWindowSystem::numberOfDesktops() - 1)) {
994 Containment *swapScreensWith(0);
997 if (isDesktopContainment) {
1000 if (screen < 0 && newScreen > -1) {
1001 QObject::connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), toolBox.data(), SLOT(reposition()), Qt::UniqueConnection);
1002 }
else if (newScreen < 0) {
1003 QObject::disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), toolBox.data(), SLOT(reposition()));
1007 if (newScreen > -1) {
1010 if (currently && currently != q) {
1011 kDebug() <<
"currently is on screen" << currently->
screen()
1012 <<
"desktop" << currently->desktop()
1013 <<
"and is" << currently->activity()
1015 currently->setScreen(-1, currently->desktop());
1016 swapScreensWith = currently;
1021 if (newScreen < numScreens && newScreen > -1 && isDesktopContainment) {
1025 int oldDesktop = desktop;
1026 desktop = newDesktop;
1028 int oldScreen = screen;
1033 if (oldScreen != newScreen || oldDesktop != newDesktop) {
1039 KConfigGroup c = q->
config();
1040 c.writeEntry(
"screen", screen);
1041 c.writeEntry(
"desktop", desktop);
1042 if (newScreen != -1) {
1043 lastScreen = newScreen;
1044 lastDesktop = newDesktop;
1045 c.writeEntry(
"lastScreen", lastScreen);
1046 c.writeEntry(
"lastDesktop", lastDesktop);
1048 emit q->configNeedsSaving();
1049 emit q->screenChanged(oldScreen, newScreen, q);
1052 if (swapScreensWith) {
1054 swapScreensWith->setScreen(oldScreen, oldDesktop);
1057 checkRemoveAction();
1059 if (newScreen >= 0) {
1071 return d->lastScreen;
1081 return d->lastDesktop;
1085 const QString &parentApp)
1092 const QString &category,
1093 const QString &parentApp)
1097 if (parentApp.isEmpty()) {
1098 constraint.append(
"(not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '')");
1100 constraint.append(
"[X-KDE-ParentApp] == '").append(parentApp).append(
"'");
1103 if (!type.isEmpty()) {
1104 if (!constraint.isEmpty()) {
1105 constraint.append(
" and ");
1108 constraint.append(
"'").append(type).append(
"' ~in [X-Plasma-ContainmentCategories]");
1111 if (!category.isEmpty()) {
1112 if (!constraint.isEmpty()) {
1113 constraint.append(
" and ");
1116 constraint.append(
"[X-KDE-PluginInfo-Category] == '").append(category).append(
"'");
1117 if (category ==
"Miscellaneous") {
1118 constraint.append(
" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
1122 KService::List offers = KServiceTypeTrader::self()->query(
"Plasma/Containment", constraint);
1124 return KPluginInfo::fromServices(offers);
1129 const QString constraint = QString(
"'%1' in [X-Plasma-DropMimeTypes]").arg(mimetype);
1131 const KService::List offers = KServiceTypeTrader::self()->query(
"Plasma/Containment", constraint);
1132 return KPluginInfo::fromServices(offers);
1138 QSet<QString> types;
1140 foreach (
const KPluginInfo &containmentInfo, containmentInfos) {
1141 QStringList theseTypes = containmentInfo.service()->property(
"X-Plasma-ContainmentCategories").toStringList();
1142 foreach (
const QString &
type, theseTypes) {
1147 return types.toList();
1154 (event->mimeData()->hasFormat(static_cast<Corona*>(scene())->appletMimeType()) ||
1155 KUrl::List::canDecode(event->mimeData()) ||
1156 event->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())));
1158 if (!event->isAccepted()) {
1160 QStringList formats =
event->mimeData()->formats();
1162 foreach (
const QString &format, formats) {
1164 if (!appletList.isEmpty()) {
1165 event->setAccepted(
true);
1170 if (!event->isAccepted()) {
1171 foreach (
const QString &format, formats) {
1173 if (!wallpaperList.isEmpty()) {
1174 event->setAccepted(
true);
1181 if (event->isAccepted()) {
1182 if (d->dropZoneStarted) {
1185 if (!d->showDropZoneDelayTimer) {
1186 d->showDropZoneDelayTimer =
new QTimer(
this);
1187 d->showDropZoneDelayTimer->setInterval(300);
1188 d->showDropZoneDelayTimer->setSingleShot(
true);
1189 connect(d->showDropZoneDelayTimer, SIGNAL(timeout()),
this, SLOT(showDropZoneDelayed()));
1192 d->dropPoints.insert(0, event->pos());
1193 d->showDropZoneDelayTimer->start();
1201 if (d->showDropZoneDelayTimer) {
1202 d->showDropZoneDelayTimer->stop();
1205 if (event->pos().y() < 1 ||
event->pos().y() > size().height() ||
1206 event->pos().x() < 1 ||
event->pos().x() > size().width()) {
1208 d->dropZoneStarted =
false;
1212 void ContainmentPrivate::showDropZoneDelayed()
1214 dropZoneStarted =
true;
1215 q->showDropZone(dropPoints.value(0).toPoint());
1216 dropPoints.remove(0);
1221 QGraphicsItem *item = scene()->itemAt(event->scenePos());
1222 event->setAccepted(item ==
this || item == d->toolBox.data() || !item);
1224 if (!event->isAccepted()) {
1225 if (d->showDropZoneDelayTimer) {
1226 d->showDropZoneDelayTimer->stop();
1236 d->dropData(event->scenePos(),
event->screenPos(), event);
1238 Applet::dropEvent(event);
1242 void ContainmentPrivate::dropData(QPointF scenePos, QPoint screenPos, QGraphicsSceneDragDropEvent *dropEvent)
1244 if (q->immutability() !=
Mutable) {
1248 QPointF pos = q->mapFromScene(scenePos);
1249 const QMimeData *mimeData = 0;
1252 mimeData = dropEvent->mimeData();
1254 QClipboard *clipboard = QApplication::clipboard();
1255 mimeData = clipboard->mimeData(QClipboard::Selection);
1261 kDebug() <<
"no mime data";
1267 QString appletMimetype(q->corona() ? q->corona()->appletMimeType() : QString());
1269 if (!appletMimetype.isEmpty() && mimeData->hasFormat(appletMimetype)) {
1270 QString data = mimeData->data(appletMimetype);
1271 const QStringList appletNames = data.split(
'\n', QString::SkipEmptyParts);
1272 foreach (
const QString &appletName, appletNames) {
1274 QRectF geom(pos, QSize(0, 0));
1275 q->addApplet(appletName, QVariantList(), geom);
1278 dropEvent->acceptProposedAction();
1280 }
else if (mimeData->hasFormat(ExtenderItemMimeData::mimeType())) {
1281 kDebug() <<
"mimetype plasma/extenderitem is dropped, creating internal:extender";
1283 const ExtenderItemMimeData *extenderData = qobject_cast<
const ExtenderItemMimeData*>(mimeData);
1285 ExtenderItem *item = extenderData->extenderItem();
1286 QRectF geometry(pos - extenderData->pointerOffset(), item->size());
1287 kDebug() <<
"desired geometry: " << geometry;
1288 Applet *applet = qobject_cast<ExtenderApplet *>(item->extender() ? item->extender()->applet() : 0);
1290 qreal left, top, right, bottom;
1291 applet->getContentsMargins(&left, &top, &right, &bottom);
1292 applet->setPos(geometry.topLeft() - QPointF(
int(left),
int(top)));
1295 applet = addApplet(
"internal:extender", QVariantList(), geometry, 0,
true);
1298 appletAppeared(applet);
1299 applet->flushPendingConstraintsEvents();
1300 applet->d->scheduleModificationNotification();
1301 applet->adjustSize();
1304 item->setExtender(applet->extender());
1306 }
else if (KUrl::List::canDecode(mimeData)) {
1309 const KUrl::List urls = KUrl::List::fromMimeData(mimeData);
1310 foreach (
const KUrl &url, urls) {
1314 dropPoints[job] = dropEvent->pos();
1316 dropPoints[job] = scenePos;
1321 #ifndef PLASMA_NO_KIO
1323 KMimeType::Ptr mime = KMimeType::findByUrl(url);
1324 QString mimeName = mime->name();
1325 QRectF geom(pos, QSize());
1328 kDebug() <<
"can decode" << mimeName << args;
1331 KIO::JobFlags flags = KIO::HideProgressInfo;
1332 KIO::MimetypeJob *job = KIO::mimetype(url, flags);
1334 dropPoints[job] = dropEvent->pos();
1336 dropPoints[job] = scenePos;
1339 QObject::connect(job, SIGNAL(result(
KJob*)), q, SLOT(dropJobResult(
KJob*)));
1340 QObject::connect(job, SIGNAL(mimetype(KIO::Job*,QString)),
1341 q, SLOT(mimeTypeRetrieved(KIO::Job*,QString)));
1343 KMenu *choices =
new KMenu(
"Content dropped");
1344 choices->addAction(KIcon(
"process-working"), i18n(
"Fetching file type..."));
1346 choices->popup(dropEvent->screenPos());
1348 choices->popup(screenPos);
1351 dropMenus[job] = choices;
1357 dropEvent->acceptProposedAction();
1360 QStringList formats = mimeData->formats();
1361 QHash<QString, KPluginInfo> seenPlugins;
1362 QHash<QString, QString> pluginFormats;
1364 foreach (
const QString &format, formats) {
1367 foreach (
const KPluginInfo &plugin, plugins) {
1368 if (seenPlugins.contains(plugin.pluginName())) {
1372 seenPlugins.insert(plugin.pluginName(), plugin);
1373 pluginFormats.insert(plugin.pluginName(), format);
1378 QString selectedPlugin;
1380 if (seenPlugins.isEmpty()) {
1382 }
else if (seenPlugins.count() == 1) {
1383 selectedPlugin = seenPlugins.constBegin().key();
1386 QHash<QAction *, QString> actionsToPlugins;
1387 foreach (
const KPluginInfo &info, seenPlugins) {
1389 if (!info.icon().isEmpty()) {
1390 action = choices.addAction(KIcon(info.icon()), info.name());
1392 action = choices.addAction(info.name());
1395 actionsToPlugins.insert(action, info.pluginName());
1398 QAction *choice = choices.exec(screenPos);
1400 selectedPlugin = actionsToPlugins[choice];
1404 if (!selectedPlugin.isEmpty()) {
1410 QClipboard *clipboard = QApplication::clipboard();
1411 mimeData = clipboard->mimeData(QClipboard::Selection);
1414 KTemporaryFile tempFile;
1415 if (mimeData && tempFile.open()) {
1417 tempFile.setAutoRemove(
false);
1420 QDataStream stream(&tempFile);
1421 QByteArray data = mimeData->data(pluginFormats[selectedPlugin]);
1422 stream.writeRawData(data, data.size());
1425 QRectF geom(pos, QSize());
1427 args << tempFile.fileName();
1431 q->addApplet(selectedPlugin, args, geom);
1437 void ContainmentPrivate::clearDataForMimeJob(KIO::Job *job)
1439 #ifndef PLASMA_NO_KIO
1440 QObject::disconnect(job, 0, q, 0);
1441 dropPoints.remove(job);
1442 KMenu *choices = dropMenus.take(job);
1445 #endif // PLASMA_NO_KIO
1450 QPointF pos = dropPoints.take(job);
1453 kDebug() <<
"remote applet access failed: " << job->errorText();
1458 kDebug() <<
"how did we end up here? if applet is null, the job->error should be nonzero";
1462 q->addApplet(job->
applet(), pos);
1465 void ContainmentPrivate::dropJobResult(
KJob *job)
1467 #ifndef PLASMA_NO_KIO
1468 KIO::TransferJob* tjob =
dynamic_cast<KIO::TransferJob*
>(job);
1470 kDebug() <<
"job is not a KIO::TransferJob, won't handle the drop...";
1471 clearDataForMimeJob(tjob);
1475 kDebug() <<
"ERROR" << tjob->error() <<
' ' << tjob->errorString();
1479 mimeTypeRetrieved(qobject_cast<KIO::Job *>(job), QString());
1480 #endif // PLASMA_NO_KIO
1483 void ContainmentPrivate::mimeTypeRetrieved(KIO::Job *job,
const QString &mimetype)
1485 #ifndef PLASMA_NO_KIO
1486 kDebug() <<
"Mimetype Job returns." << mimetype;
1487 KIO::TransferJob* tjob =
dynamic_cast<KIO::TransferJob*
>(job);
1489 kDebug() <<
"job should be a TransferJob, but isn't";
1490 clearDataForMimeJob(job);
1494 if (mimetype.isEmpty() && !appletList.count()) {
1495 clearDataForMimeJob(job);
1496 kDebug() <<
"No applets found matching the url (" << tjob->url() <<
") or the mimetype (" << mimetype <<
")";
1501 if (dropPoints.keys().contains(tjob)) {
1502 posi = dropPoints[tjob];
1503 kDebug() <<
"Received a suitable dropEvent at" << posi;
1505 kDebug() <<
"Bailing out. Cannot find associated dropEvent related to the TransferJob";
1506 clearDataForMimeJob(job);
1510 KMenu *choices = dropMenus.value(tjob);
1512 kDebug() <<
"Bailing out. No QMenu found for this job.";
1513 clearDataForMimeJob(job);
1518 args << tjob->url().url() << mimetype;
1520 kDebug() <<
"Creating menu for:" << mimetype << posi << args;
1523 KPluginInfo::List wallpaperList;
1524 if (drawWallpaper) {
1525 if (wallpaper && wallpaper->supportsMimetype(mimetype)) {
1526 wallpaperList << wallpaper->d->wallpaperDescription;
1532 if (!appletList.isEmpty() || !wallpaperList.isEmpty()) {
1534 QHash<QAction *, QString> actionsToApplets;
1535 choices->addTitle(i18n(
"Widgets"));
1536 foreach (
const KPluginInfo &info, appletList) {
1537 kDebug() << info.name();
1539 if (!info.icon().isEmpty()) {
1540 action = choices->addAction(KIcon(info.icon()), info.name());
1542 action = choices->addAction(info.name());
1545 actionsToApplets.insert(action, info.pluginName());
1546 kDebug() << info.pluginName();
1548 actionsToApplets.insert(choices->addAction(i18n(
"Icon")),
"icon");
1550 QHash<QAction *, QString> actionsToWallpapers;
1551 if (!wallpaperList.isEmpty()) {
1552 choices->addTitle(i18n(
"Wallpaper"));
1554 QMap<QString, KPluginInfo> sorted;
1555 foreach (
const KPluginInfo &info, appletList) {
1556 sorted.insert(info.name(), info);
1559 foreach (
const KPluginInfo &info, wallpaperList) {
1561 if (!info.icon().isEmpty()) {
1562 action = choices->addAction(KIcon(info.icon()), info.name());
1564 action = choices->addAction(info.name());
1567 actionsToWallpapers.insert(action, info.pluginName());
1571 QAction *choice = choices->exec();
1576 if (!mimetype.isEmpty() && !tjob->error()) {
1578 KIO::Scheduler::publishSlaveOnHold();
1580 QString plugin = actionsToApplets.value(choice);
1581 if (plugin.isEmpty()) {
1583 plugin = actionsToWallpapers.value(choice);
1584 if (!wallpaper || plugin != wallpaper->pluginName()) {
1585 kDebug() <<
"Wallpaper dropped:" << tjob->url();
1586 q->setWallpaper(plugin);
1590 kDebug() <<
"Wallpaper dropped:" << tjob->url();
1591 wallpaper->setUrls(KUrl::List() << tjob->url());
1594 addApplet(actionsToApplets[choice], args, QRectF(posi, QSize()));
1597 clearDataForMimeJob(job);
1602 addApplet(
"icon", args, QRectF(posi, QSize()));
1606 clearDataForMimeJob(job);
1607 #endif // PLASMA_NO_KIO
1610 #ifndef KDE_NO_DEPRECATED
1613 return d->toolBox.data();
1619 if (d->toolBox.data()) {
1620 d->toolBox.data()->deleteLater();
1627 return d->toolBox.data();
1635 if (d->isPanelContainment()) {
1638 QMetaObject::invokeMethod(
corona(),
"layoutContainments");
1642 d->wallpaper->setBoundingRect(QRectF(QPointF(0, 0), size()));
1651 if (event->key() == Qt::Key_Tab) {
1652 if (!d->applets.isEmpty()) {
1653 kDebug() <<
"let's give focus to...." << (
QObject*)d->applets.first();
1654 d->applets.first()->setFocus(Qt::TabFocusReason);
1662 if (d->appletAt(event->scenePos())) {
1666 if (d->wallpaper && d->wallpaper->isInitialized()) {
1667 QGraphicsItem *item = scene()->itemAt(event->scenePos());
1670 d->wallpaper->wheelEvent(event);
1672 if (event->isAccepted()) {
1680 if (d->prepareContainmentActions(trigger, event->screenPos())) {
1681 d->actionPlugins()->value(trigger)->contextEvent(event);
1685 Applet::wheelEvent(event);
1699 (change == QGraphicsItem::ItemSceneHasChanged ||
1700 change == QGraphicsItem::ItemPositionHasChanged)) {
1708 QMetaObject::invokeMethod(
corona(),
"layoutContainments");
1719 QAction *action = this->
action(name);
1721 action->setEnabled(enable);
1722 action->setVisible(enable);
1730 d->toolBox.data()->addTool(action);
1737 d->toolBox.data()->removeTool(action);
1752 return (d->toolBox && d->toolBox.data()->isShowing());
1757 if (d->toolBox && !d->toolBox.data()->isShowing()) {
1758 d->toolBox.data()->setShowing(
true);
1765 if (d->toolBox && d->toolBox.data()->isShowing()) {
1766 d->toolBox.data()->setShowing(
false);
1774 if (d->focusedApplet) {
1775 d->focusedApplet->addAssociatedWidget(widget);
1778 foreach (
const Applet *applet, d->applets) {
1779 if (applet->d->activationAction) {
1780 widget->addAction(applet->d->activationAction);
1788 if (d->focusedApplet) {
1789 d->focusedApplet->removeAssociatedWidget(widget);
1792 foreach (
const Applet *applet, d->applets) {
1793 if (applet->d->activationAction) {
1794 widget->removeAction(applet->d->activationAction);
1802 if (drawWallpaper) {
1803 KConfigGroup cfg =
config();
1808 delete d->wallpaper;
1815 return d->drawWallpaper;
1820 KConfigGroup cfg =
config();
1821 bool newPlugin =
true;
1822 bool newMode =
true;
1824 if (d->drawWallpaper) {
1827 if (d->wallpaper->pluginName() !=
pluginName) {
1828 delete d->wallpaper;
1833 newMode = d->wallpaper->renderingMode().name() != mode;
1838 if (!pluginName.isEmpty() && !d->wallpaper) {
1843 d->wallpaper->setParent(
this);
1844 d->wallpaper->setBoundingRect(QRectF(QPointF(0, 0), size()));
1845 d->wallpaper->setRenderingMode(mode);
1848 cfg.writeEntry(
"wallpaperplugin", pluginName);
1851 if (d->wallpaper->isInitialized()) {
1852 KConfigGroup wallpaperConfig = KConfigGroup(&cfg,
"Wallpaper");
1853 wallpaperConfig = KConfigGroup(&wallpaperConfig, pluginName);
1854 d->wallpaper->restore(wallpaperConfig);
1858 cfg.writeEntry(
"wallpaperpluginmode", mode);
1865 if (!d->wallpaper) {
1866 cfg.deleteEntry(
"wallpaperplugin");
1867 cfg.deleteEntry(
"wallpaperpluginmode");
1870 if (newPlugin || newMode) {
1871 if (newPlugin && d->wallpaper) {
1872 connect(d->wallpaper, SIGNAL(
configureRequested()),
this, SLOT(requestConfiguration()));
1882 return d->wallpaper;
1890 if (d->actionPlugins()->contains(trigger)) {
1891 plugin = d->actionPlugins()->value(trigger);
1893 d->actionPlugins()->remove(trigger);
1898 if (pluginName.isEmpty()) {
1899 cfg.deleteEntry(trigger);
1900 }
else if (plugin) {
1905 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
1906 plugin->
restore(pluginConfig);
1909 switch (d->containmentActionsSource) {
1910 case ContainmentPrivate::Activity:
1912 case ContainmentPrivate::Local:
1919 cfg.writeEntry(trigger, pluginName);
1920 d->actionPlugins()->insert(trigger, plugin);
1923 cfg.deleteEntry(trigger);
1932 return d->actionPlugins()->keys();
1951 foreach (
Applet *a, applets) {
1955 KConfigGroup c = q->config();
1961 if (!act.isEmpty()) {
1962 c.writeEntry(
"activityId", act);
1965 if (!act.isEmpty()) {
1966 c.writeEntry(
"activity", act);
1970 toolBox.data()->update();
1972 emit q->configNeedsSaving();
1973 emit q->contextChanged(con);
1978 return d->context()->currentActivity();
1983 return d->context();
1986 Context *ContainmentPrivate::context()
1997 KActionCollection* ContainmentPrivate::actions()
1999 return static_cast<Applet*
>(q)->d->actions;
2004 if (focusedApplet == applet) {
2008 QList<QWidget *> widgets = actions()->associatedWidgets();
2009 if (focusedApplet) {
2010 foreach (
QWidget *w, widgets) {
2011 focusedApplet->removeAssociatedWidget(w);
2015 if (applet && applets.contains(applet)) {
2017 focusedApplet = applet;
2018 foreach (
QWidget *w, widgets) {
2022 if (!focusedApplet->hasFocus()) {
2023 focusedApplet->setFocus(Qt::ShortcutFocusReason);
2032 if (d->applets.isEmpty()) {
2035 int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) + 1 : 0;
2036 if (index >= d->applets.size()) {
2039 kDebug() <<
"index" << index;
2040 d->focusApplet(d->applets.at(index));
2045 if (d->applets.isEmpty()) {
2048 int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) - 1 : -1;
2050 index = d->applets.size() - 1;
2052 kDebug() <<
"index" << index;
2053 d->focusApplet(d->applets.at(index));
2071 void ContainmentPrivate::configChanged()
2073 if (drawWallpaper) {
2074 KConfigGroup group = q->config();
2080 void ContainmentPrivate::requestConfiguration()
2082 emit q->configureRequested(q);
2088 if (appletStatus == q->status()) {
2089 emit q->newStatus(appletStatus);
2093 if (appletStatus < q->status()) {
2096 foreach (Applet *applet, applets) {
2097 if (applet->status() > appletStatus) {
2098 appletStatus = applet->status();
2103 q->setStatus(appletStatus);
2114 const QString title = i18nc(
"@title:window %1 is the name of the containment",
"Remove %1",
name());
2115 KGuiItem
remove = KStandardGuiItem::remove();
2116 remove.setText(title);
2117 if (KMessageBox::warningContinueCancel(
view(),
2118 i18nc(
"%1 is the name of the containment",
"Do you really want to remove this %1?",
name()),
2119 title,
remove) != KMessageBox::Continue) {
2127 void ContainmentPrivate::createToolBox()
2129 if (!toolBox && KAuthorized::authorizeKAction(
"plasma/containment_context_menu")) {
2133 QObject::connect(toolBox.data(), SIGNAL(toggled()), q, SIGNAL(toolBoxToggled()));
2134 QObject::connect(toolBox.data(), SIGNAL(toggled()), q, SLOT(updateToolBoxVisibility()));
2141 void ContainmentPrivate::positionToolBox()
2143 QMetaObject::invokeMethod(toolBox.data(),
"reposition");
2146 void ContainmentPrivate::updateToolBoxVisibility()
2148 emit q->toolBoxVisibilityChanged(toolBox.data()->isShowing());
2151 void ContainmentPrivate::triggerShowAddWidgets()
2153 emit q->showAddWidgetsInterface(QPointF());
2156 void ContainmentPrivate::containmentConstraintsEvent(Plasma::Constraints constraints)
2158 if (!q->isContainment()) {
2165 checkRemoveAction();
2166 const bool unlocked = q->immutability() ==
Mutable;
2167 q->setAcceptDrops(unlocked);
2168 q->enableAction(
"add widgets", unlocked);
2171 foreach (Applet *a, applets) {
2172 a->setImmutability(q->immutability());
2188 foreach (Applet *applet, applets) {
2189 applet->updateConstraints(appletConstraints);
2202 q->addToolBoxAction(q->action(
"remove"));
2203 checkRemoveAction();
2207 Applet *ContainmentPrivate::addApplet(
const QString &name,
const QVariantList &args,
2208 const QRectF &appletGeometry, uint
id,
bool delayInit)
2210 if (!q->isContainment()) {
2214 if (!delayInit && q->immutability() !=
Mutable) {
2215 kDebug() <<
"addApplet for" << name <<
"requested, but we're currently immutable!";
2221 v->setCursor(Qt::BusyCursor);
2230 kDebug() <<
"Applet" << name <<
"could not be loaded.";
2231 applet =
new Applet(0, QString(),
id);
2232 applet->setFailedToLaunch(
true, i18n(
"Could not find requested component: %1", name));
2237 q->addApplet(applet, appletGeometry.topLeft(), delayInit);
2241 bool ContainmentPrivate::regionIsEmpty(
const QRectF ®ion, Applet *ignoredApplet)
const
2243 foreach (Applet *applet, applets) {
2244 if (applet != ignoredApplet && applet->geometry().intersects(region)) {
2253 applets.removeAll(applet);
2254 if (focusedApplet == applet) {
2258 emit q->appletRemoved(applet);
2259 emit q->configNeedsSaving();
2262 void ContainmentPrivate::appletAppearAnimationComplete()
2264 Animation *anim = qobject_cast<Animation *>(q->sender());
2266 Applet *applet = qobject_cast<Applet*>(anim->targetWidget());
2268 appletAppeared(applet);
2273 void ContainmentPrivate::appletAppeared(Applet *applet)
2276 KConfigGroup *cg = applet->d->mainConfigGroup();
2278 emit q->configNeedsSaving();
2281 void ContainmentPrivate::positionPanel(
bool force)
2284 kDebug() <<
"no scene yet";
2289 if (ContainmentPrivate::s_positioningPanels) {
2297 const QPointF p = q->pos();
2300 p.y() + q->size().height() < -INTER_CONTAINMENT_MARGIN &&
2301 q->scene()->collidingItems(q).isEmpty()) {
2307 QPointF newPos = preferredPanelPos(q->corona());
2309 ContainmentPrivate::s_positioningPanels =
true;
2311 ContainmentPrivate::s_positioningPanels =
false;
2315 bool ContainmentPrivate::isPanelContainment()
const
2320 QPointF ContainmentPrivate::preferredPos(Corona *corona)
const
2324 if (isPanelContainment()) {
2326 return preferredPanelPos(corona);
2331 while (QGraphicsItem *i = corona->itemAt(pos, t)) {
2332 pos.setX(i->scenePos().x() + i->boundingRect().width() + 10);
2339 QPointF ContainmentPrivate::preferredPanelPos(Corona *corona)
const
2345 qreal bottom = horiz ? 0 : VERTICAL_STACKING_OFFSET;
2346 qreal lastHeight = 0;
2351 foreach (
const Containment *other, corona->containments()) {
2353 !other->d->isPanelContainment() ||
2360 qreal y = other->pos().y();
2362 lastHeight = other->size().height();
2366 qreal width = other->size().width();
2367 qreal x = other->pos().x() + width;
2370 bottom = x + lastHeight;
2379 bottom -= lastHeight + INTER_CONTAINMENT_MARGIN;
2381 kDebug() <<
"moved to" << QPointF(0, bottom - q->size().height());
2382 newPos = QPointF(0, bottom - q->size().height());
2384 bottom += lastHeight + INTER_CONTAINMENT_MARGIN;
2386 kDebug() <<
"moved to" << QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
2387 newPos = QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
2394 bool ContainmentPrivate::prepareContainmentActions(
const QString &trigger,
const QPoint &screenPos, KMenu *menu)
2396 ContainmentActions *plugin = actionPlugins()->value(trigger);
2400 plugin->setContainment(q);
2402 if (!plugin->isInitialized()) {
2403 KConfigGroup cfg = q->containmentActionsConfig();
2404 KConfigGroup pluginConfig = KConfigGroup(&cfg, trigger);
2405 plugin->restore(pluginConfig);
2408 if (plugin->configurationRequired()) {
2409 KMenu *localMenu = menu ? menu :
new KMenu();
2411 localMenu->addTitle(i18n(
"This plugin needs to be configured"));
2412 localMenu->addAction(q->action(
"configure"));
2415 localMenu->exec(screenPos);
2421 QList<QAction*> actions = plugin->contextualActions();
2422 if (actions.isEmpty()) {
2425 if (!isPanelContainment() && q->action(
"configure")) {
2426 menu->addAction(q->action(
"configure"));
2429 menu->addActions(actions);
2439 switch (d->containmentActionsSource) {
2440 case ContainmentPrivate::Local:
2442 cfg = KConfigGroup(&cfg,
"ActionPlugins");
2444 case ContainmentPrivate::Activity:
2446 cfg = KConfigGroup(&cfg, d->context()->currentActivityId());
2447 cfg = KConfigGroup(&cfg,
"ActionPlugins");
2450 cfg = KConfigGroup(
corona()->
config(),
"ActionPlugins");
2455 QHash<QString, ContainmentActions*> * ContainmentPrivate::actionPlugins()
2457 switch (containmentActionsSource) {
2461 return &localActionPlugins;
2463 return &globalActionPlugins;
2469 #include "containment.moc"