• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libplasma

containment.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2007 by Aaron Seigo <aseigo@kde.org>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License as
00006  *   published by the Free Software Foundation; either version 2, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details
00013  *
00014  *   You should have received a copy of the GNU Library General Public
00015  *   License along with this program; if not, write to the
00016  *   Free Software Foundation, Inc.,
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018  */
00019 
00020 #include "containment.h"
00021 
00022 #include <QAction>
00023 #include <QDesktopWidget>
00024 #include <QFile>
00025 #include <QGraphicsSceneContextMenuEvent>
00026 #include <QGraphicsView>
00027 #include <QMimeData>
00028 #include <QPainter>
00029 #include <QStyleOptionGraphicsItem>
00030 
00031 #include <KApplication>
00032 #include <KAuthorized>
00033 #include <KIcon>
00034 #include <KMenu>
00035 #include <KMimeType>
00036 #include <KRun>
00037 #include <KServiceTypeTrader>
00038 #include <KStandardDirs>
00039 
00040 #include "applethandle_p.h"
00041 #include "corona.h"
00042 #include "phase.h"
00043 #include "desktoptoolbox_p.h"
00044 #include "svg.h"
00045 
00046 #include "layouts/freelayout.h"
00047 #include "layouts/boxlayout.h"
00048 
00049 namespace Plasma
00050 {
00051 
00052 static const int INTER_CONTAINMENT_MARGIN = 6;
00053 
00054 class Containment::Private
00055 {
00056 public:
00057     Private(Containment* c)
00058         : q(c),
00059           formFactor(Planar),
00060           location(Floating),
00061           screen(-1),
00062           toolbox(0),
00063           type(Containment::NoContainmentType)
00064     {
00065     }
00066 
00067     ~Private()
00068     {
00069         qDeleteAll(applets);
00070         applets.clear();
00071     }
00072 
00073     DesktopToolbox* createToolbox()
00074     {
00075         if (!toolbox) {
00076             toolbox = new DesktopToolbox(q);
00077             toolbox->setPos(q->geometry().width() - toolbox->boundingRect().width(), 0);
00078         }
00079 
00080         return toolbox;
00081     }
00082 
00083     Containment *q;
00084     FormFactor formFactor;
00085     Location location;
00086     Applet::List applets;
00087     QMap<Applet*, AppletHandle*> handles;
00088     int screen;
00089     DesktopToolbox *toolbox;
00090     Containment::Type type;
00091 };
00092 
00093 Containment::Containment(QGraphicsItem* parent,
00094                          const QString& serviceId,
00095                          uint containmentId)
00096     : Applet(parent, serviceId, containmentId),
00097       d(new Private(this))
00098 {
00099     // WARNING: do not access config() OR globalConfig() in this method!
00100     //          that requires a scene, which is not available at this point
00101     setDrawStandardBackground(false);
00102     setContainmentType(CustomContainment);
00103 }
00104 
00105 Containment::Containment(QObject* parent, const QVariantList& args)
00106     : Applet(parent, args),
00107       d(new Private(this))
00108 {
00109     // WARNING: do not access config() OR globalConfig() in this method!
00110     //          that requires a scene, which is not available at this point
00111     setDrawStandardBackground(false);
00112 }
00113 
00114 Containment::~Containment()
00115 {
00116     delete d;
00117 }
00118 
00119 void Containment::init()
00120 {
00121     setCachePaintMode(NoCacheMode);
00122     setFlag(QGraphicsItem::ItemIsMovable, false);
00123     setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
00124     setAcceptDrops(true);
00125     setAcceptsHoverEvents(true);
00126 
00127     //TODO: would be nice to not do this on init, as it causes Phase to init
00128     connect(Phase::self(), SIGNAL(animationComplete(QGraphicsItem*,Plasma::Phase::Animation)),
00129             this, SLOT(appletAnimationComplete(QGraphicsItem*,Plasma::Phase::Animation)));
00130 
00131     if (d->type == NoContainmentType) {
00132         setContainmentType(DesktopContainment);
00133     }
00134 }
00135 
00136 void Containment::loadConstraints(KConfigGroup* group)
00137 {
00138     /*kDebug() << "!!!!!!!!!!!!initConstraints" << group->name() << containmentType();
00139     kDebug() << "    location:" << group->readEntry("location", (int)d->location);
00140     kDebug() << "    geom:" << group->readEntry("geometry", geometry());
00141     kDebug() << "    formfactor:" << group->readEntry("formfactor", (int)d->formFactor);
00142     kDebug() << "    screen:" << group->readEntry("screen", d->screen);*/
00143     setGeometry(group->readEntry("geometry", geometry()));
00144     setLocation((Plasma::Location)group->readEntry("location", (int)d->location));
00145     setFormFactor((Plasma::FormFactor)group->readEntry("formfactor", (int)d->formFactor));
00146     setScreen(group->readEntry("screen", d->screen));
00147 }
00148 
00149 void Containment::saveConstraints(KConfigGroup* group) const
00150 {
00151     // locking is saved in Applet::save
00152     group->writeEntry("screen", d->screen);
00153     group->writeEntry("formfactor", (int)d->formFactor);
00154     group->writeEntry("location", (int)d->location);
00155 }
00156 
00157 void Containment::containmentConstraintsUpdated(Plasma::Constraints constraints)
00158 {
00159     //kDebug() << "got containmentConstraintsUpdated" << constraints << (QObject*)d->toolbox;
00160     if (d->toolbox) {
00161         if (constraints & Plasma::ScreenConstraint) {
00162             d->toolbox->setPos(geometry().width() - d->toolbox->boundingRect().width(), 0);
00163         }
00164 
00165         if (constraints & Plasma::ImmutableConstraint) {
00166             d->toolbox->enableTool("addwidgets", !isImmutable());
00167         }
00168     }
00169 }
00170 
00171 Containment::Type Containment::containmentType() const
00172 {
00173     return d->type;
00174 }
00175 
00176 void Containment::setContainmentType(Containment::Type type)
00177 {
00178     d->type = type;
00179 
00180     if (isContainment() && type == DesktopContainment) {
00181         if (!d->toolbox) {
00182             Plasma::Widget *addWidgetTool = addToolBoxTool("addwidgets", "list-add", i18n("Add Widgets"));
00183             connect(addWidgetTool, SIGNAL(clicked()), this, SIGNAL(showAddWidgets()));
00184 
00185             Plasma::Widget *zoomInTool = addToolBoxTool("zoomIn", "zoom-in", i18n("Zoom In"));
00186             connect(zoomInTool, SIGNAL(clicked()), this, SIGNAL(zoomIn()));
00187 
00188             Plasma::Widget *zoomOutTool = addToolBoxTool("zoomOut", "zoom-out", i18n("Zoom Out"));
00189             connect(zoomOutTool, SIGNAL(clicked()), this, SIGNAL(zoomOut()));
00190         }
00191     } else {
00192         delete d->toolbox;
00193         d->toolbox = 0;
00194     }
00195 }
00196 
00197 Corona* Containment::corona() const
00198 {
00199     return dynamic_cast<Corona*>(scene());
00200 }
00201 
00202 void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
00203 {
00204     //kDebug() << "let's see if we manage to get a context menu here, huh";
00205     if (!isContainment() || !scene() || !KAuthorized::authorizeKAction("desktop_contextmenu")) {
00206         Applet::contextMenuEvent(event);
00207         return;
00208     }
00209 
00210     QPointF point = event->scenePos();
00211     QGraphicsItem* item = scene()->itemAt(point);
00212     if (item == this) {
00213         item = 0;
00214     }
00215 
00216     Applet* applet = 0;
00217 
00218     while (item) {
00219         applet = qgraphicsitem_cast<Applet*>(item);
00220         if (applet && !applet->isContainment()) {
00221             break;
00222         }
00223 
00224         // applet may have a value due to finding a containment!
00225         applet = 0;
00226         item = item->parentItem();
00227     }
00228 
00229     KMenu desktopMenu;
00230     //kDebug() << "context menu event " << (QObject*)applet;
00231     if (applet) {
00232         bool hasEntries = false;
00233 
00234         QList<QAction*> actions = applet->contextActions();
00235         if (!actions.isEmpty()) {
00236             foreach(QAction* action, actions) {
00237                 desktopMenu.addAction(action);
00238             }
00239             hasEntries = true;
00240         }
00241 
00242         if (applet->hasConfigurationInterface()) {
00243             QAction* configureApplet = new QAction(i18n("%1 Settings", applet->name()), &desktopMenu);
00244             configureApplet->setIcon(KIcon("configure"));
00245             connect(configureApplet, SIGNAL(triggered(bool)),
00246                     applet, SLOT(showConfigurationInterface()));
00247             desktopMenu.addAction(configureApplet);
00248             hasEntries = true;
00249         }
00250 
00251         actions = contextActions();
00252         if (actions.count() > 0) {
00253             hasEntries = true;
00254             QMenu *containmentActionMenu = &desktopMenu;
00255 
00256             if (actions.count() > 2) {
00257                 containmentActionMenu = new KMenu(i18n("%1 Options", name()), &desktopMenu);
00258                 desktopMenu.addMenu(containmentActionMenu);
00259             }
00260 
00261             foreach(QAction* action, actions) {
00262                 containmentActionMenu->addAction(action);
00263             }
00264         }
00265 
00266         if (scene() && !static_cast<Corona*>(scene())->isImmutable()) {
00267             if (hasEntries) {
00268                 desktopMenu.addSeparator();
00269             }
00270 
00271             QAction* closeApplet = new QAction(i18n("Remove this %1", applet->name()), &desktopMenu);
00272             QVariant appletV;
00273             appletV.setValue((QObject*)applet);
00274             closeApplet->setData(appletV);
00275             closeApplet->setIcon(KIcon("edit-delete"));
00276             connect(closeApplet, SIGNAL(triggered(bool)),
00277                     this, SLOT(destroyApplet()));
00278             desktopMenu.addAction(closeApplet);
00279             hasEntries = true;
00280         }
00281 
00282         if (!hasEntries) {
00283             Applet::contextMenuEvent(event);
00284             kDebug() << "no entries";
00285             return;
00286         }
00287     } else {
00288         if (!scene() || (static_cast<Corona*>(scene())->isImmutable() && !KAuthorized::authorizeKAction("unlock_desktop"))) {
00289             //kDebug() << "immutability";
00290             Applet::contextMenuEvent(event);
00291             return;
00292         }
00293 
00294         QList<QAction*> actions = contextActions();
00295 
00296         if (actions.count() < 1) {
00297             //kDebug() << "no applet, but no actions";
00298             Applet::contextMenuEvent(event);
00299             return;
00300         }
00301 
00302         foreach(QAction* action, actions) {
00303             desktopMenu.addAction(action);
00304         }
00305     }
00306 
00307     event->accept();
00308     //kDebug() << "executing at" << event->screenPos();
00309     desktopMenu.exec(event->screenPos());
00310 }
00311 
00312 void Containment::destroyApplet()
00313 {
00314     QAction *action = qobject_cast<QAction*>(sender());
00315 
00316     if (!action) {
00317         return;
00318     }
00319 
00320     Applet *applet = qobject_cast<Applet*>(action->data().value<QObject*>());
00321     Phase::self()->animateItem(applet, Phase::Disappear);
00322 }
00323 
00324 void Containment::setFormFactor(FormFactor formFactor)
00325 {
00326     if (d->formFactor == formFactor && layout()) {
00327         return;
00328     }
00329 
00330     //kDebug() << "switching FF to " << formFactor;
00331     d->formFactor = formFactor;
00332     Layout *lay = 0;
00333     //note: setting a new layout autodeletes the old one
00334     //and creating a layout calls setLayout on the parent
00335 
00336     switch (d->formFactor) {
00337         case Planar:
00338             lay = new FreeLayout(this);
00339             break;
00340         case Horizontal:
00341             lay = new BoxLayout(BoxLayout::LeftToRight, this);
00342             lay->setMargin(0);
00343             lay->setSpacing(4);
00344             break;
00345         case Vertical:
00346             lay = new BoxLayout(BoxLayout::TopToBottom, this);
00347             lay->setMargin(0);
00348             lay->setSpacing(4);
00349             break;
00350         case MediaCenter:
00351             //FIXME: need a layout type here!
00352             setLayout(0); //auto-delete
00353             break;
00354         default:
00355             kDebug() << "This can't be happening! Or... can it? ;)" << d->formFactor;
00356             setLayout(0); //auto-delete
00357             break;
00358     }
00359 
00360     if (lay) {
00361         foreach (Applet* applet, d->applets) {
00362             lay->addItem(applet);
00363             applet->updateConstraints(Plasma::FormFactorConstraint);
00364         }
00365     }
00366 
00367     updateConstraints(Plasma::FormFactorConstraint);
00368 }
00369 
00370 FormFactor Containment::formFactor() const
00371 {
00372     if (isContainment()) {
00373         return d->formFactor;
00374     }
00375 
00376     return Applet::formFactor();
00377 }
00378 
00379 void Containment::setLocation(Location location)
00380 {
00381     if (d->location == location) {
00382         return;
00383     }
00384 
00385     d->location = location;
00386 
00387     foreach (Applet* applet, d->applets) {
00388         applet->updateConstraints(Plasma::LocationConstraint);
00389     }
00390 
00391     setScreen(screen());
00392     updateConstraints(Plasma::LocationConstraint);
00393 }
00394 
00395 Location Containment::location() const
00396 {
00397     return d->location;
00398 }
00399 
00400 void Containment::clearApplets()
00401 {
00402     qDeleteAll(d->applets);
00403     d->applets.clear();
00404 }
00405 
00406 Applet* Containment::addApplet(const QString& name, const QVariantList& args, uint id, const QRectF& appletGeometry, bool delayInit)
00407 {
00408     QGraphicsView *v = view();
00409     if (v) {
00410         v->setCursor(Qt::BusyCursor);
00411     }
00412 
00413     Applet* applet = Applet::loadApplet(name, id, args);
00414     if (v) {
00415         v->unsetCursor();
00416     }
00417 
00418     if (!applet) {
00419         kDebug() << "Applet" << name << "could not be loaded.";
00420         applet = new Applet;
00421     }
00422 
00423     addApplet(applet, appletGeometry.topLeft(), delayInit);
00424 
00425     if (containmentType() != PanelContainment) {
00426         //kDebug() << "adding applet" << applet->name() << "with a default geometry of" << appletGeometry << appletGeometry.isValid();
00427         if (appletGeometry.isValid()) {
00428             applet->setGeometry(appletGeometry);
00429         } else if (appletGeometry.x() != -1 && appletGeometry.y() != -1) {
00430             // yes, this means we can't have items start -1, -1
00431             applet->setGeometry(QRectF(appletGeometry.topLeft(),
00432                                     applet->sizeHint()));
00433         } else if (geometry().isValid()) {
00434             applet->setGeometry(geometryForApplet(applet));
00435         }
00436     }
00437 
00438     //kDebug() << applet->name() << "sizehint:" << applet->sizeHint() << "geometry:" << applet->geometry();
00439 
00440     Corona *c = corona();
00441     if (c) {
00442         connect(applet, SIGNAL(configNeedsSaving()), corona(), SLOT(scheduleConfigSync()));
00443     }
00444 
00445     emit appletAdded(applet);
00446     return applet;
00447 }
00448 
00449 //pos must be relative to the containment already. use mapfromscene.
00450 //what we're trying to do here for panels is make the applet go to the requested position,
00451 //or somewhere close to it, and get integrated properly into the containment as if it were created
00452 //there.
00453 void Containment::addApplet(Applet *applet, const QPointF &pos, bool dontInit)
00454 {
00455     if (!applet) {
00456         kDebug() << "adding null applet!?!";
00457         return;
00458     }
00459 
00460     Containment *currentContainment = applet->containment();
00461     int index = -1;
00462 
00463     if (containmentType() == PanelContainment) {
00464         //panels don't want backgrounds, which is important when setting geometry
00465         applet->setDrawStandardBackground(false);
00466 
00467         // Calculate where the user wants the applet to go before adding it
00468         //so long as this isn't a new applet with a delayed init
00469         if (! dontInit || (currentContainment && currentContainment != this)) {
00470             index = indexAt(pos);
00471         }
00472     }
00473 
00474     if (currentContainment && currentContainment != this) {
00475         applet->removeSceneEventFilter(currentContainment);
00476         KConfigGroup oldConfig = applet->config();
00477         applet->resetConfigurationObject();
00478         currentContainment->d->applets.removeAll(applet);
00479         addChild(applet);
00480 
00481         //FIXME: we will lose parts of the existing configuration that aren't
00482         //       resaved. but KConfigGroup::reparent does not exist in 4.0.x
00483         // now move the old config to the new location
00484         // KConfigGroup c = config().group("Applets").group(QString::number(applet->id()));
00485         // oldConfig.reparent(&c);
00486     } else {
00487         addChild(applet);
00488     }
00489 
00490     d->applets << applet;
00491 
00492     connect(applet, SIGNAL(destroyed(QObject*)),
00493             this, SLOT(appletDestroyed(QObject*)));
00494 
00495     if (containmentType() == PanelContainment) {
00496         // Reposition the applet after adding has been done
00497         if (index != -1) {
00498             BoxLayout *l = dynamic_cast<BoxLayout *>(layout());
00499             l->insertItem(index, l->takeAt(l->indexOf(applet)));
00500             d->applets.removeAll(applet);
00501             d->applets.insert(index, applet);
00502         }
00503     } else {
00504         //FIXME if it came from a panel its bg was disabled
00505         //maybe we should expect the applet to handle that on a constraint update?
00506 
00507         //should we really do this? hell, do we have any business playing with the geometry of
00508         //non-panel applets at all?
00509         if (pos != QPointF(-1, -1)) {
00510             applet->setPos(pos);
00511         }
00512     }
00513     prepareApplet(applet, dontInit); //must at least flush constraints
00514 }
00515 
00516 //containment-relative pos... right?
00517 int Containment::indexAt(const QPointF &pos) const
00518 {
00519     if (pos == QPointF(-1, -1)) {
00520         return -1;
00521     }
00522     BoxLayout *l = dynamic_cast<BoxLayout *>(layout());
00523     if (l) {
00524         foreach (Applet *existingApplet, d->applets) {
00525             if (formFactor() == Horizontal) {
00526                 qreal middle = (existingApplet->geometry().left() +
00527                         existingApplet->geometry().right()) / 2.0;
00528                 // Applets are checked in order so there is no need to check
00529                 // if the position is equal to or greater than the applet's
00530                 // leftmost point. This also allows for dropping in the gap
00531                 // between applets.
00532                 if (pos.x() < middle) {
00533                     return l->indexOf(existingApplet);
00534                 } else if (pos.x() <= existingApplet->geometry().right()) {
00535                     return l->indexOf(existingApplet) + 1;
00536                 }
00537             } else {
00538                 qreal middle = (existingApplet->geometry().top() +
00539                         existingApplet->geometry().bottom()) / 2.0;
00540                 if (pos.y() < middle) {
00541                     return l->indexOf(existingApplet);
00542                 } else if (pos.y() <= existingApplet->geometry().bottom()) {
00543                     return l->indexOf(existingApplet) + 1;
00544                 }
00545             }
00546         }
00547     }
00548     return -1;
00549 }
00550 
00551 void Containment::prepareApplet(Applet *applet, bool delayInit)
00552 {
00553     if (delayInit) {
00554         if (containmentType() == DesktopContainment) {
00555             applet->installSceneEventFilter(this);
00556         }
00557     } else {
00558         applet->init();
00559         Phase::self()->animateItem(applet, Phase::Appear);
00560     }
00561 
00562     applet->updateConstraints(Plasma::AllConstraints);
00563     if (!delayInit) {
00564         applet->flushUpdatedConstraints();
00565     }
00566 }
00567 
00568 QRectF Containment::geometryForApplet(Applet *applet) const
00569 {
00570     // The value part of these maps isn't used. Only sorted keys are needed.
00571     QMap<qreal, bool> xPositions;
00572     QMap<qreal, bool> yPositions;
00573 
00574     // Add the top-left corner offset by the applet's border
00575     QPointF offset = applet->boundingRect().topLeft();
00576     xPositions[-offset.x()] = true;
00577     yPositions[-offset.y()] = true;
00578 
00579     QRectF placement(QPointF(0, 0), applet->sizeHint());
00580     foreach (Applet *existingApplet, d->applets) {
00581         QPointF bottomRight = existingApplet->geometry().bottomRight();
00582         if (bottomRight.x() + placement.width() < geometry().width()) {
00583             xPositions[bottomRight.x() + 1] = true;
00584         }
00585         if (bottomRight.y() + placement.height() < geometry().height()) {
00586             yPositions[bottomRight.y() + 1] = true;
00587         }
00588     }
00589 
00590     // Try to fit it in an empty space
00591     foreach (qreal x, xPositions.keys()) {
00592         foreach (qreal y, yPositions.keys()) {
00593             placement.moveTo(x, y);
00594             if (regionIsEmpty(placement, applet)) {
00595                 return placement;
00596             }
00597         }
00598     }
00599 
00600     // Otherwise place it in the centre of the screen
00601     placement.moveLeft(geometry().width() / 2 - placement.width() / 2);
00602     placement.moveTop(geometry().height() / 2 - placement.height() / 2);
00603     return placement;
00604 }
00605 
00606 bool Containment::regionIsEmpty(const QRectF &region, Applet *ignoredApplet) const
00607 {
00608     foreach (Applet *applet, d->applets) {
00609         if (applet != ignoredApplet && applet->geometry().intersects(region)) {
00610             return false;
00611         }
00612     }
00613     return true;
00614 }
00615 
00616 void Containment::appletDestroyed(QObject* object)
00617 {
00618     // we do a static_cast here since it really isn't an Applet by this
00619     // point anymore since we are in the qobject dtor. we don't actually
00620     // try and do anything with it, we just need the value of the pointer
00621     // so this unsafe looking code is actually just fine.
00622     Applet* applet = static_cast<Plasma::Applet*>(object);
00623     d->applets.removeAll(applet);
00624     emit appletRemoved(applet);
00625 }
00626 
00627 void Containment::appletAnimationComplete(QGraphicsItem *item, Plasma::Phase::Animation anim)
00628 {
00629     if (anim == Phase::Disappear) {
00630         QGraphicsItem *parent = item->parentItem();
00631 
00632         while (parent) {
00633             if (parent == this) {
00634                 Applet *applet = qgraphicsitem_cast<Applet*>(item);
00635 
00636                 if (applet) {
00637                     applet->destroy();
00638                 }
00639 
00640                 break;
00641             }
00642 
00643             parent = parent->parentItem();
00644         }
00645     } else if (anim == Phase::Appear) {
00646         if (containmentType() == DesktopContainment &&
00647             item->parentItem() == this &&
00648             qgraphicsitem_cast<Applet*>(item)) {
00649                 item->installSceneEventFilter(this);
00650         }
00651     }
00652 }
00653 
00654 Applet::List Containment::applets() const
00655 {
00656     return d->applets;
00657 }
00658 
00659 void Containment::setScreen(int screen)
00660 {
00661     // screen of -1 means no associated screen.
00662     // sanity check to make sure someone else doesn't have this screen already!
00663     if (screen > -1 && containmentType() == DesktopContainment && corona()) {
00664         Containment* currently = corona()->containmentForScreen(screen);
00665         if (currently && currently != this) {
00666             //kDebug() << "currently is on screen" << currently->screen() << "and is" << currently->name() << (QObject*)currently << (QObject*)this;
00667             currently->setScreen(-1);
00668         }
00669     }
00670 
00671     //kDebug() << "setting screen to" << screen << "and we are a" << containmentType();
00672     QDesktopWidget *desktop = QApplication::desktop();
00673     int numScreens = desktop->numScreens();
00674     if (screen < -1) {
00675         screen = -1;
00676     }
00677 
00678     //kDebug() << "setting screen to " << screen << "and type is" << containmentType();
00679     if (screen < numScreens && screen > -1) {
00680         QRect r = desktop->screenGeometry(screen);
00681 
00682         if (containmentType() == DesktopContainment) {
00683             // we need to find how many screens are to our top and left
00684             // to calculate the proper offsets for the margins.
00685             int x = r.x();
00686             int y = r.y();
00687             int screensLeft = 0;
00688             int screensAbove = 0;
00689             for (int i = 0; i < numScreens; ++i) {
00690                 QRect otherScreen = desktop->screenGeometry(screen);
00691                 if (x > otherScreen.x()) {
00692                     ++screensLeft;
00693                 }
00694 
00695                 if (y > otherScreen.y()) {
00696                     ++screensAbove;
00697                 }
00698             }
00699 
00700             r.moveLeft(r.x() + INTER_CONTAINMENT_MARGIN * screensLeft);
00701             r.moveTop(r.y() + INTER_CONTAINMENT_MARGIN * screensAbove);
00702 
00703             // FIXME: positioning at this x,y will break if we switch between containments for a
00704             //        given screen! we should change the pos() on new containment setup.
00705             setGeometry(r);
00706             //kDebug() << "setting geometry to" << desktop->screenGeometry(screen) << r << geometry();
00707         } else if (containmentType() == PanelContainment) {
00708             QRect r = desktop->screenGeometry(screen);
00709             //kDebug() << "we are a panel on" << r << ", let's move ourselves to a negative coordinate system" << -(r.x() * 2) - r.height() - INTER_CONTAINMENT_MARGIN;
00710             // panels are moved into negative coords; we double the x() so that each screen get's
00711             // it's own area for panels
00712             int vertOffset = (r.y() * 2) + r.height() + INTER_CONTAINMENT_MARGIN;
00713             translate(0, -vertOffset);
00714         }
00715     }
00716 
00717     d->screen = screen;
00718     updateConstraints(Plasma::ScreenConstraint);
00719 }
00720 
00721 int Containment::screen() const
00722 {
00723     return d->screen;
00724 }
00725 
00726 KPluginInfo::List Containment::knownContainments(const QString &category,
00727                                                  const QString &parentApp)
00728 {
00729     QString constraint;
00730 
00731     if (parentApp.isEmpty()) {
00732         constraint.append("not exist [X-KDE-ParentApp]");
00733     } else {
00734         constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
00735     }
00736 
00737     if (!category.isEmpty()) {
00738         if (!constraint.isEmpty()) {
00739             constraint.append(" and ");
00740         }
00741 
00742         constraint.append("[X-KDE-PluginInfo-Category] == '").append(category).append("'");
00743         if (category == "Miscellaneous") {
00744             constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
00745         }
00746     }
00747 
00748     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
00749     //kDebug() << "constraint was" << constraint << "which got us" << offers.count() << "matches";
00750     return KPluginInfo::fromServices(offers);
00751 }
00752 
00753 KPluginInfo::List Containment::knownContainmentsForMimetype(const QString &mimetype)
00754 {
00755     QString constraint = QString("'%1' in MimeTypes").arg(mimetype);
00756     //kDebug() << "knownContainmentsForMimetype with" << mimetype << constraint;
00757     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
00758     return KPluginInfo::fromServices(offers);
00759 }
00760 
00761 void Containment::dropEvent(QGraphicsSceneDragDropEvent *event)
00762 {
00763     //kDebug() << "drop event:" << event->mimeData()->text();
00764 
00765     QString mimetype(static_cast<Corona*>(scene())->appletMimeType());
00766 
00767     if (event->mimeData()->hasFormat(mimetype) && scene()) {
00768         QString plasmoidName;
00769         plasmoidName = event->mimeData()->data(mimetype);
00770         QRectF geom(mapFromScene(event->scenePos()), QSize(0, 0));
00771         addApplet(plasmoidName, QVariantList(), 0, geom);
00772         event->acceptProposedAction();
00773     } else if (KUrl::List::canDecode(event->mimeData())) {
00774         KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
00775         foreach (const KUrl& url, urls) {
00776             KMimeType::Ptr mime = KMimeType::findByUrl(url);
00777             QString mimeName = mime->name();
00778             QRectF geom(event->scenePos(), QSize(0, 0));
00779             QVariantList args;
00780             args << url.url();
00781             //             kDebug() << mimeName;
00782             KPluginInfo::List appletList = Applet::knownAppletsForMimetype(mimeName);
00783 
00784             if (appletList.isEmpty()) {
00785                 // no special applet associated with this mimetype, let's
00786                 addApplet("icon", args, 0, geom);
00787             } else {
00788                 //TODO: should we show a dialog here to choose which plasmoid load if
00789                 //appletList.count() > 0?
00790                 addApplet(appletList.first().pluginName(), args, 0, geom);
00791             }
00792         }
00793         event->acceptProposedAction();
00794     }
00795 }
00796 
00797 void Containment::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00798 {
00799     //FIXME Qt4.4 check to see if this is still necessary to avoid unecessary repaints
00800     //            check with QT_FLUSH_PAINT=1 and mouse through applets that accept hover,
00801     //            applets that don't and system windows
00802     if (event->spontaneous()) {
00803         Applet::hoverEnterEvent(event);
00804     }
00805     Q_UNUSED(event)
00806 }
00807 
00808 void Containment::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00809 {
00810     //FIXME Qt4.4 check to see if this is still necessary to avoid unecessary repaints
00811     //            check with QT_FLUSH_PAINT=1 and mouse through applets that accept hover,
00812     //            applets that don't and system windows
00813 //    Applet::hoverLeaveEvent(event);
00814     Q_UNUSED(event)
00815 }
00816 
00817 bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
00818 {
00819     Applet *applet = qgraphicsitem_cast<Applet*>(watched);
00820 
00821     // Otherwise we're watching something we shouldn't be...
00822     //kDebug() << "got sceneEvent";
00823     Q_ASSERT(applet!=0);
00824     if (!d->applets.contains(applet)) {
00825         return false;
00826     }
00827 
00828     switch (event->type()) {
00829     case QEvent::GraphicsSceneHoverEnter:
00830         //kDebug() << "got hoverenterEvent" << isImmutable() << " " << applet->isImmutable();
00831         if (!isImmutable() && !applet->isImmutable()) {
00832             if (d->handles.contains(applet)) {
00833                 d->handles[applet]->startFading(AppletHandle::FadeIn);
00834             } else {
00835                 //kDebug() << "generated applet handle";
00836                 //TODO: there should be a small delay on showing these. they pop up too quickly/easily
00837                 //      right now
00838                 AppletHandle *handle = new AppletHandle(this, applet);
00839                 d->handles[applet] = handle;
00840                 connect(handle, SIGNAL(disappearDone(AppletHandle*)),
00841                         this, SLOT(handleDisappeared(AppletHandle*)));
00842                 connect(applet, SIGNAL(geometryChanged()),
00843                         handle, SLOT(appletResized()));
00844             }
00845         }
00846         break;
00847     case QEvent::GraphicsSceneHoverLeave:
00848         //kDebug() << "got hoverLeaveEvent";
00849         if (d->handles.contains(applet)) {
00850             QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent *>(event);
00851             if (!d->handles[applet]->boundingRect().contains(d->handles[applet]->mapFromScene(he->scenePos()))) {
00852                 d->handles[applet]->startFading(AppletHandle::FadeOut);
00853             }
00854         }
00855     default:
00856         break;
00857     }
00858 
00859     return false;
00860 }
00861 
00862 void Containment::handleDisappeared(AppletHandle *handle)
00863 {
00864     d->handles.remove(handle->applet());
00865     handle->deleteLater();
00866 }
00867 
00868 void Containment::emitLaunchActivated()
00869 {
00870     kDebug();
00871     emit launchActivated();
00872 }
00873 
00874 Plasma::Widget * Containment::addToolBoxTool(const QString& toolName, const QString& iconName, const QString& iconText)
00875 {
00876     Plasma::Icon *tool = new Plasma::Icon(this);
00877 
00878     tool->setDrawBackground(true);
00879     tool->setIcon(KIcon(iconName));
00880     tool->setText(iconText);
00881     tool->setOrientation(Qt::Horizontal);
00882     QSizeF iconSize = tool->sizeFromIconSize(22);
00883     tool->setMinimumSize(iconSize);
00884     tool->setMaximumSize(iconSize);
00885     tool->resize(tool->sizeHint());
00886 
00887     d->createToolbox()->addTool(tool, toolName);
00888 
00889     return tool;
00890 }
00891 
00892 void Containment::enableToolBoxTool(const QString &toolname, bool enable)
00893 {
00894     d->createToolbox()->enableTool(toolname, enable);
00895 }
00896 
00897 bool Containment::isToolboxToolEnabled(const QString &toolname) const
00898 {
00899     return d->createToolbox()->isToolEnabled(toolname);
00900 }
00901 
00902 void Containment::showToolbox()
00903 {
00904     d->createToolbox()->showToolbox();
00905 }
00906 
00907 void Containment::hideToolbox()
00908 {
00909     d->createToolbox()->hideToolbox();
00910 }
00911 
00912 } // Plasma namespace
00913 
00914 #include "containment.moc"
00915 

libplasma

Skip menu "libplasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal