00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "containment.h"
00022 #include "containment_p.h"
00023
00024 #include <QAction>
00025 #include <QDesktopWidget>
00026 #include <QFile>
00027 #include <QGraphicsSceneContextMenuEvent>
00028 #include <QGraphicsView>
00029 #include <QMimeData>
00030 #include <QPainter>
00031 #include <QStyleOptionGraphicsItem>
00032 #include <QGraphicsLayout>
00033 #include <QGraphicsLinearLayout>
00034
00035 #include <KAction>
00036 #include <KApplication>
00037 #include <KAuthorized>
00038 #include <KIcon>
00039 #include <KMenu>
00040 #include <KMessageBox>
00041 #include <KMimeType>
00042 #include <KRun>
00043 #include <KServiceTypeTrader>
00044 #include <KStandardDirs>
00045 #include <KWindowSystem>
00046
00047 #include "applet_p.h"
00048 #include "applethandle_p.h"
00049 #include "corona.h"
00050 #include "animator.h"
00051 #include "desktoptoolbox_p.h"
00052 #include "paneltoolbox_p.h"
00053 #include "svg.h"
00054
00055 namespace Plasma
00056 {
00057
00058 Containment::StyleOption::StyleOption()
00059 : QStyleOptionGraphicsItem(),
00060 view(0)
00061 {
00062 version = Version;
00063 type = Type;
00064 }
00065
00066 Containment::StyleOption::StyleOption(const Containment::StyleOption & other)
00067 : QStyleOptionGraphicsItem(other),
00068 view(other.view)
00069 {
00070 version = Version;
00071 type = Type;
00072 }
00073
00074 Containment::StyleOption::StyleOption(const QStyleOptionGraphicsItem &other)
00075 : QStyleOptionGraphicsItem(other),
00076 view(0)
00077 {
00078 version = Version;
00079 type = Type;
00080 }
00081
00082 Containment::Containment(QGraphicsItem* parent,
00083 const QString& serviceId,
00084 uint containmentId)
00085 : Applet(parent, serviceId, containmentId),
00086 d(new ContainmentPrivate(this))
00087 {
00088
00089
00090 setPos(0, 0);
00091 setBackgroundHints(NoBackground);
00092 setContainmentType(CustomContainment);
00093 }
00094
00095 Containment::Containment(QObject* parent, const QVariantList& args)
00096 : Applet(parent, args),
00097 d(new ContainmentPrivate(this))
00098 {
00099
00100
00101 setPos(0, 0);
00102 setBackgroundHints(NoBackground);
00103 }
00104
00105 Containment::~Containment()
00106 {
00107 delete d;
00108 }
00109
00110 void Containment::init()
00111 {
00112 if (isContainment()) {
00113 setCacheMode(NoCache);
00114 setFlag(QGraphicsItem::ItemIsMovable, false);
00115 }
00116 setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
00117 setAcceptDrops(true);
00118 setAcceptsHoverEvents(true);
00119
00120
00121 connect(Animator::self(), SIGNAL(animationFinished(QGraphicsItem*,Plasma::Animator::Animation)),
00122 this, SLOT(containmentAppletAnimationComplete(QGraphicsItem*,Plasma::Animator::Animation)));
00123
00124 if (d->type == NoContainmentType) {
00125 setContainmentType(DesktopContainment);
00126 }
00127
00128
00129 bool unlocked = immutability() == Mutable;
00130
00131 QAction *appletBrowserAction = new QAction(i18n("Add Widgets..."), this);
00132 appletBrowserAction->setIcon(KIcon("list-add"));
00133 appletBrowserAction->setVisible(unlocked);
00134 appletBrowserAction->setEnabled(unlocked);
00135 connect(appletBrowserAction, SIGNAL(triggered()), this, SLOT(triggerShowAddWidgets()));
00136 appletBrowserAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00137 appletBrowserAction->setShortcut(QKeySequence("ctrl+a"));
00138 d->actions().addAction("add widgets", appletBrowserAction);
00139
00140 QAction *action = new QAction(i18n("Next Applet"), this);
00141
00142 connect(action, SIGNAL(triggered()), this, SLOT(focusNextApplet()));
00143 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00144 action->setShortcut(QKeySequence("ctrl+n"));
00145 d->actions().addAction("next applet", action);
00146
00147 action = new QAction(i18n("Previous Applet"), this);
00148
00149 connect(action, SIGNAL(triggered()), this, SLOT(focusPreviousApplet()));
00150 action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00151 action->setShortcut(QKeySequence("ctrl+p"));
00152 d->actions().addAction("previous applet", action);
00153
00154 if (immutability() != SystemImmutable) {
00155
00156
00157 QAction *lockDesktopAction = new QAction(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets"), this);
00158 lockDesktopAction->setIcon(KIcon(unlocked ? "object-locked" : "object-unlocked"));
00159 connect(lockDesktopAction, SIGNAL(triggered(bool)), this, SLOT(toggleDesktopImmutability()));
00160 lockDesktopAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00161 lockDesktopAction->setShortcut(QKeySequence("ctrl+l"));
00162 d->actions().addAction("lock widgets", lockDesktopAction);
00163 }
00164
00165 if (d->type != PanelContainment &&
00166 d->type != CustomPanelContainment) {
00167 QAction *zoomAction = new QAction(i18n("Zoom In"), this);
00168 zoomAction->setIcon(KIcon("zoom-in"));
00169 connect(zoomAction, SIGNAL(triggered(bool)), this, SLOT(zoomIn()));
00170 zoomAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00171
00172 QList<QKeySequence> keys;
00173 keys << QKeySequence(QKeySequence::ZoomIn);
00174 keys << QKeySequence("ctrl+=");
00175 zoomAction->setShortcuts(keys);
00176 d->actions().addAction("zoom in", zoomAction);
00177
00178 zoomAction = new QAction(i18n("Zoom Out"), this);
00179 zoomAction->setIcon(KIcon("zoom-out"));
00180 connect(zoomAction, SIGNAL(triggered(bool)), this, SLOT(zoomOut()));
00181 zoomAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00182 zoomAction->setShortcut(QKeySequence(QKeySequence::ZoomOut));
00183 d->actions().addAction("zoom out", zoomAction);
00184
00185 QAction *activityAction = new QAction(i18n("Add Activity"), this);
00186 activityAction->setIcon(KIcon("list-add"));
00187 activityAction->setVisible(unlocked);
00188 activityAction->setEnabled(unlocked);
00189 connect(activityAction, SIGNAL(triggered(bool)), this, SLOT(addSiblingContainment()));
00190 activityAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
00191 activityAction->setShortcut(QKeySequence("ctrl+shift+a"));
00192 d->actions().addAction("add sibling containment", activityAction);
00193
00194 if (d->type == DesktopContainment && d->toolBox) {
00195 d->toolBox->addTool(this->action("add widgets"));
00196 d->toolBox->addTool(this->action("zoom in"));
00197 d->toolBox->addTool(this->action("zoom out"));
00198 if (immutability() != SystemImmutable) {
00199 d->toolBox->addTool(this->action("lock widgets"));
00200 }
00201 d->toolBox->addTool(this->action("add sibling containment"));
00202 }
00203 }
00204
00205 Applet::init();
00206 }
00207
00208
00209 bool appletConfigLessThan(const KConfigGroup &c1, const KConfigGroup &c2)
00210 {
00211 QPointF p1 = c1.readEntry("geometry", QRectF()).topLeft();
00212 QPointF p2 = c2.readEntry("geometry", QRectF()).topLeft();
00213 if (p1.x() != p2.x()) {
00214 return p1.x() < p2.x();
00215 }
00216 return p1.y() < p2.y();
00217 }
00218
00219 void Containment::restore(KConfigGroup &group)
00220 {
00221
00222
00223
00224
00225
00226 if (!isContainment()) {
00227 Applet::restore(group);
00228 return;
00229 }
00230
00231 QRectF geo = group.readEntry("geometry", geometry());
00232
00233
00234
00235 if (geo.size() != geo.size().boundedTo(maximumSize())) {
00236 setMaximumSize(maximumSize().expandedTo(geo.size()));
00237 }
00238 if (geo.size() != geo.size().expandedTo(minimumSize())) {
00239 setMinimumSize(minimumSize().boundedTo(geo.size()));
00240 }
00241 setGeometry(geo);
00242
00243 setLocation((Plasma::Location)group.readEntry("location", (int)d->location));
00244 setFormFactor((Plasma::FormFactor)group.readEntry("formfactor", (int)d->formFactor));
00245 setScreen(group.readEntry("screen", d->screen));
00246
00247 flushPendingConstraintsEvents();
00248
00249 restoreContents(group);
00250 setImmutability((ImmutabilityType)group.readEntry("immutability", (int)Mutable));
00251 }
00252
00253 void Containment::save(KConfigGroup &g) const
00254 {
00255 KConfigGroup group = g;
00256 if (!group.isValid()) {
00257 group = config();
00258 }
00259
00260
00261 Applet::save(group);
00262 group.writeEntry("screen", d->screen);
00263 group.writeEntry("formfactor", (int)d->formFactor);
00264 group.writeEntry("location", (int)d->location);
00265 saveContents(group);
00266 }
00267
00268 void Containment::saveContents(KConfigGroup &group) const
00269 {
00270 KConfigGroup applets(&group, "Applets");
00271 foreach (const Applet* applet, d->applets) {
00272 KConfigGroup appletConfig(&applets, QString::number(applet->id()));
00273 applet->save(appletConfig);
00274 }
00275 }
00276
00277 void Containment::restoreContents(KConfigGroup &group)
00278 {
00279 KConfigGroup applets(&group, "Applets");
00280
00281
00282
00283 QList<KConfigGroup> appletConfigs;
00284 foreach (const QString &appletGroup, applets.groupList()) {
00285
00286 KConfigGroup appletConfig(&applets, appletGroup);
00287 appletConfigs.append(appletConfig);
00288 }
00289 qSort(appletConfigs.begin(), appletConfigs.end(), appletConfigLessThan);
00290
00291 foreach (KConfigGroup appletConfig, appletConfigs) {
00292 int appId = appletConfig.name().toUInt();
00293
00294 QString plugin = appletConfig.readEntry("plugin", QString());
00295
00296 if (plugin.isEmpty()) {
00297 continue;
00298 }
00299
00300 Applet *applet = d->addApplet(plugin, QVariantList(), appletConfig.readEntry("geometry", QRectF()), appId, true);
00301 applet->restore(appletConfig);
00302 }
00303 }
00304
00305 Containment::Type Containment::containmentType() const
00306 {
00307 return d->type;
00308 }
00309
00310 void Containment::setContainmentType(Containment::Type type)
00311 {
00312 if (d->type == type) {
00313 return;
00314 }
00315
00316 delete d->toolBox;
00317 d->toolBox = 0;
00318 d->type = type;
00319
00320 if (!isContainment()) {
00321 return;
00322 }
00323
00324 if ((type == DesktopContainment || type == PanelContainment)) {
00325 d->createToolBox();
00326 }
00327 }
00328
00329 Corona* Containment::corona() const
00330 {
00331 return dynamic_cast<Corona*>(scene());
00332 }
00333
00334 void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
00335 {
00336
00337 if (!isContainment() || !scene() || !KAuthorized::authorizeKAction("desktop_contextmenu")) {
00338 Applet::contextMenuEvent(event);
00339 return;
00340 }
00341
00342 QPointF point = event->scenePos();
00343 QGraphicsItem* item = scene()->itemAt(point);
00344 if (item == this) {
00345 item = 0;
00346 }
00347
00348 Applet* applet = 0;
00349
00350 while (item) {
00351 applet = qgraphicsitem_cast<Applet*>(item);
00352 if (applet && !applet->isContainment()) {
00353 break;
00354 }
00355
00356
00357 applet = 0;
00358 item = item->parentItem();
00359 }
00360
00361 KMenu desktopMenu;
00362
00363 if (applet) {
00364 bool hasEntries = false;
00365
00366 QList<QAction*> actions = applet->contextualActions();
00367 if (!actions.isEmpty()) {
00368 foreach(QAction* action, actions) {
00369 if (action) {
00370 desktopMenu.addAction(action);
00371 }
00372 }
00373 hasEntries = true;
00374 }
00375
00376 if (applet->hasConfigurationInterface()) {
00377 QAction* configureApplet = applet->d->actions.action("configure");
00378 if (configureApplet) {
00379 desktopMenu.addAction(configureApplet);
00380 hasEntries = true;
00381 }
00382 }
00383
00384 QList<QAction*> containmentActions = contextualActions();
00385 if (!containmentActions.isEmpty()) {
00386 if (hasEntries) {
00387 desktopMenu.addSeparator();
00388 }
00389
00390 hasEntries = true;
00391 QMenu *containmentActionMenu = &desktopMenu;
00392
00393 if (!actions.isEmpty() && containmentActions.count() > 2) {
00394 containmentActionMenu = new KMenu(i18n("%1 Options", name()), &desktopMenu);
00395 desktopMenu.addMenu(containmentActionMenu);
00396 }
00397
00398 foreach (QAction* action, containmentActions) {
00399 if (action) {
00400 containmentActionMenu->addAction(action);
00401 }
00402 }
00403 }
00404
00405 if (scene() && static_cast<Corona*>(scene())->immutability() == Mutable) {
00406 if (hasEntries) {
00407 desktopMenu.addSeparator();
00408 }
00409
00410 QAction* closeApplet = applet->d->actions.action("remove");
00411 if (!closeApplet) {
00412 kDebug() << "no remove action!!!!!!!!";
00413 closeApplet = new QAction(i18n("Remove this %1", applet->name()), &desktopMenu);
00414 closeApplet->setIcon(KIcon("edit-delete"));
00415 connect(closeApplet, SIGNAL(triggered(bool)), applet, SLOT(destroy()));
00416 }
00417 desktopMenu.addAction(closeApplet);
00418 hasEntries = true;
00419 }
00420
00421 if (!hasEntries) {
00422 Applet::contextMenuEvent(event);
00423 kDebug() << "no entries";
00424 return;
00425 }
00426 } else {
00427 if (!scene() || (static_cast<Corona*>(scene())->immutability() != Mutable && !KAuthorized::authorizeKAction("unlock_desktop"))) {
00428
00429 Applet::contextMenuEvent(event);
00430 return;
00431 }
00432
00433 QList<QAction*> actions = contextualActions();
00434
00435 if (actions.count() < 1) {
00436
00437 Applet::contextMenuEvent(event);
00438 return;
00439 }
00440
00441 foreach (QAction* action, actions) {
00442 if (action) {
00443 desktopMenu.addAction(action);
00444 }
00445 }
00446 }
00447
00448 event->accept();
00449
00450 desktopMenu.exec(event->screenPos());
00451 }
00452
00453 void Containment::setFormFactor(FormFactor formFactor)
00454 {
00455 if (d->formFactor == formFactor && layout()) {
00456 return;
00457 }
00458
00459
00460 FormFactor was = d->formFactor;
00461 d->formFactor = formFactor;
00462
00463 if (isContainment() &&
00464 was != formFactor &&
00465 (d->type == PanelContainment ||
00466 d->type == CustomPanelContainment)) {
00467
00468 d->positionPanel(true);
00469 }
00470
00471 updateConstraints(Plasma::FormFactorConstraint);
00472 }
00473
00474 void Containment::setLocation(Location location)
00475 {
00476 if (d->location == location) {
00477 return;
00478 }
00479
00480 bool emitGeomChange = false;
00481
00482 if ((location == TopEdge || location == BottomEdge) &&
00483 (d->location == TopEdge || d->location == BottomEdge)) {
00484 emitGeomChange = true;
00485 }
00486
00487 if ((location == RightEdge || location == LeftEdge) &&
00488 (d->location == RightEdge || d->location == LeftEdge)) {
00489 emitGeomChange = true;
00490 }
00491
00492 d->location = location;
00493
00494 foreach (Applet* applet, d->applets) {
00495 applet->updateConstraints(Plasma::LocationConstraint);
00496 }
00497
00498 if (emitGeomChange) {
00499
00500
00501 emit geometryChanged();
00502 }
00503
00504 updateConstraints(Plasma::LocationConstraint);
00505 }
00506
00507 void Containment::addSiblingContainment()
00508 {
00509 emit addSiblingContainment(this);
00510 }
00511
00512 void Containment::clearApplets()
00513 {
00514 foreach (Applet *applet, d->applets) {
00515 applet->d->cleanUpAndDelete();
00516 }
00517
00518 d->applets.clear();
00519 }
00520
00521 Applet* Containment::addApplet(const QString& name, const QVariantList& args, const QRectF &appletGeometry)
00522 {
00523 return d->addApplet(name, args, appletGeometry);
00524 }
00525
00526
00527
00528
00529
00530 void Containment::addApplet(Applet *applet, const QPointF &pos, bool delayInit)
00531 {
00532 if (!delayInit && immutability() != Mutable) {
00533 return;
00534 }
00535
00536 if (!applet) {
00537 kDebug() << "adding null applet!?!";
00538 return;
00539 }
00540
00541 if (d->applets.contains(applet)) {
00542 kDebug() << "already have this applet!";
00543 }
00544
00545 Containment *currentContainment = applet->containment();
00546
00547 if (containmentType() == PanelContainment) {
00548
00549 setBackgroundHints(NoBackground);
00550 }
00551
00552 if (currentContainment && currentContainment != this) {
00553 emit currentContainment->appletRemoved(applet);
00554 applet->removeSceneEventFilter(currentContainment);
00555 KConfigGroup oldConfig = applet->config();
00556 currentContainment->d->applets.removeAll(applet);
00557 if (currentContainment->d->handles.contains(applet)) {
00558 currentContainment->d->handles.remove(applet);
00559 }
00560 applet->setParentItem(this);
00561
00562
00563 KConfigGroup c = config().group("Applets").group(QString::number(applet->id()));
00564 oldConfig.reparent(&c);
00565 applet->d->resetConfigurationObject();
00566 } else {
00567 applet->setParentItem(this);
00568 }
00569
00570 d->applets << applet;
00571
00572 connect(applet, SIGNAL(configNeedsSaving()), this, SIGNAL(configNeedsSaving()));
00573 connect(applet, SIGNAL(releaseVisualFocus()), this, SIGNAL(releaseVisualFocus()));
00574 connect(applet, SIGNAL(destroyed(QObject*)), this, SLOT(appletDestroyed(QObject*)));
00575
00576 if (pos != QPointF(-1, -1)) {
00577 applet->setPos(pos);
00578 }
00579
00580 if (delayInit) {
00581 if (containmentType() == DesktopContainment) {
00582 applet->installSceneEventFilter(this);
00583
00584 }
00585 } else {
00586 applet->init();
00587 Animator::self()->animateItem(applet, Animator::AppearAnimation);
00588 }
00589
00590 applet->updateConstraints(Plasma::AllConstraints | Plasma::StartupCompletedConstraint);
00591 if (!delayInit) {
00592 applet->flushPendingConstraintsEvents();
00593 }
00594
00595 emit appletAdded(applet, pos);
00596 }
00597
00598 Applet::List Containment::applets() const
00599 {
00600 return d->applets;
00601 }
00602
00603 void Containment::setScreen(int screen)
00604 {
00605
00606 if (d->type == DesktopContainment || d->type == CustomContainment) {
00607 #ifndef Q_OS_WIN
00608
00609 if (d->screen < 0 && screen > -1) {
00610 connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(positionToolBox()));
00611 } else if (screen < 0) {
00612 disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(positionToolBox()));
00613 }
00614 #endif
00615 if (screen > -1 && corona()) {
00616
00617 Containment* currently = corona()->containmentForScreen(screen);
00618 if (currently && currently != this) {
00619
00620 currently->setScreen(-1);
00621 }
00622 }
00623 }
00624
00625
00626 QDesktopWidget *desktop = QApplication::desktop();
00627 int numScreens = desktop->numScreens();
00628 if (screen < -1) {
00629 screen = -1;
00630 }
00631
00632
00633 if (screen < numScreens && screen > -1) {
00634 if (containmentType() == DesktopContainment ||
00635 containmentType() >= CustomContainment) {
00636 resize(desktop->screenGeometry(screen).size());
00637 }
00638 }
00639
00640 int oldScreen = d->screen;
00641 d->screen = screen;
00642 updateConstraints(Plasma::ScreenConstraint);
00643 if (oldScreen != screen) {
00644 emit screenChanged(oldScreen, screen, this);
00645 }
00646 }
00647
00648 int Containment::screen() const
00649 {
00650 return d->screen;
00651 }
00652
00653 QPoint Containment::effectiveScreenPos() const
00654 {
00655 if (d->screen < 0) {
00656 return QPoint();
00657 }
00658
00659 QRect r = QApplication::desktop()->screenGeometry(d->screen);
00660 if (containmentType() == PanelContainment ||
00661 containmentType() == CustomPanelContainment) {
00662 QRectF p = geometry();
00663
00664 switch (d->location) {
00665 case TopEdge:
00666 return QPoint(r.left() + p.x(), r.top());
00667 break;
00668 case BottomEdge:
00669 return QPoint(r.left() + p.x(), r.bottom() - p.height());
00670 break;
00671 case LeftEdge:
00672 return QPoint(r.left(), r.top() + (p.bottom() + INTER_CONTAINMENT_MARGIN));
00673 break;
00674 case RightEdge:
00675 return QPoint(r.right() - p.width(), r.top() + (p.bottom() + INTER_CONTAINMENT_MARGIN));
00676 break;
00677 default:
00678
00679 return p.topLeft().toPoint();
00680 break;
00681 }
00682 } else {
00683
00684
00685 return r.topLeft();
00686 }
00687 }
00688
00689 KPluginInfo::List Containment::listContainments(const QString &category,
00690 const QString &parentApp)
00691 {
00692 QString constraint;
00693
00694 if (parentApp.isEmpty()) {
00695 constraint.append("not exist [X-KDE-ParentApp]");
00696 } else {
00697 constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
00698 }
00699
00700 if (!category.isEmpty()) {
00701 if (!constraint.isEmpty()) {
00702 constraint.append(" and ");
00703 }
00704
00705 constraint.append("[X-KDE-PluginInfo-Category] == '").append(category).append("'");
00706 if (category == "Miscellaneous") {
00707 constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
00708 }
00709 }
00710
00711 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
00712
00713 return KPluginInfo::fromServices(offers);
00714 }
00715
00716 KPluginInfo::List Containment::listContainmentsForMimetype(const QString &mimetype)
00717 {
00718 QString constraint = QString("'%1' in [X-Plasma-DropMimeTypes]").arg(mimetype);
00719
00720 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
00721 return KPluginInfo::fromServices(offers);
00722 }
00723
00724 void Containment::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
00725 {
00726
00727 event->setAccepted(immutability() == Mutable &&
00728 (event->mimeData()->hasFormat(static_cast<Corona*>(scene())->appletMimeType()) ||
00729 KUrl::List::canDecode(event->mimeData())));
00730 }
00731
00732 void Containment::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
00733 {
00734 QGraphicsItem *item = scene()->itemAt(event->scenePos());
00735 event->setAccepted(item == this || !item);
00736 }
00737
00738 void Containment::dropEvent(QGraphicsSceneDragDropEvent *event)
00739 {
00740
00741
00742 QString mimetype(static_cast<Corona*>(scene())->appletMimeType());
00743
00744 if (event->mimeData()->hasFormat(mimetype) && scene()) {
00745 QString data = event->mimeData()->data(mimetype);
00746 QStringList appletNames = data.split('\n', QString::SkipEmptyParts);
00747
00748 foreach (const QString &appletName, appletNames) {
00749
00750 QRectF geom(mapFromScene(event->scenePos()), QSize(0, 0));
00751 addApplet(appletName, QVariantList(), geom);
00752 }
00753 event->acceptProposedAction();
00754 } else if (KUrl::List::canDecode(event->mimeData())) {
00755
00756
00757 KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
00758 foreach (const KUrl& url, urls) {
00759 KMimeType::Ptr mime = KMimeType::findByUrl(url);
00760 QString mimeName = mime->name();
00761 QRectF geom(event->pos(), QSize());
00762 QVariantList args;
00763 args << url.url();
00764
00765 KPluginInfo::List appletList = Applet::listAppletInfoForMimetype(mimeName);
00766
00767 if (appletList.isEmpty()) {
00768
00769 addApplet("icon", args, geom);
00770 } else {
00771
00773 QMenu choices;
00774 QHash<QAction*, QString> actionsToPlugins;
00775 foreach (const KPluginInfo &info, appletList) {
00776 QAction *action;
00777 if (!info.icon().isEmpty()) {
00778 action = choices.addAction(KIcon(info.icon()), info.name());
00779 } else {
00780 action = choices.addAction(info.name());
00781 }
00782
00783 actionsToPlugins.insert(action, info.pluginName());
00784 }
00785
00786 actionsToPlugins.insert(choices.addAction(i18n("Icon")), "icon");
00787 QAction *choice = choices.exec(event->screenPos());
00788 if (choice) {
00789 addApplet(actionsToPlugins[choice], args, geom);
00790 }
00791 }
00792 }
00793 event->acceptProposedAction();
00794 }
00795 }
00796
00797 void Containment::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00798 {
00799
00800
00801
00802 if (event->spontaneous()) {
00803 Applet::hoverEnterEvent(event);
00804 }
00805 Q_UNUSED(event)
00806 }
00807
00808 void Containment::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00809 {
00810
00811
00812
00813
00814 Q_UNUSED(event)
00815 }
00816
00817 void Containment::keyPressEvent(QKeyEvent *event)
00818 {
00819
00820 if (event->key() == Qt::Key_Tab) {
00821 if (!d->applets.isEmpty()) {
00822 kDebug() << "let's give focus to...." << (QObject*)d->applets.first();
00823 d->applets.first()->setFocus(Qt::TabFocusReason);
00824 }
00825 }
00826 }
00827
00828 bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
00829 {
00830 Applet *applet = qgraphicsitem_cast<Applet*>(watched);
00831
00832
00833 Q_ASSERT(applet!=0);
00834 if (!d->applets.contains(applet)) {
00835 return false;
00836 }
00837
00838
00839 switch (event->type()) {
00840 case QEvent::GraphicsSceneHoverEnter:
00841
00842 if (immutability() == Mutable && applet->immutability() == Mutable) {
00843 QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
00844 if (!d->handles.contains(applet)) {
00845
00846 AppletHandle *handle = new AppletHandle(this, applet, he->pos());
00847 d->handles[applet] = handle;
00848 connect(handle, SIGNAL(disappearDone(AppletHandle*)),
00849 this, SLOT(handleDisappeared(AppletHandle*)));
00850 connect(applet, SIGNAL(geometryChanged()),
00851 handle, SLOT(appletResized()));
00852 }
00853 }
00854 break;
00855 default:
00856 break;
00857 }
00858
00859 return false;
00860 }
00861
00862 QVariant Containment::itemChange(GraphicsItemChange change, const QVariant &value)
00863 {
00864
00865
00866 if (isContainment() &&
00867 (change == QGraphicsItem::ItemSceneHasChanged || change == QGraphicsItem::ItemPositionHasChanged) &&
00868 !d->positioning) {
00869 switch (containmentType()) {
00870 case PanelContainment:
00871 case CustomPanelContainment:
00872 d->positionPanel();
00873 break;
00874 default:
00875 d->positionContainment();
00876 break;
00877 }
00878 }
00879
00880 return Applet::itemChange(change, value);
00881 }
00882
00883 void Containment::enableAction(const QString &name, bool enable)
00884 {
00885 QAction *action = this->action(name);
00886 if (action) {
00887 action->setEnabled(enable);
00888 action->setVisible(enable);
00889 }
00890 }
00891
00892 void Containment::addToolBoxTool(QAction *action)
00893 {
00894 if (d->toolBox) {
00895 d->toolBox->addTool(action);
00896 }
00897 }
00898
00899 void Containment::removeToolBoxTool(QAction *action)
00900 {
00901 if (d->toolBox) {
00902 d->toolBox->removeTool(action);
00903 }
00904 }
00905
00906 void Containment::setToolBoxOpen(bool open)
00907 {
00908 if (open) {
00909 openToolBox();
00910 } else {
00911 closeToolBox();
00912 }
00913 }
00914
00915 void Containment::openToolBox()
00916 {
00917 if (d->toolBox) {
00918 d->toolBox->showToolBox();
00919 }
00920 }
00921
00922 void Containment::closeToolBox()
00923 {
00924 if (d->toolBox) {
00925 d->toolBox->hideToolBox();
00926 }
00927 }
00928
00929 void Containment::addAssociatedWidget(QWidget *widget)
00930 {
00931 Applet::addAssociatedWidget(widget);
00932 if (d->focusedApplet) {
00933 d->focusedApplet->addAssociatedWidget(widget);
00934 }
00935
00936 foreach (const Applet* applet, d->applets) {
00937 if (applet->d->activationAction) {
00938 widget->addAction(applet->d->activationAction);
00939 }
00940 }
00941 }
00942
00943 void Containment::removeAssociatedWidget(QWidget *widget)
00944 {
00945 Applet::removeAssociatedWidget(widget);
00946 if (d->focusedApplet) {
00947 d->focusedApplet->removeAssociatedWidget(widget);
00948 }
00949
00950 foreach (const Applet* applet, d->applets) {
00951 if (applet->d->activationAction) {
00952 widget->removeAction(applet->d->activationAction);
00953 }
00954 }
00955 }
00956
00957 KActionCollection& ContainmentPrivate::actions()
00958 {
00959 return static_cast<Applet*>(q)->d->actions;
00960 }
00961
00962 void ContainmentPrivate::focusApplet(Plasma::Applet *applet)
00963 {
00964 if (focusedApplet == applet) {
00965 return;
00966 }
00967
00968 if (q->screen() == -1) {
00969
00970
00971 emit q->focusRequested(q);
00972 }
00973
00974 QList<QWidget *> widgets = actions().associatedWidgets();
00975 if (focusedApplet) {
00976 foreach (QWidget *w, widgets) {
00977 focusedApplet->removeAssociatedWidget(w);
00978 }
00979 }
00980
00981
00982 if (applets.contains(applet)) {
00983
00984 focusedApplet = applet;
00985 if (focusedApplet) {
00986 foreach (QWidget *w, widgets) {
00987 focusedApplet->addAssociatedWidget(w);
00988 }
00989 }
00990 applet->setFocus(Qt::ShortcutFocusReason);
00991 } else {
00992 focusedApplet = 0;
00993 }
00994 }
00995
00996 void Containment::focusNextApplet()
00997 {
00998 if (d->applets.isEmpty()) {
00999 return;
01000 }
01001 int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) + 1 : 0;
01002 if (index >= d->applets.size()) {
01003 index = 0;
01004 }
01005 kDebug() << "index" << index;
01006 d->focusApplet(d->applets.at(index));
01007 }
01008
01009 void Containment::focusPreviousApplet()
01010 {
01011 if (d->applets.isEmpty()) {
01012 return;
01013 }
01014 int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) - 1 : -1;
01015 if (index < 0) {
01016 index = d->applets.size() - 1;
01017 }
01018 kDebug() << "index" << index;
01019 d->focusApplet(d->applets.at(index));
01020 }
01021
01022 void Containment::destroy()
01023 {
01024 if (immutability() != Mutable) {
01025 return;
01026 }
01027
01028 if (isContainment()) {
01029
01030
01031 if (d->type != PanelContainment && d->type != CustomPanelContainment &&
01032 (d->screen != -1 || d->screen >= QApplication::desktop()->numScreens())) {
01033 kDebug() << (QObject*)this << "containment has a screen number?" << d->screen;
01034 return;
01035 }
01036
01037
01038 if (KMessageBox::warningContinueCancel(view(), i18n("Do you really want to remove this %1?", name()),
01039 i18n("Remove %1", name()), KStandardGuiItem::remove()) == KMessageBox::Continue ) {
01040
01041 Applet::destroy();
01042 }
01043 } else {
01044 Applet::destroy();
01045 }
01046 }
01047
01048
01049
01050
01051 void ContainmentPrivate::toggleDesktopImmutability()
01052 {
01053 if (q->corona()) {
01054 if (q->corona()->immutability() == Mutable) {
01055 q->corona()->setImmutability(UserImmutable);
01056 } else if (q->corona()->immutability() == UserImmutable) {
01057 q->corona()->setImmutability(Mutable);
01058 }
01059 } else {
01060 if (q->immutability() == Mutable) {
01061 q->setImmutability(UserImmutable);
01062 } else if (q->immutability() == UserImmutable) {
01063 q->setImmutability(Mutable);
01064 }
01065 }
01066 }
01067
01068 void ContainmentPrivate::zoomIn()
01069 {
01070 emit q->zoomRequested(q, Plasma::ZoomIn);
01071 }
01072
01073 void ContainmentPrivate::zoomOut()
01074 {
01075 emit q->zoomRequested(q, Plasma::ZoomOut);
01076 }
01077
01078 ToolBox* ContainmentPrivate::createToolBox()
01079 {
01080 if (!toolBox) {
01081 switch (type) {
01082 case Containment::PanelContainment:
01083 toolBox = new PanelToolBox(q);
01084 toolBox->setSize(22);
01085 toolBox->setIconSize(QSize(16, 16));
01086 if (q->immutability() != Mutable) {
01087 toolBox->hide();
01088 }
01089 break;
01090 case Containment::DesktopContainment:
01091 toolBox = new DesktopToolBox(q);
01092 break;
01093 default:
01094 break;
01095 }
01096
01097 if (toolBox) {
01098 QObject::connect(toolBox, SIGNAL(toggled()), q, SIGNAL(toolBoxToggled()));
01099 positionToolBox();
01100 }
01101 }
01102
01103 return toolBox;
01104 }
01105
01106 void ContainmentPrivate::positionToolBox()
01107 {
01108 if (!toolBox) {
01109 return;
01110 }
01111
01112
01113 if (type == Containment::PanelContainment) {
01114 if (q->formFactor() == Vertical) {
01115 toolBox->setOrientation(Qt::Vertical);
01116 toolBox->setPos(q->geometry().width()/2 - toolBox->boundingRect().width()/2, q->geometry().height());
01117
01118 } else {
01119 toolBox->setOrientation(Qt::Horizontal);
01120 if (QApplication::layoutDirection() == Qt::RightToLeft) {
01121 toolBox->setPos(q->geometry().left(), q->geometry().height()/2 - toolBox->boundingRect().height()/2);
01122 } else {
01123 toolBox->setPos(q->geometry().width(), q->geometry().height()/2 - toolBox->boundingRect().height()/2);
01124 }
01125 }
01126 } else {
01127 QDesktopWidget *desktop = QApplication::desktop();
01128 QRectF r = desktop->availableGeometry(screen);
01129 if (q->view() && !q->view()->transform().isScaling()) {
01130 toolBox->setPos(r.topRight());
01131 } else {
01132 toolBox->setPos(q->mapFromScene(QPointF(q->geometry().topRight())));
01133 }
01134 }
01135 }
01136
01137 void ContainmentPrivate::triggerShowAddWidgets()
01138 {
01139 emit q->showAddWidgetsInterface(QPointF());
01140 }
01141
01142 void ContainmentPrivate::handleDisappeared(AppletHandle *handle)
01143 {
01144 if (handles.contains(handle->applet())) {
01145 handles.remove(handle->applet());
01146 handle->deleteLater();
01147 }
01148 }
01149
01150 void ContainmentPrivate::containmentConstraintsEvent(Plasma::Constraints constraints)
01151 {
01152 if (!q->isContainment()) {
01153 return;
01154 }
01155
01156
01157 if (constraints & Plasma::ImmutableConstraint) {
01158
01159 bool unlocked = q->immutability() == Mutable;
01160 q->setAcceptDrops(unlocked);
01161
01162 QAction *action = actions().action("add widgets");
01163 if (action) {
01164 action->setVisible(unlocked);
01165 action->setEnabled(unlocked);
01166 }
01167
01168
01169
01170
01171
01172
01173 action = actions().action("lock widgets");
01174 if (action) {
01175 action->setText(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets"));
01176 action->setIcon(KIcon(unlocked ? "object-locked" : "object-unlocked"));
01177 }
01178
01179
01180 foreach (Applet *a, applets) {
01181 a->updateConstraints(ImmutableConstraint);
01182 }
01183
01184 if (q->isContainment() && type == Containment::PanelContainment) {
01185 if (unlocked) {
01186 toolBox->show();
01187 } else {
01188 toolBox->hide();
01189 }
01190 }
01191 }
01192
01193 if ((constraints & Plasma::SizeConstraint || constraints & Plasma::ScreenConstraint) &&
01194 toolBox) {
01195 positionToolBox();
01196 }
01197
01198 if (constraints & Plasma::FormFactorConstraint) {
01199 if (toolBox) {
01200 if (q->formFactor() == Vertical) {
01201 toolBox->setOrientation(Qt::Vertical);
01202
01203 } else {
01204 toolBox->setOrientation(Qt::Horizontal);
01205 }
01206 }
01207
01208 foreach (Applet *applet, applets) {
01209 applet->updateConstraints(Plasma::FormFactorConstraint);
01210 }
01211 }
01212
01213 if (constraints & Plasma::SizeConstraint) {
01214 switch (q->containmentType()) {
01215 case Containment::PanelContainment:
01216 case Containment::CustomPanelContainment:
01217 positionPanel();
01218 break;
01219 default:
01220 positionContainment();
01221 break;
01222 }
01223 }
01224 }
01225
01226 Applet* ContainmentPrivate::addApplet(const QString& name, const QVariantList& args,
01227 const QRectF& appletGeometry, uint id, bool delayInit)
01228 {
01229 if (!delayInit && q->immutability() != Mutable) {
01230 kDebug() << "addApplet for" << name << "requested, but we're currently immutable!";
01231 return 0;
01232 }
01233
01234 QGraphicsView *v = q->view();
01235 if (v) {
01236 v->setCursor(Qt::BusyCursor);
01237 }
01238
01239 Applet* applet = Applet::load(name, id, args);
01240 if (v) {
01241 v->unsetCursor();
01242 }
01243
01244 if (!applet) {
01245 kDebug() << "Applet" << name << "could not be loaded.";
01246 applet = new Applet(0, QString(), id);
01247
01248
01249 }
01250
01251
01252
01253 q->addApplet(applet, appletGeometry.topLeft(), delayInit);
01254 return applet;
01255 }
01256
01257 bool ContainmentPrivate::regionIsEmpty(const QRectF ®ion, Applet *ignoredApplet) const
01258 {
01259 foreach (Applet *applet, applets) {
01260 if (applet != ignoredApplet && applet->geometry().intersects(region)) {
01261 return false;
01262 }
01263 }
01264 return true;
01265 }
01266
01267 void ContainmentPrivate::appletDestroyed(QObject* object)
01268 {
01269
01270
01271
01272
01273 Applet* applet = static_cast<Plasma::Applet*>(object);
01274 applets.removeAll(applet);
01275 if (focusedApplet == applet) {
01276 focusedApplet = 0;
01277 }
01278 emit q->appletRemoved(applet);
01279 emit q->configNeedsSaving();
01280 }
01281
01282 void ContainmentPrivate::containmentAppletAnimationComplete(QGraphicsItem *item, Plasma::Animator::Animation anim)
01283 {
01284 if (anim == Animator::AppearAnimation &&
01285 q->containmentType() == Containment::DesktopContainment &&
01286 item->parentItem() == q) {
01287 Applet *applet = qgraphicsitem_cast<Applet*>(item);
01288
01289 if (applet) {
01290 applet->installSceneEventFilter(q);
01291 KConfigGroup *cg = applet->d->mainConfigGroup();
01292 applet->save(*cg);
01293 emit q->configNeedsSaving();
01294
01295 }
01296 }
01297 }
01298
01299 void ContainmentPrivate::positionContainment()
01300 {
01301 Corona *c = q->corona();
01302 if (!c) {
01303 return;
01304 }
01305
01306 QList<Containment*> containments = c->containments();
01307 QMutableListIterator<Containment*> it(containments);
01308
01309 bool noCollissions = true;
01310 while (it.hasNext()) {
01311 Containment *containment = it.next();
01312 if (containment == q ||
01313 containment->containmentType() == Containment::PanelContainment ||
01314 containment->containmentType() == Containment::CustomPanelContainment) {
01315
01316
01317 it.remove();
01318 continue;
01319 }
01320
01321 if (noCollissions && q->collidesWithItem(containment)) {
01322 noCollissions = false;
01323 }
01324 }
01325
01326 if (noCollissions) {
01327
01328
01329 return;
01330 }
01331
01332 int width = 0;
01333 int height = 0;
01334
01335 QDesktopWidget *desktop = QApplication::desktop();
01336 int numScreens = desktop->numScreens();
01337
01338 for (int i = 0; i < numScreens; ++i) {
01339 QRect otherScreen = desktop->screenGeometry(i);
01340
01341 if (width < otherScreen.width()) {
01342 width = otherScreen.width();
01343 }
01344
01345 if (height < otherScreen.height()) {
01346 height = otherScreen.height();
01347 }
01348 }
01349
01350
01351 width = (width + INTER_CONTAINMENT_MARGIN) * 4;
01352 height += INTER_CONTAINMENT_MARGIN;
01353
01354
01355 QRectF r = q->boundingRect();
01356 QPointF topLeft(0, 0);
01357 q->setPos(topLeft);
01358
01359 positioning = true;
01360 while (true) {
01361 it.toFront();
01362 int shift = 0;
01363
01364 while (it.hasNext()) {
01365 Containment *containment = it.next();
01366
01367 if (q->collidesWithItem(containment)) {
01368 shift = containment->geometry().right();
01369
01370
01371
01372
01373 break;
01374 }
01375
01376 QPointF pos = containment->pos();
01377 if (pos.x() <= topLeft.x() && pos.y() <= topLeft.y()) {
01378
01379
01380
01381 it.remove();
01382 }
01383 }
01384
01385 if (shift == 0) {
01386
01387 break;
01388 }
01389
01390 if (shift + r.width() + INTER_CONTAINMENT_MARGIN > width) {
01391
01392 topLeft = QPoint(0, topLeft.y() + height);
01393 } else {
01394 topLeft.setX(shift + INTER_CONTAINMENT_MARGIN);
01395 }
01396
01397 q->setPos(topLeft);
01398
01399
01400 }
01401
01402 positioning = false;
01403 }
01404
01405 void ContainmentPrivate::positionPanel(bool force)
01406 {
01407 if (!q->scene()) {
01408 kDebug() << "no scene yet";
01409 return;
01410 }
01411
01412
01413
01414
01415 const QPointF p = q->pos();
01416
01417 if (!force &&
01418 p.y() + q->size().height() < -INTER_CONTAINMENT_MARGIN &&
01419 q->scene()->collidingItems(q).isEmpty()) {
01420
01421 return;
01422 }
01423
01424
01425 bool horiz = q->formFactor() == Plasma::Horizontal;
01426 qreal bottom = horiz ? 0 : VERTICAL_STACKING_OFFSET;
01427 qreal lastHeight = 0;
01428
01429
01430
01431
01432 foreach (const Containment* other, q->corona()->containments()) {
01433 if (other == q ||
01434 (other->containmentType() != Containment::PanelContainment &&
01435 other->containmentType() != Containment::CustomPanelContainment) ||
01436 horiz != (other->formFactor() == Plasma::Horizontal)) {
01437
01438 continue;
01439 }
01440
01441 if (horiz) {
01442 qreal y = other->pos().y();
01443 if (y < bottom) {
01444 lastHeight = other->size().height();
01445 bottom = y;
01446 }
01447 } else {
01448 qreal width = other->size().width();
01449 qreal x = other->pos().x() + width;
01450 if (x > bottom) {
01451 lastHeight = width;
01452 bottom = x + lastHeight;
01453 }
01454 }
01455 }
01456
01457 kDebug() << "positioning" << (horiz ? "" : "non-") << "horizontal panel; forced?" << force;
01458
01459
01460 QPointF newPos;
01461 if (horiz) {
01462 bottom -= lastHeight + INTER_CONTAINMENT_MARGIN;
01463
01464 kDebug() << "moved to" << QPointF(0, bottom - q->size().height());
01465 newPos = QPointF(0, bottom - q->size().height());
01466 } else {
01467 bottom += lastHeight + INTER_CONTAINMENT_MARGIN;
01468
01469 kDebug() << "moved to" << QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
01470 newPos = QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
01471 }
01472
01473 positioning = true;
01474 if (p != newPos) {
01475 q->setPos(newPos);
01476 emit q->geometryChanged();
01477 }
01478 positioning = false;
01479 }
01480
01481
01482 }
01483
01484 #include "containment.moc"
01485