• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Plasma

corona.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2007 Matt Broadstone <mbroadst@gmail.com>
00003  *   Copyright 2007 Aaron Seigo <aseigo@kde.org>
00004  *   Copyright 2007 Riccardo Iaconelli <riccardo@kde.org>
00005  *   Copyright (c) 2009 Chani Armitage <chani@kde.org>
00006  *
00007  *   This program is free software; you can redistribute it and/or modify
00008  *   it under the terms of the GNU Library General Public License as
00009  *   published by the Free Software Foundation; either version 2, or
00010  *   (at your option) any later version.
00011  *
00012  *   This program is distributed in the hope that it will be useful,
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *   GNU General Public License for more details
00016  *
00017  *   You should have received a copy of the GNU Library General Public
00018  *   License along with this program; if not, write to the
00019  *   Free Software Foundation, Inc.,
00020  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00021  */
00022 
00023 #include "corona.h"
00024 
00025 #include <QApplication>
00026 #include <QDesktopWidget>
00027 #include <QGraphicsView>
00028 #include <QGraphicsSceneDragDropEvent>
00029 #include <QGraphicsGridLayout>
00030 #include <QMimeData>
00031 #include <QPainter>
00032 #include <QTimer>
00033 
00034 #include <cmath>
00035 
00036 #include <kaction.h>
00037 #include <kactioncollection.h>
00038 #include <kdebug.h>
00039 #include <kglobal.h>
00040 #include <klocale.h>
00041 #include <kmimetype.h>
00042 #include <kshortcutsdialog.h>
00043 #include <kwindowsystem.h>
00044 
00045 #include "animator.h"
00046 #include "abstracttoolbox.h"
00047 #include "containment.h"
00048 #include "containmentactionspluginsconfig.h"
00049 #include "view.h"
00050 #include "private/animator_p.h"
00051 #include "private/applet_p.h"
00052 #include "private/containment_p.h"
00053 #include "tooltipmanager.h"
00054 #include "abstractdialogmanager.h"
00055 
00056 using namespace Plasma;
00057 
00058 namespace Plasma
00059 {
00060 
00061 // constant controlling how long between requesting a configuration sync
00062 // and one happening should occur. currently 10 seconds
00063 const int CONFIG_SYNC_TIMEOUT = 10000;
00064 
00065 class CoronaPrivate
00066 {
00067 public:
00068     CoronaPrivate(Corona *corona)
00069         : q(corona),
00070           immutability(Mutable),
00071           mimetype("text/x-plasmoidservicename"),
00072           config(0),
00073           actions(corona)
00074     {
00075         if (KGlobal::hasMainComponent()) {
00076             configName = KGlobal::mainComponent().componentName() + "-appletsrc";
00077         } else {
00078             configName = "plasma-appletsrc";
00079         }
00080     }
00081 
00082     ~CoronaPrivate()
00083     {
00084         qDeleteAll(containments);
00085     }
00086 
00087     void init()
00088     {
00089         q->setStickyFocus(true);
00090         configSyncTimer.setSingleShot(true);
00091         QObject::connect(&configSyncTimer, SIGNAL(timeout()), q, SLOT(syncConfig()));
00092 
00093         //some common actions
00094         actions.setConfigGroup("Shortcuts");
00095 
00096         KAction *lockAction = actions.addAction("lock widgets");
00097         QObject::connect(lockAction, SIGNAL(triggered(bool)), q, SLOT(toggleImmutability()));
00098         lockAction->setText(i18n("Lock Widgets"));
00099         lockAction->setAutoRepeat(true);
00100         lockAction->setIcon(KIcon("object-locked"));
00101         lockAction->setData(AbstractToolBox::ControlTool);
00102         lockAction->setShortcut(KShortcut("alt+d, l"));
00103         lockAction->setShortcutContext(Qt::ApplicationShortcut);
00104 
00105         //FIXME this doesn't really belong here. desktop KCM maybe?
00106         //but should the shortcuts be per-app or really-global?
00107         //I don't know how to make kactioncollections use plasmarc
00108         KAction *action = actions.addAction("configure shortcuts");
00109         QObject::connect(action, SIGNAL(triggered()), q, SLOT(showShortcutConfig()));
00110         action->setText(i18n("Shortcut Settings"));
00111         action->setIcon(KIcon("configure-shortcuts"));
00112         action->setAutoRepeat(false);
00113         action->setData(AbstractToolBox::ConfigureTool);
00114         //action->setShortcut(KShortcut("ctrl+h"));
00115         action->setShortcutContext(Qt::ApplicationShortcut);
00116 
00117         actions.readSettings();
00118 
00119         //fake containment/applet actions
00120         KActionCollection *aActions = AppletPrivate::defaultActions(q);
00121         KActionCollection *cActions = AppletPrivate::defaultActions(q); //containment has to start with applet stuff
00122         ContainmentPrivate::addDefaultActions(cActions); //now it's really containment
00123         //grab the current stuff
00124         cActions->readSettings();
00125         aActions->readSettings();
00126 
00127         shortcutsDlg.setModal(false);
00128         shortcutsDlg.addCollection(aActions);
00129         shortcutsDlg.addCollection(cActions);
00130 
00131         QObject::connect(&shortcutsDlg, SIGNAL(saved()), q, SIGNAL(shortcutsChanged()));
00132     }
00133 
00134     void showShortcutConfig()
00135     {
00136         //show a kshortcutsdialog with the actions
00137         shortcutsDlg.configure();
00138     }
00139 
00140     void toggleImmutability()
00141     {
00142         if (immutability == Mutable) {
00143             q->setImmutability(UserImmutable);
00144         } else {
00145             q->setImmutability(Mutable);
00146         }
00147     }
00148 
00149     void saveLayout(KSharedConfigPtr cg) const
00150     {
00151         KConfigGroup containmentsGroup(cg, "Containments");
00152         foreach (const Containment *containment, containments) {
00153             QString cid = QString::number(containment->id());
00154             KConfigGroup containmentConfig(&containmentsGroup, cid);
00155             containment->save(containmentConfig);
00156         }
00157     }
00158 
00159     void updateContainmentImmutability()
00160     {
00161         foreach (Containment *c, containments) {
00162             // we need to tell each containment that immutability has been altered
00163             c->updateConstraints(ImmutableConstraint);
00164         }
00165     }
00166 
00167     void containmentDestroyed(QObject *obj)
00168     {
00169         // we do a static_cast here since it really isn't an Containment by this
00170         // point anymore since we are in the qobject dtor. we don't actually
00171         // try and do anything with it, we just need the value of the pointer
00172         // so this unsafe looking code is actually just fine.
00173         Containment* containment = static_cast<Plasma::Containment*>(obj);
00174         int index = containments.indexOf(containment);
00175 
00176         if (index > -1) {
00177             containments.removeAt(index);
00178             q->requestConfigSync();
00179         }
00180     }
00181 
00182     void syncConfig()
00183     {
00184         q->config()->sync();
00185         emit q->configSynced();
00186     }
00187 
00188     Containment *addContainment(const QString &name, const QVariantList &args,
00189                                 uint id, bool delayedInit)
00190     {
00191         QString pluginName = name;
00192         Containment *containment = 0;
00193         Applet *applet = 0;
00194 
00195         //kDebug() << "Loading" << name << args << id;
00196 
00197         if (pluginName.isEmpty() || pluginName == "default") {
00198             // default to the desktop containment
00199             pluginName = "desktop";
00200         }
00201 
00202         bool loadingNull = pluginName == "null";
00203         if (!loadingNull) {
00204             applet = Applet::load(pluginName, id, args);
00205             containment = dynamic_cast<Containment*>(applet);
00206         }
00207 
00208         if (!containment) {
00209             if (!loadingNull) {
00210                 kDebug() << "loading of containment" << name << "failed.";
00211             }
00212 
00213             // in case we got a non-Containment from Applet::loadApplet or
00214             // a null containment was requested
00215             if (applet) {
00216                 // the applet probably doesn't know what's hit it, so let's pretend it can be
00217                 // initialized to make assumptions in the applet's dtor safer
00218                 q->addItem(applet);
00219                 applet->init();
00220                 q->removeItem(applet);
00221                 delete applet;
00222             }
00223             applet = containment = new Containment(0, 0, id);
00224 
00225             if (loadingNull) {
00226                 containment->setDrawWallpaper(false);
00227             } else {
00228                 containment->setFailedToLaunch(false);
00229             }
00230 
00231             // we want to provide something and don't care about the failure to launch
00232             containment->setFormFactor(Plasma::Planar);
00233         }
00234 
00235         // if this is a new containment, we need to ensure that there are no stale
00236         // configuration data around
00237         if (id == 0) {
00238             KConfigGroup conf(q->config(), "Containments");
00239             conf = KConfigGroup(&conf, QString::number(containment->id()));
00240             conf.deleteGroup();
00241         }
00242 
00243         applet->d->isContainment = true;
00244         containment->setPos(containment->d->preferredPos(q));
00245         q->addItem(containment);
00246         applet->d->setIsContainment(true, true);
00247         containments.append(containment);
00248 
00249         if (!delayedInit) {
00250             containment->init();
00251             KConfigGroup cg = containment->config();
00252             containment->restore(cg);
00253             containment->updateConstraints(Plasma::StartupCompletedConstraint);
00254             containment->save(cg);
00255             q->requestConfigSync();
00256             containment->flushPendingConstraintsEvents();
00257         }
00258 
00259         QObject::connect(containment, SIGNAL(destroyed(QObject*)),
00260                          q, SLOT(containmentDestroyed(QObject*)));
00261         QObject::connect(containment, SIGNAL(configNeedsSaving()),
00262                          q, SLOT(requestConfigSync()));
00263         QObject::connect(containment, SIGNAL(releaseVisualFocus()),
00264                          q, SIGNAL(releaseVisualFocus()));
00265         QObject::connect(containment, SIGNAL(screenChanged(int,int,Plasma::Containment*)),
00266                          q, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)));
00267 
00268         if (!delayedInit) {
00269             emit q->containmentAdded(containment);
00270         }
00271 
00272         return containment;
00273     }
00274 
00275     void offscreenWidgetDestroyed(QObject *);
00276     QList<Plasma::Containment *> importLayout(const KConfigBase &conf, bool mergeConfig);
00277 
00278     static bool s_positioningContainments;
00279 
00280     Corona *q;
00281     ImmutabilityType immutability;
00282     QString mimetype;
00283     QString configName;
00284     KSharedConfigPtr config;
00285     QTimer configSyncTimer;
00286     QList<Containment*> containments;
00287     QHash<uint, QGraphicsWidget*> offscreenWidgets;
00288     KActionCollection actions;
00289     KShortcutsDialog shortcutsDlg;
00290     QMap<Containment::Type, ContainmentActionsPluginsConfig> containmentActionsDefaults;
00291     QWeakPointer<AbstractDialogManager>dialogManager;
00292     QHash<Containment::Type, QString> toolBoxPlugins;
00293 };
00294 
00295 bool CoronaPrivate::s_positioningContainments = false;
00296 
00297 Corona::Corona(QObject *parent)
00298     : QGraphicsScene(parent),
00299       d(new CoronaPrivate(this))
00300 {
00301     kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Corona ctor start";
00302     d->init();
00303     ToolTipManager::self()->m_corona = this;
00304     //setViewport(new QGLWidget(QGLFormat(QGL::StencilBuffer | QGL::AlphaChannel)));
00305 }
00306 
00307 Corona::~Corona()
00308 {
00309     KConfigGroup trans(KGlobal::config(), "PlasmaTransientsConfig");
00310     trans.deleteGroup();
00311 
00312     // FIXME: Same fix as in Plasma::View - make sure that when the focused widget is
00313     //        destroyed we don't try to transfer it to something that's already been
00314     //        deleted.
00315     clearFocus();
00316     delete d;
00317 }
00318 
00319 void Corona::setAppletMimeType(const QString &type)
00320 {
00321     d->mimetype = type;
00322 }
00323 
00324 QString Corona::appletMimeType()
00325 {
00326     return d->mimetype;
00327 }
00328 
00329 void Corona::saveLayout(const QString &configName) const
00330 {
00331     KSharedConfigPtr c;
00332 
00333     if (configName.isEmpty() || configName == d->configName) {
00334         c = config();
00335     } else {
00336         c = KSharedConfig::openConfig(configName);
00337     }
00338 
00339     d->saveLayout(c);
00340 }
00341 
00342 void Corona::exportLayout(KConfigGroup &config, QList<Containment*> containments)
00343 {
00344     foreach (const QString &group, config.groupList()) {
00345         KConfigGroup cg(&config, group);
00346         cg.deleteGroup();
00347     }
00348 
00349     //temporarily unlock so that removal works
00350     ImmutabilityType oldImm = immutability();
00351     d->immutability = Mutable;
00352 
00353     KConfigGroup dest(&config, "Containments");
00354     KConfigGroup dummy;
00355     foreach (Plasma::Containment *c, containments) {
00356         c->save(dummy);
00357         c->config().reparent(&dest);
00358 
00359         //ensure the containment is unlocked
00360         //this is done directly because we have to bypass any SystemImmutable checks
00361         c->Applet::d->immutability = Mutable;
00362         foreach (Applet *a, c->applets()) {
00363             a->d->immutability = Mutable;
00364         }
00365 
00366         c->destroy(false);
00367     }
00368 
00369     //restore immutability
00370     d->immutability = oldImm;
00371 
00372     config.sync();
00373 }
00374 
00375 void Corona::requestConfigSync()
00376 {
00377     // TODO: should we check into our immutability before doing this?
00378 
00379     //NOTE: this is a pretty simplistic model: we simply save no more than CONFIG_SYNC_TIMEOUT
00380     //      after the first time this is called. not much of a heuristic for save points, but
00381     //      it should at least compress these activities a bit and provide a way for applet
00382     //      authors to ween themselves from the sync() disease. A more interesting/dynamic
00383     //      algorithm for determining when to actually sync() to disk might be better, though.
00384     if (!d->configSyncTimer.isActive()) {
00385         d->configSyncTimer.start(CONFIG_SYNC_TIMEOUT);
00386     }
00387 }
00388 
00389 void Corona::requireConfigSync()
00390 {
00391     d->syncConfig();
00392 }
00393 
00394 void Corona::initializeLayout(const QString &configName)
00395 {
00396     clearContainments();
00397     loadLayout(configName);
00398 
00399     if (d->containments.isEmpty()) {
00400         loadDefaultLayout();
00401         if (!d->containments.isEmpty()) {
00402             requestConfigSync();
00403         }
00404     }
00405 
00406     if (config()->isImmutable()) {
00407         setImmutability(SystemImmutable);
00408     } else {
00409         KConfigGroup coronaConfig(config(), "General");
00410         setImmutability((ImmutabilityType)coronaConfig.readEntry("immutability", (int)Mutable));
00411     }
00412 }
00413 
00414 bool containmentSortByPosition(const Containment *c1, const Containment *c2)
00415 {
00416     return c1->id() < c2->id();
00417 }
00418 
00419 void Corona::layoutContainments()
00420 {
00421     if (CoronaPrivate::s_positioningContainments) {
00422         return;
00423     }
00424 
00425     CoronaPrivate::s_positioningContainments = true;
00426 
00427     //TODO: we should avoid running this too often; consider compressing requests
00428     //      with a timer.
00429     QList<Containment*> c = containments();
00430     QMutableListIterator<Containment*> it(c);
00431 
00432     while (it.hasNext()) {
00433         Containment *containment = it.next();
00434         if (containment->containmentType() == Containment::PanelContainment ||
00435             containment->containmentType() == Containment::CustomPanelContainment ||
00436             offscreenWidgets().contains(containment)) {
00437             // weed out all containments we don't care about at all
00438             // e.g. Panels and ourself
00439             it.remove();
00440             continue;
00441         }
00442     }
00443 
00444     qSort(c.begin(), c.end(), containmentSortByPosition);
00445 
00446     if (c.isEmpty()) {
00447         CoronaPrivate::s_positioningContainments = false;
00448         return;
00449     }
00450 
00451     int column = 0;
00452     int x = 0;
00453     int y = 0;
00454     int rowHeight = 0;
00455 
00456     it.toFront();
00457     while (it.hasNext()) {
00458         Containment *containment = it.next();
00459         containment->setPos(x, y);
00460         //kDebug() << ++count << "setting to" << x << y;
00461 
00462         int height = containment->size().height();
00463         if (height > rowHeight) {
00464             rowHeight = height;
00465         }
00466 
00467         ++column;
00468 
00469         if (column == CONTAINMENT_COLUMNS) {
00470             column = 0;
00471             x = 0;
00472             y += rowHeight + INTER_CONTAINMENT_MARGIN + TOOLBOX_MARGIN;
00473             rowHeight = 0;
00474         } else {
00475             x += containment->size().width() + INTER_CONTAINMENT_MARGIN;
00476         }
00477         //kDebug() << "column: " << column << "; x " << x << "; y" << y << "; width was"
00478         //         << containment->size().width();
00479     }
00480 
00481     CoronaPrivate::s_positioningContainments = false;
00482 }
00483 
00484 
00485 void Corona::loadLayout(const QString &configName)
00486 {
00487     if (!configName.isEmpty() && configName != d->configName) {
00488         // if we have a new config name passed in, then use that as the config file for this Corona
00489         d->config = 0;
00490         d->configName = configName;
00491     }
00492 
00493     KSharedConfigPtr conf = config();
00494     d->importLayout(*conf, false);
00495 }
00496 
00497 QList<Plasma::Containment *> Corona::importLayout(const KConfigGroup &conf)
00498 {
00499     return d->importLayout(conf, true);
00500 }
00501 
00502 #ifndef KDE_NO_DEPRECATED
00503 QList<Plasma::Containment *> Corona::importLayout(const KConfigBase &conf)
00504 {
00505     return d->importLayout(conf, true);
00506 }
00507 #endif
00508 
00509 QList<Plasma::Containment *> CoronaPrivate::importLayout(const KConfigBase &conf, bool mergeConfig)
00510 {
00511     if (const KConfigGroup *group = dynamic_cast<const KConfigGroup *>(&conf)) {
00512         if (!group->isValid()) {
00513             return QList<Containment *>();
00514         }
00515     }
00516 
00517     QList<Plasma::Containment *> newContainments;
00518     QSet<uint> containmentsIds;
00519 
00520     foreach (Containment *containment, containments) {
00521         containmentsIds.insert(containment->id());
00522     }
00523 
00524     KConfigGroup containmentsGroup(&conf, "Containments");
00525 
00526     foreach (const QString &group, containmentsGroup.groupList()) {
00527         KConfigGroup containmentConfig(&containmentsGroup, group);
00528 
00529         if (containmentConfig.entryMap().isEmpty()) {
00530             continue;
00531         }
00532 
00533         uint cid = group.toUInt();
00534         if (containmentsIds.contains(cid)) {
00535             cid = ++AppletPrivate::s_maxAppletId;
00536         } else if (cid > AppletPrivate::s_maxAppletId) {
00537             AppletPrivate::s_maxAppletId = cid;
00538         }
00539 
00540         if (mergeConfig) {
00541             KConfigGroup realConf(q->config(), "Containments");
00542             realConf = KConfigGroup(&realConf, QString::number(cid));
00543             // in case something was there before us
00544             realConf.deleteGroup();
00545             containmentConfig.copyTo(&realConf);
00546         }
00547 
00548         //kDebug() << "got a containment in the config, trying to make a" << containmentConfig.readEntry("plugin", QString()) << "from" << group;
00549         kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Adding Containment" << containmentConfig.readEntry("plugin", QString());
00550         Containment *c = addContainment(containmentConfig.readEntry("plugin", QString()), QVariantList(), cid, true);
00551         if (!c) {
00552             continue;
00553         }
00554 
00555         newContainments.append(c);
00556         containmentsIds.insert(c->id());
00557 
00558         c->init();
00559         kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Init Containment" << c->pluginName();
00560         c->restore(containmentConfig);
00561         kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Restored Containment" << c->pluginName();
00562     }
00563 
00564     foreach (Containment *containment, newContainments) {
00565         containment->updateConstraints(Plasma::StartupCompletedConstraint);
00566         containment->d->initApplets();
00567         emit q->containmentAdded(containment);
00568         kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Containment" << containment->name();
00569     }
00570 
00571     return newContainments;
00572 }
00573 
00574 Containment *Corona::containmentForScreen(int screen, int desktop) const
00575 {
00576     foreach (Containment *containment, d->containments) {
00577         if (containment->screen() == screen &&
00578             (desktop < 0 || containment->desktop() == desktop) &&
00579             (containment->containmentType() == Containment::DesktopContainment ||
00580              containment->containmentType() == Containment::CustomContainment)) {
00581             return containment;
00582         }
00583     }
00584 
00585     return 0;
00586 }
00587 
00588 Containment *Corona::containmentForScreen(int screen, int desktop,
00589                                           const QString &defaultPluginIfNonExistent, const QVariantList &defaultArgs)
00590 {
00591     Containment *containment = containmentForScreen(screen, desktop);
00592     if (!containment && !defaultPluginIfNonExistent.isEmpty()) {
00593         // screen requests are allowed to bypass immutability
00594         if (screen >= 0 && screen < numScreens() &&
00595             desktop >= -1 && desktop < KWindowSystem::numberOfDesktops()) {
00596             containment = d->addContainment(defaultPluginIfNonExistent, defaultArgs, 0, false);
00597             if (containment) {
00598                 containment->setScreen(screen, desktop);
00599             }
00600         }
00601     }
00602 
00603     return containment;
00604 }
00605 QList<Containment*> Corona::containments() const
00606 {
00607     return d->containments;
00608 }
00609 
00610 void Corona::clearContainments()
00611 {
00612     foreach (Containment *containment, d->containments) {
00613         containment->clearApplets();
00614     }
00615 }
00616 
00617 KSharedConfigPtr Corona::config() const
00618 {
00619     if (!d->config) {
00620         d->config = KSharedConfig::openConfig(d->configName);
00621     }
00622 
00623     return d->config;
00624 }
00625 
00626 Containment *Corona::addContainment(const QString &name, const QVariantList &args)
00627 {
00628     if (d->immutability == Mutable) {
00629         return d->addContainment(name, args, 0, false);
00630     }
00631 
00632     return 0;
00633 }
00634 
00635 Containment *Corona::addContainmentDelayed(const QString &name, const QVariantList &args)
00636 {
00637     if (d->immutability == Mutable) {
00638         return d->addContainment(name, args, 0, true);
00639     }
00640 
00641     return 0;
00642 }
00643 
00644 void Corona::mapAnimation(Animator::Animation from, Animator::Animation to)
00645 {
00646     AnimatorPrivate::mapAnimation(from, to);
00647 }
00648 
00649 void Corona::mapAnimation(Animator::Animation from, const QString &to)
00650 {
00651     AnimatorPrivate::mapAnimation(from, to);
00652 }
00653 
00654 void Corona::addOffscreenWidget(QGraphicsWidget *widget)
00655 {
00656     foreach (QGraphicsWidget *w, d->offscreenWidgets) {
00657         if (w == widget) {
00658             kDebug() << "widget is already an offscreen widget!";
00659             return;
00660         }
00661     }
00662 
00663     //search for an empty spot in the topleft quadrant of the scene. each 'slot' is QWIDGETSIZE_MAX
00664     //x QWIDGETSIZE_MAX, so we're guaranteed to never have to move widgets once they're placed here.
00665     int i = 0;
00666     while (d->offscreenWidgets.contains(i)) {
00667         i++;
00668     }
00669 
00670     d->offscreenWidgets[i] = widget;
00671     widget->setPos((-i - 1) * QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
00672 
00673     QGraphicsWidget *pw = widget->parentWidget();
00674     widget->setParentItem(0);
00675     widget->setParent(pw);
00676 
00677     //kDebug() << "adding offscreen widget at slot " << i;
00678     if (!widget->scene()) {
00679         addItem(widget);
00680     }
00681 
00682     connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(offscreenWidgetDestroyed(QObject*)));
00683 }
00684 
00685 void Corona::removeOffscreenWidget(QGraphicsWidget *widget)
00686 {
00687     QMutableHashIterator<uint, QGraphicsWidget *> it(d->offscreenWidgets);
00688 
00689     while (it.hasNext()) {
00690         if (it.next().value() == widget) {
00691             it.remove();
00692             return;
00693         }
00694     }
00695 }
00696 
00697 QList <QGraphicsWidget *> Corona::offscreenWidgets() const
00698 {
00699     return d->offscreenWidgets.values();
00700 }
00701 
00702 void CoronaPrivate::offscreenWidgetDestroyed(QObject *o)
00703 {
00704     // at this point, it's just a QObject, not a QGraphicsWidget, but we still need
00705     // a pointer of the appropriate type.
00706     // WARNING: DO NOT USE THE WIDGET POINTER FOR ANYTHING OTHER THAN POINTER COMPARISONS
00707     QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(o);
00708     q->removeOffscreenWidget(widget);
00709 }
00710 
00711 int Corona::numScreens() const
00712 {
00713     return 1;
00714 }
00715 
00716 QRect Corona::screenGeometry(int id) const
00717 {
00718     Q_UNUSED(id);
00719     if (views().isEmpty()) {
00720         return sceneRect().toRect();
00721     } else {
00722         QGraphicsView *v = views()[0];
00723         QRect r = sceneRect().toRect();
00724         r.moveTo(v->mapToGlobal(QPoint(0, 0)));
00725         return r;
00726     }
00727 }
00728 
00729 QRegion Corona::availableScreenRegion(int id) const
00730 {
00731     return QRegion(screenGeometry(id));
00732 }
00733 
00734 QPoint Corona::popupPosition(const QGraphicsItem *item, const QSize &s)
00735 {
00736     return popupPosition(item, s, Qt::AlignLeft);
00737 }
00738 
00739 QPoint Corona::popupPosition(const QGraphicsItem *item, const QSize &s, Qt::AlignmentFlag alignment)
00740 {
00741     // TODO: merge both methods (also these in Applet) into one (with optional alignment) when we can break compatibility
00742     // TODO: add support for more flags in the future?
00743 
00744     QGraphicsView *v = viewFor(item);
00745 
00746     if (!v) {
00747         return QPoint(0, 0);
00748     }
00749 
00750     QPoint pos;
00751     QTransform sceneTransform = item->sceneTransform();
00752 
00753     //swap direction if necessary
00754     if (QApplication::isRightToLeft() && alignment != Qt::AlignCenter) {
00755         if (alignment == Qt::AlignRight) {
00756             alignment = Qt::AlignLeft;
00757         } else {
00758             alignment = Qt::AlignRight;
00759         }
00760     }
00761 
00762     //if the applet is rotated the popup position has to be un-transformed
00763     if (sceneTransform.isRotating()) {
00764         qreal angle = acos(sceneTransform.m11());
00765         QTransform newTransform;
00766         QPointF center = item->sceneBoundingRect().center();
00767 
00768         newTransform.translate(center.x(), center.y());
00769         newTransform.rotateRadians(-angle);
00770         newTransform.translate(-center.x(), -center.y());
00771         pos = v->mapFromScene(newTransform.inverted().map(item->scenePos()));
00772     } else {
00773         pos = v->mapFromScene(item->scenePos());
00774     }
00775 
00776     pos = v->mapToGlobal(pos);
00777     //kDebug() << "==> position is" << item->scenePos() << v->mapFromScene(item->scenePos()) << pos;
00778     Plasma::View *pv = dynamic_cast<Plasma::View *>(v);
00779 
00780     Plasma::Location loc = Floating;
00781     if (pv && pv->containment()) {
00782         loc = pv->containment()->location();
00783     }
00784 
00785     switch (loc) {
00786     case BottomEdge:
00787     case TopEdge: {
00788         if (alignment == Qt::AlignCenter) {
00789             pos.setX(pos.x() + item->boundingRect().width()/2 - s.width()/2);
00790         } else if (alignment == Qt::AlignRight) {
00791             pos.setX(pos.x() + item->boundingRect().width() - s.width());
00792         }
00793 
00794         if (pos.x() + s.width() > v->geometry().right()) {
00795             pos.setX(v->geometry().right() - s.width());
00796         } else {
00797             pos.setX(qMax(pos.x(), v->geometry().left()));
00798         }
00799         break;
00800     }
00801     case LeftEdge:
00802     case RightEdge: {
00803         if (alignment == Qt::AlignCenter) {
00804             pos.setY(pos.y() + item->boundingRect().height()/2 - s.height()/2);
00805         } else if (alignment == Qt::AlignRight) {
00806             pos.setY(pos.y() + item->boundingRect().height() - s.height());
00807         }
00808 
00809         if (pos.y() + s.height() > v->geometry().bottom()) {
00810             pos.setY(v->geometry().bottom() - s.height());
00811         } else {
00812             pos.setY(qMax(pos.y(), v->geometry().top()));
00813         }
00814         break;
00815     }
00816     default:
00817         if (alignment == Qt::AlignCenter) {
00818             pos.setX(pos.x() + item->boundingRect().width()/2 - s.width()/2);
00819         } else if (alignment == Qt::AlignRight) {
00820             pos.setX(pos.x() + item->boundingRect().width() - s.width());
00821         }
00822         break;
00823     }
00824 
00825     switch (loc) {
00826     case BottomEdge:
00827         pos.setY(v->geometry().y() - s.height());
00828         break;
00829     case TopEdge:
00830         pos.setY(v->geometry().bottom());
00831         break;
00832     case LeftEdge:
00833         pos.setX(v->geometry().right());
00834         break;
00835     case RightEdge:
00836         pos.setX(v->geometry().x() - s.width());
00837         break;
00838     default:
00839         if (pos.y() - s.height() > 0) {
00840              pos.ry() = pos.y() - s.height();
00841         } else {
00842              pos.ry() = pos.y() + (int)item->boundingRect().size().height() + 1;
00843         }
00844     }
00845 
00846     //are we out of screen?
00847     int screen = ((pv && pv->containment()) ? pv->containment()->screen() : -1);
00848     if (screen == -1) {
00849         if (pv) {
00850             screen = pv->screen();
00851         } else {
00852             // fall back to asking the actual system what screen the view is on
00853             // in the case we are dealing with a non-PlasmaView QGraphicsView
00854             screen = QApplication::desktop()->screenNumber(v);
00855         }
00856     }
00857 
00858     QRect screenRect = screenGeometry(screen);
00859     //kDebug() << "==> rect for" << screen << "is" << screenRect;
00860 
00861     if (loc != LeftEdge && pos.x() + s.width() > screenRect.right()) {
00862         pos.rx() -= ((pos.x() + s.width()) - screenRect.right());
00863     }
00864 
00865     if (loc != TopEdge && pos.y() + s.height() > screenRect.bottom()) {
00866         pos.ry() -= ((pos.y() + s.height()) - screenRect.bottom());
00867     }
00868 
00869     pos.rx() = qMax(0, pos.x());
00870     return pos;
00871 }
00872 
00873 void Corona::loadDefaultLayout()
00874 {
00875 }
00876 
00877 void Corona::setPreferredToolBoxPlugin(const Containment::Type type, const QString &plugin)
00878 {
00879     d->toolBoxPlugins[type] = plugin;
00880     //TODO: react to plugin changes on the fly? still don't see the use case (maybe for laptops that become tablets?)
00881 }
00882 
00883 QString Corona::preferredToolBoxPlugin(const Containment::Type type) const
00884 {
00885     return d->toolBoxPlugins.value(type);
00886 }
00887 
00888 void Corona::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
00889 {
00890     QGraphicsScene::dragEnterEvent(event);
00891 }
00892 
00893 void Corona::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
00894 {
00895     QGraphicsScene::dragLeaveEvent(event);
00896 }
00897 
00898 void Corona::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
00899 {
00900     QGraphicsScene::dragMoveEvent(event);
00901 }
00902 
00903 ImmutabilityType Corona::immutability() const
00904 {
00905     return d->immutability;
00906 }
00907 
00908 void Corona::setImmutability(const ImmutabilityType immutable)
00909 {
00910     if (d->immutability == immutable || d->immutability == SystemImmutable) {
00911         return;
00912     }
00913 
00914     kDebug() << "setting immutability to" << immutable;
00915     d->immutability = immutable;
00916     d->updateContainmentImmutability();
00917     //tell non-containments that might care (like plasmaapp or a custom corona)
00918     emit immutabilityChanged(immutable);
00919 
00920     //update our actions
00921     QAction *action = d->actions.action("lock widgets");
00922     if (action) {
00923         if (d->immutability == SystemImmutable) {
00924             action->setEnabled(false);
00925             action->setVisible(false);
00926         } else {
00927             bool unlocked = d->immutability == Mutable;
00928             action->setText(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets"));
00929             action->setIcon(KIcon(unlocked ? "object-locked" : "object-unlocked"));
00930             action->setEnabled(true);
00931             action->setVisible(true);
00932         }
00933     }
00934 
00935     if (d->immutability != SystemImmutable) {
00936         KConfigGroup cg(config(), "General");
00937 
00938         // we call the dptr member directly for locked since isImmutable()
00939         // also checks kiosk and parent containers
00940         cg.writeEntry("immutability", (int)d->immutability);
00941         requestConfigSync();
00942     }
00943 }
00944 
00945 QList<Plasma::Location> Corona::freeEdges(int screen) const
00946 {
00947     QList<Plasma::Location> freeEdges;
00948     freeEdges << Plasma::TopEdge << Plasma::BottomEdge
00949               << Plasma::LeftEdge << Plasma::RightEdge;
00950 
00951     foreach (Containment *containment, containments()) {
00952         if (containment->screen() == screen &&
00953             freeEdges.contains(containment->location())) {
00954             freeEdges.removeAll(containment->location());
00955         }
00956     }
00957 
00958     return freeEdges;
00959 }
00960 
00961 QAction *Corona::action(QString name) const
00962 {
00963     return d->actions.action(name);
00964 }
00965 
00966 void Corona::addAction(QString name, QAction *action)
00967 {
00968     d->actions.addAction(name, action);
00969 }
00970 
00971 KAction* Corona::addAction(QString name)
00972 {
00973     return d->actions.addAction(name);
00974 }
00975 
00976 QList<QAction*> Corona::actions() const
00977 {
00978     return d->actions.actions();
00979 }
00980 
00981 void Corona::enableAction(const QString &name, bool enable)
00982 {
00983     QAction *action = d->actions.action(name);
00984     if (action) {
00985         action->setEnabled(enable);
00986         action->setVisible(enable);
00987     }
00988 }
00989 
00990 void Corona::updateShortcuts()
00991 {
00992     d->actions.readSettings();
00993     d->shortcutsDlg.addCollection(&d->actions);
00994 }
00995 
00996 void Corona::addShortcuts(KActionCollection *newShortcuts)
00997 {
00998     d->shortcutsDlg.addCollection(newShortcuts);
00999 }
01000 
01001 void Corona::setContainmentActionsDefaults(Containment::Type containmentType, const ContainmentActionsPluginsConfig &config)
01002 {
01003     d->containmentActionsDefaults.insert(containmentType, config);
01004 }
01005 
01006 ContainmentActionsPluginsConfig Corona::containmentActionsDefaults(Containment::Type containmentType)
01007 {
01008     return d->containmentActionsDefaults.value(containmentType);
01009 }
01010 
01011 void Corona::setDialogManager(AbstractDialogManager *dialogManager)
01012 {
01013     d->dialogManager = dialogManager;
01014 }
01015 
01016 AbstractDialogManager *Corona::dialogManager()
01017 {
01018     return d->dialogManager.data();
01019 }
01020 
01021 } // namespace Plasma
01022 
01023 #include "corona.moc"
01024 

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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