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

Plasma

applet.cpp
Go to the documentation of this file.
00001 /*
00002  *   Copyright 2005 by Aaron Seigo <aseigo@kde.org>
00003  *   Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
00004  *   Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
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 "applet.h"
00024 #include "private/applet_p.h"
00025 
00026 #include "config-plasma.h"
00027 
00028 #include <plasma/animations/animation.h>
00029 
00030 #include <cmath>
00031 #include <limits>
00032 
00033 #include <QApplication>
00034 #include <QEvent>
00035 #include <QFile>
00036 #include <QGraphicsGridLayout>
00037 #include <QGraphicsSceneMouseEvent>
00038 #include <QGraphicsView>
00039 #include <QHostInfo>
00040 #include <QLabel>
00041 #include <QList>
00042 #include <QGraphicsLinearLayout>
00043 #include <QPainter>
00044 #include <QRegExp>
00045 #include <QSize>
00046 #include <QStyleOptionGraphicsItem>
00047 #include <QTextDocument>
00048 #include <QUiLoader>
00049 #include <QVBoxLayout>
00050 #include <QWidget>
00051 
00052 #include <kaction.h>
00053 #include <kactioncollection.h>
00054 #include <kauthorized.h>
00055 #include <kcolorscheme.h>
00056 #include <kdialog.h>
00057 #include <kdesktopfile.h>
00058 #include <kicon.h>
00059 #include <kiconloader.h>
00060 #include <kkeysequencewidget.h>
00061 #include <kplugininfo.h>
00062 #include <kstandarddirs.h>
00063 #include <kservice.h>
00064 #include <kservicetypetrader.h>
00065 #include <kshortcut.h>
00066 #include <kwindowsystem.h>
00067 #include <kpushbutton.h>
00068 
00069 #ifndef PLASMA_NO_KUTILS
00070 #include <kcmoduleinfo.h>
00071 #include <kcmoduleproxy.h>
00072 #else
00073 #include <kcmodule.h>
00074 #endif
00075 
00076 #ifndef PLASMA_NO_SOLID
00077 #include <solid/powermanagement.h>
00078 #endif
00079 
00080 #include "abstracttoolbox.h"
00081 #include "authorizationmanager.h"
00082 #include "authorizationrule.h"
00083 #include "configloader.h"
00084 #include "containment.h"
00085 #include "corona.h"
00086 #include "dataenginemanager.h"
00087 #include "dialog.h"
00088 #include "extenders/extender.h"
00089 #include "extenders/extenderitem.h"
00090 #include "package.h"
00091 #include "plasma.h"
00092 #include "scripting/appletscript.h"
00093 #include "svg.h"
00094 #include "framesvg.h"
00095 #include "popupapplet.h"
00096 #include "private/applethandle_p.h"
00097 #include "private/extenderitem_p.h"
00098 #include "private/framesvg_p.h"
00099 #include "theme.h"
00100 #include "view.h"
00101 #include "widgets/iconwidget.h"
00102 #include "widgets/label.h"
00103 #include "widgets/pushbutton.h"
00104 #include "widgets/busywidget.h"
00105 #include "tooltipmanager.h"
00106 #include "wallpaper.h"
00107 #include "paintutils.h"
00108 #include "abstractdialogmanager.h"
00109 #include "pluginloader.h"
00110 
00111 #include "private/associatedapplicationmanager_p.h"
00112 #include "private/authorizationmanager_p.h"
00113 #include "private/containment_p.h"
00114 #include "private/extenderapplet_p.h"
00115 #include "private/package_p.h"
00116 #include "private/packages_p.h"
00117 #include "private/plasmoidservice_p.h"
00118 #include "private/popupapplet_p.h"
00119 #include "private/remotedataengine_p.h"
00120 #include "private/service_p.h"
00121 #include "ui_publish.h"
00122 
00123 
00124 namespace Plasma
00125 {
00126 
00127 Applet::Applet(const KPluginInfo &info, QGraphicsItem *parent, uint appletId)
00128     :  QGraphicsWidget(parent),
00129        d(new AppletPrivate(KService::Ptr(), &info, appletId, this))
00130 {
00131     // WARNING: do not access config() OR globalConfig() in this method!
00132     //          that requires a scene, which is not available at this point
00133     d->init();
00134 }
00135 
00136 Applet::Applet(QGraphicsItem *parent, const QString &serviceID, uint appletId)
00137     :  QGraphicsWidget(parent),
00138        d(new AppletPrivate(KService::serviceByStorageId(serviceID), 0, appletId, this))
00139 {
00140     // WARNING: do not access config() OR globalConfig() in this method!
00141     //          that requires a scene, which is not available at this point
00142     d->init();
00143 }
00144 
00145 Applet::Applet(QGraphicsItem *parent,
00146                const QString &serviceID,
00147                uint appletId,
00148                const QVariantList &args)
00149     :  QGraphicsWidget(parent),
00150        d(new AppletPrivate(KService::serviceByStorageId(serviceID), 0, appletId, this))
00151 {
00152     // WARNING: do not access config() OR globalConfig() in this method!
00153     //          that requires a scene, which is not available at this point
00154 
00155     QVariantList &mutableArgs = const_cast<QVariantList &>(args);
00156     if (!mutableArgs.isEmpty()) {
00157         mutableArgs.removeFirst();
00158 
00159         if (!mutableArgs.isEmpty()) {
00160             mutableArgs.removeFirst();
00161         }
00162     }
00163 
00164     d->args = mutableArgs;
00165 
00166     d->init();
00167 }
00168 
00169 Applet::Applet(QObject *parentObject, const QVariantList &args)
00170     :  QGraphicsWidget(0),
00171        d(new AppletPrivate(
00172              KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()), 0,
00173              args.count() > 1 ? args[1].toInt() : 0, this))
00174 {
00175     // now remove those first two items since those are managed by Applet and subclasses shouldn't
00176     // need to worry about them. yes, it violates the constness of this var, but it lets us add
00177     // or remove items later while applets can just pretend that their args always start at 0
00178     QVariantList &mutableArgs = const_cast<QVariantList &>(args);
00179     if (!mutableArgs.isEmpty()) {
00180         mutableArgs.removeFirst();
00181 
00182         if (!mutableArgs.isEmpty()) {
00183             mutableArgs.removeFirst();
00184         }
00185     }
00186 
00187     d->args = mutableArgs;
00188 
00189     setParent(parentObject);
00190 
00191     // WARNING: do not access config() OR globalConfig() in this method!
00192     //          that requires a scene, which is not available at this point
00193     d->init();
00194 
00195     // the brain damage seen in the initialization list is due to the
00196     // inflexibility of KService::createInstance
00197 }
00198 
00199 Applet::Applet(const QString &packagePath, uint appletId, const QVariantList &args)
00200     : QGraphicsWidget(0),
00201       d(new AppletPrivate(KService::Ptr(new KService(packagePath + "/metadata.desktop")), 0, appletId, this))
00202 {
00203     Q_UNUSED(args) // FIXME?
00204     d->init(packagePath);
00205 }
00206 
00207 Applet::~Applet()
00208 {
00209     //let people know that i will die
00210     emit appletDestroyed(this);
00211 
00212     if (!d->transient && d->extender) {
00213         //This would probably be nicer if it was located in extender. But in it's dtor, this won't
00214         //work since when that get's called, the applet's config() isn't accessible anymore. (same
00215         //problem with calling saveState(). Doing this in saveState() might be a possibility, but
00216         //that would require every extender savestate implementation to call it's parent function,
00217         //which isn't very nice.
00218         d->extender.data()->saveState();
00219 
00220         foreach (ExtenderItem *item, d->extender.data()->attachedItems()) {
00221             if (item->autoExpireDelay()) {
00222                 //destroy temporary extender items, or items that aren't detached, so their
00223                 //configuration won't linger after a plasma restart.
00224                 item->destroy();
00225             }
00226         }
00227     }
00228 
00229     // clean up our config dialog, if any
00230     delete KConfigDialog::exists(d->configDialogId());
00231     delete d;
00232 }
00233 
00234 PackageStructure::Ptr Applet::packageStructure()
00235 {
00236     if (!AppletPrivate::packageStructure) {
00237         AppletPrivate::packageStructure = new PlasmoidPackage();
00238     }
00239 
00240     return AppletPrivate::packageStructure;
00241 }
00242 
00243 void Applet::init()
00244 {
00245     setFlag(ItemIsMovable, true);
00246     if (d->script) {
00247         d->setupScriptSupport();
00248 
00249         if (!d->script->init() && !d->failed) {
00250             setFailedToLaunch(true, i18n("Script initialization failed"));
00251         }
00252     }
00253 }
00254 
00255 uint Applet::id() const
00256 {
00257     return d->appletId;
00258 }
00259 
00260 void Applet::save(KConfigGroup &g) const
00261 {
00262     if (d->transient) {
00263         return;
00264     }
00265 
00266     KConfigGroup group = g;
00267     if (!group.isValid()) {
00268         group = *d->mainConfigGroup();
00269     }
00270 
00271     //kDebug() << "saving" << pluginName() << "to" << group.name();
00272     // we call the dptr member directly for locked since isImmutable()
00273     // also checks kiosk and parent containers
00274     group.writeEntry("immutability", (int)d->immutability);
00275     group.writeEntry("plugin", pluginName());
00276 
00277     group.writeEntry("geometry", geometry());
00278     group.writeEntry("zvalue", zValue());
00279 
00280     if (!d->started) {
00281         return;
00282     }
00283 
00284     //FIXME: for containments, we need to have some special values here w/regards to
00285     //       screen affinity (e.g. "bottom of screen 0")
00286     //kDebug() << pluginName() << "geometry is" << geometry()
00287     //         << "pos is" << pos() << "bounding rect is" << boundingRect();
00288     if (transform() == QTransform()) {
00289         group.deleteEntry("transform");
00290     } else {
00291         QList<qreal> m;
00292         QTransform t = transform();
00293         m << t.m11() << t.m12() << t.m13() << t.m21() << t.m22() << t.m23() << t.m31() << t.m32() << t.m33();
00294         group.writeEntry("transform", m);
00295         //group.writeEntry("transform", transformToString(transform()));
00296     }
00297 
00298     KConfigGroup appletConfigGroup(&group, "Configuration");
00299     saveState(appletConfigGroup);
00300 
00301     if (d->configLoader) {
00302         // we're saving so we know its changed, we don't need or want the configChanged
00303         // signal bubbling up at this point due to that
00304         disconnect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
00305         d->configLoader->writeConfig();
00306         connect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
00307     }
00308 }
00309 
00310 void Applet::restore(KConfigGroup &group)
00311 {
00312     QList<qreal> m = group.readEntry("transform", QList<qreal>());
00313     if (m.count() == 9) {
00314         QTransform t(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
00315         setTransform(t);
00316     }
00317 
00318     qreal z = group.readEntry("zvalue", 0);
00319 
00320     if (z >= AppletPrivate::s_maxZValue) {
00321         AppletPrivate::s_maxZValue = z;
00322     }
00323 
00324     if (z > 0) {
00325         setZValue(z);
00326     }
00327 
00328     setImmutability((ImmutabilityType)group.readEntry("immutability", (int)Mutable));
00329 
00330     QRectF geom = group.readEntry("geometry", QRectF());
00331     if (geom.isValid()) {
00332         setGeometry(geom);
00333     }
00334 
00335     KConfigGroup shortcutConfig(&group, "Shortcuts");
00336     QString shortcutText = shortcutConfig.readEntryUntranslated("global", QString());
00337     if (!shortcutText.isEmpty()) {
00338         setGlobalShortcut(KShortcut(shortcutText));
00339         /*
00340         kDebug() << "got global shortcut for" << name() << "of" << QKeySequence(shortcutText);
00341         kDebug() << "set to" << d->activationAction->objectName()
00342                  << d->activationAction->globalShortcut().primary();
00343                  */
00344     }
00345 
00346     // local shortcut, if any
00347     //TODO: implement; the shortcut will need to be registered with the containment
00348     /*
00349 #include "accessmanager.h"
00350 #include "private/plasmoidservice_p.h"
00351 #include "authorizationmanager.h"
00352 #include "authorizationmanager.h"
00353     shortcutText = shortcutConfig.readEntryUntranslated("local", QString());
00354     if (!shortcutText.isEmpty()) {
00355         //TODO: implement; the shortcut
00356     }
00357     */
00358 }
00359 
00360 void AppletPrivate::setFocus()
00361 {
00362     //kDebug() << "setting focus";
00363     q->setFocus(Qt::ShortcutFocusReason);
00364 }
00365 
00366 void Applet::setFailedToLaunch(bool failed, const QString &reason)
00367 {
00368     if (d->failed == failed) {
00369         if (failed && !reason.isEmpty()) {
00370             foreach (QGraphicsItem *item, QGraphicsItem::children()) {
00371                 Label *l = dynamic_cast<Label *>(item);
00372                 if (l) {
00373                     l->setText(d->visibleFailureText(reason));
00374                 }
00375             }
00376         }
00377         return;
00378     }
00379 
00380     d->failed = failed;
00381     prepareGeometryChange();
00382 
00383     foreach (QGraphicsItem *item, childItems()) {
00384         if (!dynamic_cast<AppletHandle *>(item)) {
00385             delete item;
00386         }
00387     }
00388 
00389     d->messageOverlay = 0;
00390     if (d->messageDialog) {
00391         d->messageDialog.data()->deleteLater();
00392         d->messageDialog.clear();
00393     }
00394 
00395     setLayout(0);
00396 
00397     if (failed) {
00398         setBackgroundHints(d->backgroundHints|StandardBackground);
00399 
00400         QGraphicsLinearLayout *failureLayout = new QGraphicsLinearLayout(this);
00401         failureLayout->setContentsMargins(0, 0, 0, 0);
00402 
00403         IconWidget *failureIcon = new IconWidget(this);
00404         failureIcon->setIcon(KIcon("dialog-error"));
00405         failureLayout->addItem(failureIcon);
00406 
00407         Label *failureWidget = new Plasma::Label(this);
00408         failureWidget->setText(d->visibleFailureText(reason));
00409         QLabel *label = failureWidget->nativeWidget();
00410         label->setWordWrap(true);
00411         failureLayout->addItem(failureWidget);
00412 
00413         Plasma::ToolTipManager::self()->registerWidget(failureIcon);
00414         Plasma::ToolTipContent data(i18n("Unable to load the widget"), reason,
00415                                     KIcon("dialog-error"));
00416         Plasma::ToolTipManager::self()->setContent(failureIcon, data);
00417 
00418         setLayout(failureLayout);
00419         resize(300, 250);
00420         d->background->resizeFrame(geometry().size());
00421     }
00422 
00423     update();
00424 }
00425 
00426 void Applet::saveState(KConfigGroup &group) const
00427 {
00428     if (d->script) {
00429         emit d->script->saveState(group);
00430     }
00431 
00432     if (group.config()->name() != config().config()->name()) {
00433         // we're being saved to a different file!
00434         // let's just copy the current values in our configuration over
00435         KConfigGroup c = config();
00436         c.copyTo(&group);
00437     }
00438 }
00439 
00440 KConfigGroup Applet::config(const QString &group) const
00441 {
00442     if (d->transient) {
00443         return KConfigGroup(KGlobal::config(), "PlasmaTransientsConfig");
00444     }
00445 
00446     KConfigGroup cg = config();
00447     return KConfigGroup(&cg, group);
00448 }
00449 
00450 KConfigGroup Applet::config() const
00451 {
00452     if (d->transient) {
00453         return KConfigGroup(KGlobal::config(), "PlasmaTransientsConfig");
00454     }
00455 
00456     if (d->isContainment) {
00457         return *(d->mainConfigGroup());
00458     }
00459 
00460     return KConfigGroup(d->mainConfigGroup(), "Configuration");
00461 }
00462 
00463 KConfigGroup Applet::globalConfig() const
00464 {
00465     KConfigGroup globalAppletConfig;
00466     QString group = isContainment() ? "ContainmentGlobals" : "AppletGlobals";
00467 
00468     Corona *corona = qobject_cast<Corona*>(scene());
00469     if (corona) {
00470         KSharedConfig::Ptr coronaConfig = corona->config();
00471         globalAppletConfig = KConfigGroup(coronaConfig, group);
00472     } else {
00473         globalAppletConfig = KConfigGroup(KGlobal::config(), group);
00474     }
00475 
00476     return KConfigGroup(&globalAppletConfig, d->globalName());
00477 }
00478 
00479 void Applet::destroy()
00480 {
00481     if (immutability() != Mutable || d->transient || !d->started) {
00482         return; //don't double delete
00483     }
00484 
00485     d->transient = true;
00486 
00487     if (isContainment()) {
00488         d->cleanUpAndDelete();
00489     } else {
00490         Animation *zoomAnim = Plasma::Animator::create(Plasma::Animator::ZoomAnimation);
00491         connect(zoomAnim, SIGNAL(finished()), this, SLOT(cleanUpAndDelete()));
00492         zoomAnim->setTargetWidget(this);
00493         zoomAnim->start();
00494     }
00495 }
00496 
00497 bool Applet::destroyed() const
00498 {
00499     return d->transient;
00500 }
00501 
00502 void AppletPrivate::selectItemToDestroy()
00503 {
00504     //FIXME: this will not work nicely with multiple screens and being zoomed out!
00505     if (isContainment) {
00506         QGraphicsView *view = q->view();
00507         if (view && view->transform().isScaling() &&
00508             q->scene()->focusItem() != q) {
00509             QGraphicsItem *focus = q->scene()->focusItem();
00510 
00511             if (focus) {
00512                 Containment *toDestroy = dynamic_cast<Containment*>(focus->topLevelItem());
00513 
00514                 if (toDestroy) {
00515                     toDestroy->destroy();
00516                     return;
00517                 }
00518             }
00519         }
00520     }
00521 
00522     q->destroy();
00523 }
00524 
00525 void AppletPrivate::updateRect(const QRectF &rect)
00526 {
00527     q->update(rect);
00528 }
00529 
00530 void AppletPrivate::cleanUpAndDelete()
00531 {
00532     //kDebug() << "???????????????? DESTROYING APPLET" << q->name() << q->scene() << " ???????????????????????????";
00533     QGraphicsWidget *parent = dynamic_cast<QGraphicsWidget *>(q->parentItem());
00534     //it probably won't matter, but right now if there are applethandles, *they* are the parent.
00535     //not the containment.
00536 
00537     //is the applet in a containment and does the containment have a layout?
00538     //if yes, we remove the applet in the layout
00539     if (parent && parent->layout()) {
00540         QGraphicsLayout *l = parent->layout();
00541         for (int i = 0; i < l->count(); ++i) {
00542             if (q == l->itemAt(i)) {
00543                 l->removeAt(i);
00544                 break;
00545             }
00546         }
00547     }
00548 
00549     if (configLoader) {
00550         configLoader->setDefaults();
00551     }
00552 
00553     resetConfigurationObject();
00554 
00555     if (q->scene()) {
00556         if (isContainment) {
00557             // prematurely emit our destruction if we are a Containment,
00558             // giving Corona a chance to remove this Containment from its collection
00559             emit q->QObject::destroyed(q);
00560         }
00561 
00562         q->scene()->removeItem(q);
00563     }
00564 
00565     q->deleteLater();
00566 }
00567 
00568 void AppletPrivate::createMessageOverlay(bool usePopup)
00569 {
00570     if (messageOverlay) {
00571         qDeleteAll(messageOverlay->children());
00572         messageOverlay->setLayout(0);
00573     }
00574 
00575     PopupApplet *popup = qobject_cast<Plasma::PopupApplet*>(q);
00576 
00577     if (!messageOverlay) {
00578         if (usePopup && popup) {
00579             if (popup->widget()) {
00580                 messageOverlayProxy = new QGraphicsProxyWidget(q);
00581                 messageOverlayProxy->setWidget(popup->widget());
00582                 messageOverlay = new AppletOverlayWidget(messageOverlayProxy);
00583             } else if (popup->graphicsWidget() &&
00584                        popup->graphicsWidget() != extender.data()) {
00585                 messageOverlay = new AppletOverlayWidget(popup->graphicsWidget());
00586             }
00587         }
00588 
00589         if (!messageOverlay) {
00590             messageOverlay = new AppletOverlayWidget(q);
00591         }
00592     }
00593 
00594     positionMessageOverlay();
00595 }
00596 
00597 void AppletPrivate::positionMessageOverlay()
00598 {
00599     if (!messageOverlay) {
00600         return;
00601     }
00602 
00603     PopupApplet *popup = qobject_cast<Plasma::PopupApplet*>(q);
00604     const bool usePopup = popup && (messageOverlay->parentItem() != q);
00605     QGraphicsItem *topItem = q;
00606 
00607     if (usePopup && popup->widget()) {
00608         // popupapplet with widget()
00609         topItem = popup->d->proxy.data();
00610         messageOverlay->setGeometry(popup->widget()->contentsRect());
00611     } else if (usePopup && popup->graphicsWidget() && popup->graphicsWidget() != extender.data()) {
00612         // popupapplet with graphicsWidget()
00613         topItem = popup->graphicsWidget();
00614         QGraphicsWidget *w = dynamic_cast<QGraphicsWidget *>(topItem);
00615         messageOverlay->setGeometry(w ? w->contentsRect() : topItem->boundingRect());
00616     } else {
00617         // normal applet
00618         messageOverlay->setGeometry(q->contentsRect());
00619     }
00620 
00621     // raise the overlay above all the other children!
00622     int zValue = 100;
00623     foreach (QGraphicsItem *child, topItem->children()) {
00624         if (child->zValue() > zValue) {
00625             zValue = child->zValue() + 1;
00626         }
00627     }
00628     messageOverlay->setZValue(zValue);
00629 }
00630 
00631 void AppletPrivate::destroyMessageOverlay()
00632 {
00633     if (messageDialog) {
00634         messageDialog.data()->animatedHide(Plasma::locationToInverseDirection(q->location()));
00635         //messageDialog.data()->deleteLater();
00636         messageDialog.clear();
00637     }
00638 
00639     if (!messageOverlay) {
00640         return;
00641     }
00642 
00643     messageOverlay->destroy();
00644     messageOverlay = 0;
00645 
00646     if (messageOverlayProxy) {
00647         messageOverlayProxy->setWidget(0);
00648         delete messageOverlayProxy;
00649         messageOverlayProxy = 0;
00650     }
00651 
00652     MessageButton buttonCode = ButtonNo;
00653     //find out if we're disappearing because of a button press
00654     PushButton *button = qobject_cast<PushButton *>(q->sender());
00655     if (button) {
00656         if (button == messageOkButton.data()) {
00657             buttonCode = ButtonOk;
00658         }
00659         if (button == messageYesButton.data()) {
00660             buttonCode = ButtonYes;
00661         }
00662         if (button == messageNoButton.data()) {
00663             buttonCode = ButtonNo;
00664         }
00665         if (button == messageCancelButton.data()) {
00666             buttonCode = ButtonCancel;
00667         }
00668 
00669         emit q->messageButtonPressed(buttonCode);
00670     } else if (q->sender() == messageOverlay) {
00671         emit q->messageButtonPressed(ButtonCancel);
00672     }
00673 }
00674 
00675 ConfigLoader *Applet::configScheme() const
00676 {
00677     return d->configLoader;
00678 }
00679 
00680 DataEngine *Applet::dataEngine(const QString &name) const
00681 {
00682     if (!d->remoteLocation.isEmpty()) {
00683         return d->remoteDataEngine(KUrl(d->remoteLocation), name);
00684     } else if (!package() || package()->metadata().remoteLocation().isEmpty()) {
00685         return d->dataEngine(name);
00686     } else {
00687         return d->remoteDataEngine(KUrl(package()->metadata().remoteLocation()), name);
00688     }
00689 }
00690 
00691 const Package *Applet::package() const
00692 {
00693     return d->package;
00694 }
00695 
00696 QGraphicsView *Applet::view() const
00697 {
00698     // It's assumed that we won't be visible on more than one view here.
00699     // Anything that actually needs view() should only really care about
00700     // one of them anyway though.
00701     if (!scene()) {
00702         return 0;
00703     }
00704 
00705     QGraphicsView *found = 0;
00706     QGraphicsView *possibleFind = 0;
00707     //kDebug() << "looking through" << scene()->views().count() << "views";
00708     foreach (QGraphicsView *view, scene()->views()) {
00709         //kDebug() << "     checking" << view << view->sceneRect()
00710         //         << "against" << sceneBoundingRect() << scenePos();
00711         if (view->sceneRect().intersects(sceneBoundingRect()) ||
00712             view->sceneRect().contains(scenePos())) {
00713             //kDebug() << "     found something!" << view->isActiveWindow();
00714             if (view->isActiveWindow()) {
00715                 found = view;
00716             } else {
00717                 possibleFind = view;
00718             }
00719         }
00720     }
00721 
00722     return found ? found : possibleFind;
00723 }
00724 
00725 QRectF Applet::mapFromView(const QGraphicsView *view, const QRect &rect) const
00726 {
00727     // Why is this adjustment needed? Qt calculation error?
00728     return mapFromScene(view->mapToScene(rect)).boundingRect().adjusted(0, 0, 1, 1);
00729 }
00730 
00731 QRect Applet::mapToView(const QGraphicsView *view, const QRectF &rect) const
00732 {
00733     // Why is this adjustment needed? Qt calculation error?
00734     return view->mapFromScene(mapToScene(rect)).boundingRect().adjusted(0, 0, -1, -1);
00735 }
00736 
00737 QPoint Applet::popupPosition(const QSize &s) const
00738 {
00739     return popupPosition(s, Qt::AlignLeft);
00740 }
00741 
00742 QPoint Applet::popupPosition(const QSize &s, Qt::AlignmentFlag alignment) const
00743 {
00744     Corona * corona = qobject_cast<Corona*>(scene());
00745     Q_ASSERT(corona);
00746 
00747     return corona->popupPosition(this, s, alignment);
00748 }
00749 
00750 void Applet::updateConstraints(Plasma::Constraints constraints)
00751 {
00752     d->scheduleConstraintsUpdate(constraints);
00753 }
00754 
00755 void Applet::constraintsEvent(Plasma::Constraints constraints)
00756 {
00757     //NOTE: do NOT put any code in here that reacts to constraints updates
00758     //      as it will not get called for any applet that reimplements constraintsEvent
00759     //      without calling the Applet:: version as well, which it shouldn't need to.
00760     //      INSTEAD put such code into flushPendingConstraintsEvents
00761     Q_UNUSED(constraints)
00762     //kDebug() << constraints << "constraints are FormFactor: " << formFactor()
00763     //         << ", Location: " << location();
00764     if (d->script) {
00765         d->script->constraintsEvent(constraints);
00766     }
00767 }
00768 
00769 void Applet::initExtenderItem(ExtenderItem *item)
00770 {
00771     if (d->script) {
00772         emit extenderItemRestored(item);
00773     } else {
00774         kWarning() << "Missing implementation of initExtenderItem in the applet "
00775                    << item->config().readEntry("SourceAppletPluginName", "")
00776                    << "!\n Any applet that uses extenders should implement initExtenderItem to "
00777                    << "instantiate a widget. Destroying the item...";
00778         item->destroy();
00779     }
00780 }
00781 
00782 Extender *Applet::extender() const
00783 {
00784     if (!d->extender) {
00785         new Extender(const_cast<Applet*>(this));
00786     }
00787 
00788     return d->extender.data();
00789 }
00790 
00791 void Applet::setBusy(bool busy)
00792 {
00793     if (busy) {
00794         if (!d->busyWidget && !d->busyWidgetTimer.isActive()) {
00795             d->busyWidgetTimer.start(500, this);
00796         }
00797     } else {
00798         d->busyWidgetTimer.stop();
00799         if (d->busyWidget) {
00800             d->busyWidget = 0;
00801             d->destroyMessageOverlay();
00802         }
00803     }
00804 }
00805 
00806 bool Applet::isBusy() const
00807 {
00808     return d->busyWidgetTimer.isActive() || (d->busyWidget && d->busyWidget->isVisible());
00809 }
00810 
00811 QString Applet::name() const
00812 {
00813     if (d->isContainment) {
00814         const Containment *c = qobject_cast<const Containment*>(this);
00815         if (c && c->d->isPanelContainment()) {
00816             return i18n("Panel");
00817         } else if (!d->appletDescription.isValid()) {
00818             return i18n("Unknown");
00819         } else {
00820             return d->appletDescription.name();
00821         }
00822     } else if (!d->appletDescription.isValid()) {
00823         return i18n("Unknown Widget");
00824     }
00825 
00826     return d->appletDescription.name();
00827 }
00828 
00829 QFont Applet::font() const
00830 {
00831     return QApplication::font();
00832 }
00833 
00834 QString Applet::icon() const
00835 {
00836     if (!d->appletDescription.isValid()) {
00837         return QString();
00838     }
00839 
00840     return d->appletDescription.icon();
00841 }
00842 
00843 QString Applet::pluginName() const
00844 {
00845     if (!d->appletDescription.isValid()) {
00846         return d->mainConfigGroup()->readEntry("plugin", QString());
00847     }
00848 
00849     return d->appletDescription.pluginName();
00850 }
00851 
00852 bool Applet::shouldConserveResources() const
00853 {
00854 #ifndef PLASMA_NO_SOLID
00855     return Solid::PowerManagement::appShouldConserveResources();
00856 #else
00857     return true;
00858 #endif
00859 }
00860 
00861 QString Applet::category() const
00862 {
00863     if (!d->appletDescription.isValid()) {
00864         return i18nc("misc category", "Miscellaneous");
00865     }
00866 
00867     return d->appletDescription.category();
00868 }
00869 
00870 QString Applet::category(const KPluginInfo &applet)
00871 {
00872     return applet.property("X-KDE-PluginInfo-Category").toString();
00873 }
00874 
00875 QString Applet::category(const QString &appletName)
00876 {
00877     if (appletName.isEmpty()) {
00878         return QString();
00879     }
00880 
00881     const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(appletName);
00882     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
00883 
00884     if (offers.isEmpty()) {
00885         return QString();
00886     }
00887 
00888     return offers.first()->property("X-KDE-PluginInfo-Category").toString();
00889 }
00890 
00891 ImmutabilityType Applet::immutability() const
00892 {
00893     // if this object is itself system immutable, then just return that; it's the most
00894     // restrictive setting possible and will override anything that might be happening above it
00895     // in the Corona->Containment->Applet hierarchy
00896     if (d->transient || (d->mainConfig && d->mainConfig->isImmutable())) {
00897         return SystemImmutable;
00898     }
00899 
00900     //Returning the more strict immutability between the applet immutability, Containment and Corona
00901     ImmutabilityType upperImmutability = Mutable;
00902     Containment *cont = d->isContainment ? 0 : containment();
00903 
00904     if (cont) {
00905         upperImmutability = cont->immutability();
00906     } else if (Corona *corona = qobject_cast<Corona*>(scene())) {
00907         upperImmutability = corona->immutability();
00908     }
00909 
00910     if (upperImmutability != Mutable) {
00911         // it's either system or user immutable, and we already check for local system immutability,
00912         // so upperImmutability is guaranteed to be as or more severe as this object's immutability
00913         return upperImmutability;
00914     } else {
00915         return d->immutability;
00916     }
00917 }
00918 
00919 void Applet::setImmutability(const ImmutabilityType immutable)
00920 {
00921     if (d->immutability == immutable || immutable == Plasma::SystemImmutable) {
00922         // we do not store system immutability in d->immutability since that gets saved
00923         // out to the config file; instead, we check with
00924         // the config group itself for this information at all times. this differs from
00925         // corona, where SystemImmutability is stored in d->immutability.
00926         return;
00927     }
00928 
00929     d->immutability = immutable;
00930     updateConstraints(ImmutableConstraint);
00931 }
00932 
00933 Applet::BackgroundHints Applet::backgroundHints() const
00934 {
00935     return d->backgroundHints;
00936 }
00937 
00938 void Applet::setBackgroundHints(const BackgroundHints hints)
00939 {
00940     if (d->backgroundHints == hints) {
00941         return;
00942     }
00943 
00944     d->backgroundHints = hints;
00945     d->preferredBackgroundHints = hints;
00946 
00947     //Draw the standard background?
00948     if ((hints & StandardBackground) || (hints & TranslucentBackground)) {
00949         if (!d->background) {
00950             d->background = new Plasma::FrameSvg(this);
00951             QObject::connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(themeChanged()));
00952         }
00953 
00954         if ((hints & TranslucentBackground) &&
00955             Plasma::Theme::defaultTheme()->currentThemeHasImage("widgets/translucentbackground")) {
00956             d->background->setImagePath("widgets/translucentbackground");
00957         } else {
00958             d->background->setImagePath("widgets/background");
00959         }
00960 
00961         d->background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
00962         qreal left, top, right, bottom;
00963         d->background->getMargins(left, top, right, bottom);
00964         setContentsMargins(left, right, top, bottom);
00965         QSizeF fitSize(left + right, top + bottom);
00966         d->background->resizeFrame(boundingRect().size());
00967 
00968         //if the background has an "overlay" element decide a random position for it and then save it so it's consistent across plasma starts
00969         if (d->background->hasElement("overlay")) {
00970             QSize overlaySize = d->background->elementSize("overlay");
00971 
00972             //position is in the boundaries overlaySize.width()*2, overlaySize.height()
00973             qsrand(id());
00974             d->background->d->overlayPos.rx() = - (overlaySize.width() /2) + (overlaySize.width() /4) * (qrand() % (4 + 1));
00975             d->background->d->overlayPos.ry() = (- (overlaySize.height() /2) + (overlaySize.height() /4) * (qrand() % (4 + 1)))/2;
00976         }
00977     } else if (d->background) {
00978         qreal left, top, right, bottom;
00979         d->background->getMargins(left, top, right, bottom);
00980 
00981         delete d->background;
00982         d->background = 0;
00983         setContentsMargins(0, 0, 0, 0);
00984     }
00985 
00986     update();
00987 }
00988 
00989 bool Applet::hasFailedToLaunch() const
00990 {
00991     return d->failed;
00992 }
00993 
00994 void Applet::paintWindowFrame(QPainter *painter,
00995                               const QStyleOptionGraphicsItem *option, QWidget *widget)
00996 {
00997     Q_UNUSED(painter)
00998     Q_UNUSED(option)
00999     Q_UNUSED(widget)
01000     //Here come the code for the window frame
01001     //kDebug() << windowFrameGeometry();
01002     //painter->drawRoundedRect(windowFrameGeometry(), 5, 5);
01003 }
01004 
01005 bool Applet::configurationRequired() const
01006 {
01007     return d->needsConfig;
01008 }
01009 
01010 void Applet::setConfigurationRequired(bool needsConfig, const QString &reason)
01011 {
01012     if (d->needsConfig == needsConfig) {
01013         return;
01014     }
01015 
01016     d->needsConfig = needsConfig;
01017 
01018     if (!needsConfig) {
01019         d->destroyMessageOverlay();
01020         return;
01021     }
01022 
01023     d->createMessageOverlay(true);
01024     d->messageOverlay->opacity = 0.4;
01025 
01026     QGraphicsGridLayout *configLayout = new QGraphicsGridLayout(d->messageOverlay);
01027     configLayout->setContentsMargins(0, 0, 0, 0);
01028 
01029   //  configLayout->addStretch();
01030     configLayout->setColumnStretchFactor(0, 5);
01031     configLayout->setColumnStretchFactor(2, 5);
01032     configLayout->setRowStretchFactor(0, 5);
01033     configLayout->setRowStretchFactor(3, 5);
01034 
01035     int row = 1;
01036     if (!reason.isEmpty()) {
01037         Label *explanation = new Label(d->messageOverlay);
01038         explanation->setText(reason);
01039         configLayout->addItem(explanation, row, 1);
01040         configLayout->setColumnStretchFactor(1, 5);
01041         ++row;
01042         configLayout->setAlignment(explanation, Qt::AlignBottom | Qt::AlignCenter);
01043     }
01044 
01045     PushButton *configWidget = new PushButton(d->messageOverlay);
01046     if (!qobject_cast<Plasma::PopupApplet *>(this) && (formFactor() == Plasma::Horizontal || formFactor() == Plasma::Vertical)) {
01047         configWidget->setImage("widgets/configuration-icons", "configure");
01048         configWidget->setMaximumSize(24,24);
01049         configWidget->setMinimumSize(24,24);
01050     } else {
01051         configWidget->setText(i18n("Configure..."));
01052     }
01053     connect(configWidget, SIGNAL(clicked()), this, SLOT(showConfigurationInterface()));
01054     configLayout->addItem(configWidget, row, 1);
01055 
01056     //configLayout->setAlignment(configWidget, Qt::AlignTop | Qt::AlignCenter);
01057     //configLayout->addStretch();
01058 
01059     d->messageOverlay->show();
01060 }
01061 
01062 void Applet::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons)
01063 {
01064     if (message.isEmpty()) {
01065         d->destroyMessageOverlay();
01066         return;
01067     }
01068 
01069     Corona *corona = qobject_cast<Corona *>(scene());
01070     QGraphicsWidget *mainWidget = new QGraphicsWidget;
01071 
01072     QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(mainWidget);
01073     mainLayout->setOrientation(Qt::Vertical);
01074     mainLayout->addStretch();
01075 
01076     QGraphicsLinearLayout *messageLayout = new QGraphicsLinearLayout();
01077     messageLayout->setOrientation(Qt::Horizontal);
01078 
01079     QGraphicsLinearLayout *buttonLayout = new QGraphicsLinearLayout();
01080     buttonLayout->setOrientation(Qt::Horizontal);
01081 
01082     mainLayout->addItem(messageLayout);
01083     mainLayout->addItem(buttonLayout);
01084     mainLayout->addStretch();
01085 
01086     IconWidget *messageIcon = new IconWidget(mainWidget);
01087     Label *messageText = new Label(mainWidget);
01088     messageText->nativeWidget()->setWordWrap(true);
01089 
01090     messageLayout->addStretch();
01091     messageLayout->addItem(messageIcon);
01092     messageLayout->addItem(messageText);
01093     messageLayout->addStretch();
01094 
01095     messageIcon->setIcon(icon);
01096     messageText->setText(message);
01097 
01098     buttonLayout->addStretch();
01099 
01100     if (buttons & ButtonOk) {
01101         d->messageOkButton = new PushButton(mainWidget);
01102         d->messageOkButton.data()->setText(i18n("&OK"));
01103         d->messageOkButton.data()->setIcon(KIcon("dialog-ok"));
01104         buttonLayout->addItem(d->messageOkButton.data());
01105         connect(d->messageOkButton.data(), SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01106     }
01107 
01108     if (buttons & ButtonYes) {
01109         d->messageYesButton = new PushButton(mainWidget);
01110         d->messageYesButton.data()->setText(i18n("&Yes"));
01111         buttonLayout->addItem(d->messageYesButton.data());
01112         connect(d->messageYesButton.data(), SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01113     }
01114 
01115     if (buttons & ButtonNo) {
01116         d->messageNoButton = new PushButton(mainWidget);
01117         d->messageNoButton.data()->setText(i18n("&No"));
01118         buttonLayout->addItem(d->messageNoButton.data());
01119         connect(d->messageNoButton.data(), SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01120     }
01121 
01122     if (buttons & ButtonCancel) {
01123         d->messageCancelButton = new PushButton(mainWidget);
01124         d->messageCancelButton.data()->setText(i18n("&Cancel"));
01125         d->messageCancelButton.data()->setIcon(KIcon("dialog-cancel"));
01126         buttonLayout->addItem(d->messageCancelButton.data());
01127         connect(d->messageCancelButton.data(), SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01128     }
01129 
01130     d->messageCloseAction = new QAction(d->messageOverlay);
01131     d->messageCloseAction.data()->setShortcut(Qt::Key_Escape);
01132     mainWidget->addAction(d->messageCloseAction.data());
01133     connect(d->messageCloseAction.data(), SIGNAL(triggered()), this, SLOT(destroyMessageOverlay()));
01134 
01135     buttonLayout->addStretch();
01136 
01137     mainWidget->adjustSize();
01138     QSizeF hint = mainWidget->preferredSize();
01139     if (hint.height() > size().height() || hint.width() > size().width()) {
01140         // either a collapsed popup in h/v form factor or just too small,
01141         // so show it in a dialog associated with ourselves
01142         if (corona) {
01143             corona->addOffscreenWidget(mainWidget);
01144         }
01145 
01146         if (d->messageDialog) {
01147             delete d->messageDialog.data()->graphicsWidget();
01148         } else {
01149             d->messageDialog = new Plasma::Dialog;
01150         }
01151 
01152         ToolTipManager::self()->hide(this);
01153         KWindowSystem::setOnAllDesktops(d->messageDialog.data()->winId(), true);
01154         KWindowSystem::setState(d->messageDialog.data()->winId(), NET::SkipTaskbar | NET::SkipPager);
01155         d->messageDialog.data()->setGraphicsWidget(mainWidget);
01156         connect(d->messageDialog.data(), SIGNAL(destroyed(QObject*)), mainWidget, SLOT(deleteLater()));
01157 
01158         // if we are going to show it in a popup, then at least make sure it can be dismissed
01159         if (buttonLayout->count() < 1) {
01160             PushButton *ok = new PushButton(mainWidget);
01161             ok->setText(i18n("OK"));
01162             ok->setIcon(KIcon("dialog-ok"));
01163             buttonLayout->addItem(ok);
01164             connect(ok, SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01165         }
01166     } else {
01167         delete d->messageDialog.data();
01168         d->createMessageOverlay();
01169         d->messageOverlay->opacity = 0.8;
01170         mainWidget->setParentItem(d->messageOverlay);
01171         QGraphicsLinearLayout *l = new QGraphicsLinearLayout(d->messageOverlay);
01172         l->addItem(mainWidget);
01173     }
01174 
01175     if (d->messageDialog) {
01176         QPoint pos = geometry().topLeft().toPoint();
01177         if (corona) {
01178             pos = corona->popupPosition(this, d->messageDialog.data()->size());
01179         }
01180 
01181         d->messageDialog.data()->move(pos);
01182         d->messageDialog.data()->animatedShow(locationToDirection(location()));
01183     } else {
01184         d->messageOverlay->show();
01185     }
01186 }
01187 
01188 QVariantList Applet::startupArguments() const
01189 {
01190     return d->args;
01191 }
01192 
01193 ItemStatus Applet::status() const
01194 {
01195     return d->itemStatus;
01196 }
01197 
01198 void Applet::setStatus(const ItemStatus status)
01199 {
01200     d->itemStatus = status;
01201     emit newStatus(status);
01202 }
01203 
01204 void Applet::flushPendingConstraintsEvents()
01205 {
01206     if (d->pendingConstraints == NoConstraint) {
01207         return;
01208     }
01209 
01210     if (d->constraintsTimer.isActive()) {
01211         d->constraintsTimer.stop();
01212     }
01213 
01214     //kDebug() << "fushing constraints: " << d->pendingConstraints << "!!!!!!!!!!!!!!!!!!!!!!!!!!!";
01215     Plasma::Constraints c = d->pendingConstraints;
01216     d->pendingConstraints = NoConstraint;
01217 
01218     if (c & Plasma::StartupCompletedConstraint) {
01219         //common actions
01220         bool unlocked = immutability() == Mutable;
01221         QAction *closeApplet = d->actions->action("remove");
01222         if (closeApplet) {
01223             closeApplet->setEnabled(unlocked);
01224             closeApplet->setVisible(unlocked);
01225             connect(closeApplet, SIGNAL(triggered(bool)), this, SLOT(selectItemToDestroy()), Qt::UniqueConnection);
01226         }
01227 
01228         QAction *configAction = d->actions->action("configure");
01229         if (configAction) {
01230             if (d->isContainment) {
01231                 connect(configAction, SIGNAL(triggered(bool)), this, SLOT(requestConfiguration()), Qt::UniqueConnection);
01232             } else {
01233                 connect(configAction, SIGNAL(triggered(bool)), this, SLOT(showConfigurationInterface()), Qt::UniqueConnection);
01234             }
01235 
01236             if (d->hasConfigurationInterface) {
01237                 bool canConfig = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
01238                 configAction->setVisible(canConfig);
01239                 configAction->setEnabled(canConfig);
01240             }
01241         }
01242 
01243         QAction *runAssociatedApplication = d->actions->action("run associated application");
01244         if (runAssociatedApplication) {
01245             connect(runAssociatedApplication, SIGNAL(triggered(bool)), this, SLOT(runAssociatedApplication()), Qt::UniqueConnection);
01246         }
01247 
01248         d->updateShortcuts();
01249         Corona * corona = qobject_cast<Corona*>(scene());
01250         if (corona) {
01251             connect(corona, SIGNAL(shortcutsChanged()), this, SLOT(updateShortcuts()), Qt::UniqueConnection);
01252         }
01253     }
01254 
01255     if (c & Plasma::ImmutableConstraint) {
01256         bool unlocked = immutability() == Mutable;
01257         QAction *action = d->actions->action("remove");
01258         if (action) {
01259             action->setVisible(unlocked);
01260             action->setEnabled(unlocked);
01261         }
01262 
01263         action = d->actions->action("configure");
01264         if (action && d->hasConfigurationInterface) {
01265             bool canConfig = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
01266             action->setVisible(canConfig);
01267             action->setEnabled(canConfig);
01268         }
01269 
01270         if (d->extender) {
01271             foreach (ExtenderItem *item, d->extender.data()->attachedItems()) {
01272                 item->d->setMovable(unlocked);
01273             }
01274         }
01275 
01276         if (!unlocked && d->handle) {
01277             AppletHandle *h = d->handle.data();
01278             disconnect(this);
01279 
01280             QGraphicsScene *s = scene();
01281             if (s && h->scene() == s) {
01282                 s->removeItem(h);
01283             }
01284 
01285             h->deleteLater();
01286         }
01287 
01288         emit immutabilityChanged(immutability());
01289     }
01290 
01291     if (c & Plasma::SizeConstraint) {
01292         d->positionMessageOverlay();
01293 
01294         if (d->started && layout()) {
01295             layout()->updateGeometry();
01296         }
01297     }
01298 
01299     if (c & Plasma::FormFactorConstraint) {
01300         FormFactor f = formFactor();
01301         if (!d->isContainment && f != Vertical && f != Horizontal) {
01302             setBackgroundHints(d->preferredBackgroundHints);
01303         } else {
01304             BackgroundHints hints = d->preferredBackgroundHints;
01305             setBackgroundHints(NoBackground);
01306             d->preferredBackgroundHints = hints;
01307         }
01308 
01309         if (d->failed) {
01310             if (f == Vertical || f == Horizontal) {
01311                 QGraphicsLayoutItem *item = layout()->itemAt(1);
01312                 layout()->removeAt(1);
01313                 delete item;
01314             }
01315         }
01316 
01317         // avoid putting rotated applets in panels
01318         if (f == Vertical || f == Horizontal) {
01319             QTransform at;
01320             at.rotateRadians(0);
01321             setTransform(at);
01322         }
01323 
01324         //was a size saved for a particular form factor?
01325         if (d->sizeForFormFactor.contains(f)) {
01326             resize(d->sizeForFormFactor.value(f));
01327         }
01328     }
01329 
01330     if (!size().isEmpty() &&
01331         ((c & Plasma::StartupCompletedConstraint) || (c & Plasma::SizeConstraint && !(c & Plasma::FormFactorConstraint)))) {
01332         d->sizeForFormFactor[formFactor()] = size();
01333     }
01334 
01335     if (c & Plasma::SizeConstraint || c & Plasma::FormFactorConstraint) {
01336         if (aspectRatioMode() == Plasma::Square || aspectRatioMode() == Plasma::ConstrainedSquare) {
01337             // enforce square size in panels
01338             //save the old size policy. since ignored doesn't (yet) have a valid use case in containments, use it as special unset value
01339             if (d->preferredSizePolicy == QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)) {
01340                 d->preferredSizePolicy = sizePolicy();
01341             }
01342             if (formFactor() == Horizontal) {
01343                 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
01344             } else if (formFactor() == Vertical) {
01345                 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
01346             } else if (d->preferredSizePolicy != QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)) {
01347                 setSizePolicy(d->preferredSizePolicy);
01348             }
01349         }
01350         updateGeometry();
01351     }
01352 
01353     // now take care of constraints in special subclasses: Contaiment and PopupApplet
01354     Containment* containment = qobject_cast<Plasma::Containment*>(this);
01355     if (d->isContainment && containment) {
01356         containment->d->containmentConstraintsEvent(c);
01357     }
01358 
01359     PopupApplet* popup = qobject_cast<Plasma::PopupApplet*>(this);
01360     if (popup) {
01361         popup->d->popupConstraintsEvent(c);
01362     }
01363 
01364     // pass the constraint on to the actual subclass
01365     constraintsEvent(c);
01366 
01367     if (c & StartupCompletedConstraint) {
01368         // start up is done, we can now go do a mod timer
01369         if (d->modificationsTimer) {
01370             if (d->modificationsTimer->isActive()) {
01371                 d->modificationsTimer->stop();
01372             }
01373         } else {
01374             d->modificationsTimer = new QBasicTimer;
01375         }
01376     }
01377 }
01378 
01379 int Applet::type() const
01380 {
01381     return Type;
01382 }
01383 
01384 QList<QAction*> Applet::contextualActions()
01385 {
01386     //kDebug() << "empty context actions";
01387     return d->script ? d->script->contextualActions() : QList<QAction*>();
01388 }
01389 
01390 QAction *Applet::action(QString name) const
01391 {
01392     return d->actions->action(name);
01393 }
01394 
01395 void Applet::addAction(QString name, QAction *action)
01396 {
01397     d->actions->addAction(name, action);
01398 }
01399 
01400 void Applet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
01401 {
01402     if (!d->started) {
01403         //kDebug() << "not started";
01404         return;
01405     }
01406 
01407     if (transform().isRotating()) {
01408         painter->setRenderHint(QPainter::SmoothPixmapTransform);
01409         painter->setRenderHint(QPainter::Antialiasing);
01410     }
01411 
01412     if (d->background &&
01413         formFactor() != Plasma::Vertical &&
01414         formFactor() != Plasma::Horizontal) {
01415         //kDebug() << "option rect is" << option->rect;
01416         d->background->paintFrame(painter);
01417     }
01418 
01419     if (d->failed) {
01420         //kDebug() << "failed!";
01421         return;
01422     }
01423 
01424     qreal left, top, right, bottom;
01425     getContentsMargins(&left, &top, &right, &bottom);
01426     QRect contentsRect = QRectF(QPointF(0, 0),
01427                                 boundingRect().size()).adjusted(left, top, -right, -bottom).toRect();
01428 
01429     if (widget && d->isContainment) {
01430         // note that the widget we get is actually the viewport of the view, not the view itself
01431         View* v = qobject_cast<Plasma::View*>(widget->parent());
01432         Containment* c = qobject_cast<Plasma::Containment*>(this);
01433 
01434         if (!v || v->isWallpaperEnabled()) {
01435 
01436             // paint the wallpaper
01437             if (c && c->drawWallpaper() && c->wallpaper()) {
01438                 Wallpaper *w = c->wallpaper();
01439                 if (!w->isInitialized()) {
01440                     // delayed paper initialization
01441                     KConfigGroup wallpaperConfig = c->config();
01442                     wallpaperConfig = KConfigGroup(&wallpaperConfig, "Wallpaper");
01443                     wallpaperConfig = KConfigGroup(&wallpaperConfig, w->pluginName());
01444                     w->restore(wallpaperConfig);
01445                     disconnect(w, SIGNAL(update(QRectF)), this, SLOT(updateRect(QRectF)));
01446                     connect(w, SIGNAL(update(QRectF)), this, SLOT(updateRect(QRectF)));
01447                 }
01448 
01449                 painter->save();
01450                 c->wallpaper()->paint(painter, option->exposedRect);
01451                 painter->restore();
01452             }
01453 
01454             // .. and now paint the actual containment interface, but with
01455             //  a Containment style option based on the one we get
01456             //  the view must be assigned only if its containment is actually our own
01457             Containment::StyleOption coption(*option);
01458             if (v && v->containment() == containment()) {
01459                 coption.view = v;
01460             }
01461             paintInterface(painter, &coption, contentsRect);
01462         }
01463     } else {
01464         //kDebug() << "paint interface of" << (QObject*) this;
01465         // paint the applet's interface
01466         paintInterface(painter, option, contentsRect);
01467     }
01468 }
01469 
01470 void Applet::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
01471 {
01472     if (d->script) {
01473         d->script->paintInterface(painter, option, contentsRect);
01474     } else {
01475         //kDebug() << "Applet::paintInterface() default impl";
01476     }
01477 }
01478 
01479 FormFactor Applet::formFactor() const
01480 {
01481     Containment *c = containment();
01482     QGraphicsWidget *pw = qobject_cast<QGraphicsWidget *>(parent());
01483     if (!pw) {
01484         pw = dynamic_cast<QGraphicsWidget *>(parentItem());
01485     }
01486     Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(pw);
01487     //assumption: this loop is usually is -really- short or doesn't run at all
01488     while (!parentApplet && pw && pw->parentWidget()) {
01489         QGraphicsWidget *parentWidget = qobject_cast<QGraphicsWidget *>(pw->parent());
01490         if (!parentWidget) {
01491             parentWidget = dynamic_cast<QGraphicsWidget *>(pw->parentItem());
01492         }
01493         pw = parentWidget;
01494         parentApplet = qobject_cast<Plasma::Applet *>(pw);
01495     }
01496 
01497 
01498     const PopupApplet *pa = dynamic_cast<const PopupApplet *>(this);
01499 
01500     //if the applet is in a widget that isn't a containment
01501     //try to retrieve the formFactor from the parent size
01502     //we can't use our own sizeHint here because it needs formFactor, so endless recursion.
01503     // a popupapplet can always be constrained.
01504     // a normal applet should to but
01505     //FIXME: not always constrained to not break systemmonitor
01506     if (parentApplet && parentApplet != c && c != this && (pa || layout())) {
01507         if (pa || (parentApplet->size().height() < layout()->effectiveSizeHint(Qt::MinimumSize).height())) {
01508             return Plasma::Horizontal;
01509         } else if (pa || (parentApplet->size().width() < layout()->effectiveSizeHint(Qt::MinimumSize).width())) {
01510             return Plasma::Vertical;
01511         }
01512         return parentApplet->formFactor();
01513     }
01514 
01515     return c ? c->d->formFactor : Plasma::Planar;
01516 }
01517 
01518 Containment *Applet::containment() const
01519 {
01520     if (d->isContainment) {
01521         Containment *c = qobject_cast<Containment*>(const_cast<Applet*>(this));
01522         if (c) {
01523             return c;
01524         }
01525     }
01526 
01527     QGraphicsItem *parent = parentItem();
01528     Containment *c = 0;
01529 
01530     while (parent) {
01531         Containment *possibleC = dynamic_cast<Containment*>(parent);
01532         if (possibleC && possibleC->Applet::d->isContainment) {
01533             c = possibleC;
01534             break;
01535         }
01536         parent = parent->parentItem();
01537     }
01538 
01539     if (!c) {
01540         //if the applet is an offscreen widget its parentItem will be 0, while its parent
01541         //will be its parentWidget, so here we check the QObject hierarchy.
01542         QObject *objParent = this->parent();
01543         while (objParent) {
01544             Containment *possibleC = qobject_cast<Containment*>(objParent);
01545             if (possibleC && possibleC->Applet::d->isContainment) {
01546                 c = possibleC;
01547                 break;
01548             }
01549             objParent = objParent->parent();
01550         }
01551     }
01552 
01553     return c;
01554 }
01555 
01556 void Applet::setGlobalShortcut(const KShortcut &shortcut)
01557 {
01558     if (!d->activationAction) {
01559         d->activationAction = new KAction(this);
01560         d->activationAction->setText(i18n("Activate %1 Widget", name()));
01561         d->activationAction->setObjectName(QString("activate widget %1").arg(id())); // NO I18N
01562         connect(d->activationAction, SIGNAL(triggered()), this, SIGNAL(activate()));
01563         connect(d->activationAction, SIGNAL(globalShortcutChanged(QKeySequence)),
01564                 this, SLOT(globalShortcutChanged()));
01565 
01566         QList<QWidget *> widgets = d->actions->associatedWidgets();
01567         foreach (QWidget *w, widgets) {
01568             w->addAction(d->activationAction);
01569         }
01570     } else if (d->activationAction->globalShortcut() == shortcut) {
01571         return;
01572     }
01573 
01574     //kDebug() << "before" << shortcut.primary() << d->activationAction->globalShortcut().primary();
01575     d->activationAction->setGlobalShortcut(
01576         shortcut,
01577         KAction::ShortcutTypes(KAction::ActiveShortcut | KAction::DefaultShortcut),
01578         KAction::NoAutoloading);
01579     d->globalShortcutChanged();
01580 }
01581 
01582 void AppletPrivate::globalShortcutChanged()
01583 {
01584     if (!activationAction) {
01585         return;
01586     }
01587 
01588     KConfigGroup shortcutConfig(mainConfigGroup(), "Shortcuts");
01589     shortcutConfig.writeEntry("global", activationAction->globalShortcut().toString());
01590     scheduleModificationNotification();
01591     //kDebug() << "after" << shortcut.primary() << d->activationAction->globalShortcut().primary();
01592 }
01593 
01594 KShortcut Applet::globalShortcut() const
01595 {
01596     if (d->activationAction) {
01597         return d->activationAction->globalShortcut();
01598     }
01599 
01600     return KShortcut();
01601 }
01602 
01603 bool Applet::isPopupShowing() const
01604 {
01605     return false;
01606 }
01607 
01608 void Applet::addAssociatedWidget(QWidget *widget)
01609 {
01610     d->actions->addAssociatedWidget(widget);
01611 }
01612 
01613 void Applet::removeAssociatedWidget(QWidget *widget)
01614 {
01615     d->actions->removeAssociatedWidget(widget);
01616 }
01617 
01618 Location Applet::location() const
01619 {
01620     Containment *c = containment();
01621     return c ? c->d->location : Plasma::Desktop;
01622 }
01623 
01624 Context *Applet::context() const
01625 {
01626     Containment *c = containment();
01627     Q_ASSERT(c);
01628     return c->d->context();
01629 }
01630 
01631 Plasma::AspectRatioMode Applet::aspectRatioMode() const
01632 {
01633     return d->aspectRatioMode;
01634 }
01635 
01636 void Applet::setAspectRatioMode(Plasma::AspectRatioMode mode)
01637 {
01638     PopupApplet *popup = qobject_cast<PopupApplet *>(this);
01639     if (popup && popup->d->dialogPtr) {
01640         popup->d->dialogPtr.data()->setAspectRatioMode(mode);
01641         popup->d->savedAspectRatio = mode;
01642     }
01643 
01644     d->aspectRatioMode = mode;
01645 }
01646 
01647 void Applet::registerAsDragHandle(QGraphicsItem *item)
01648 {
01649     if (!item || d->registeredAsDragHandle.contains(item)) {
01650         return;
01651     }
01652 
01653     d->registeredAsDragHandle.insert(item);
01654     item->installSceneEventFilter(this);
01655 }
01656 
01657 void Applet::unregisterAsDragHandle(QGraphicsItem *item)
01658 {
01659     if (!item) {
01660         return;
01661     }
01662 
01663     if (d->registeredAsDragHandle.remove(item)) {
01664         if (item != this) {
01665             item->removeSceneEventFilter(this);
01666         }
01667     }
01668 }
01669 
01670 bool Applet::isRegisteredAsDragHandle(QGraphicsItem *item)
01671 {
01672     return d->registeredAsDragHandle.contains(item);
01673 }
01674 
01675 bool Applet::hasConfigurationInterface() const
01676 {
01677     return d->hasConfigurationInterface;
01678 }
01679 
01680 void Applet::publish(AnnouncementMethods methods, const QString &resourceName)
01681 {
01682     if (d->package) {
01683         d->package->d->publish(methods);
01684     } else if (d->appletDescription.isValid()) {
01685         if (!d->service) {
01686             d->service = new PlasmoidService(this);
01687         }
01688 
01689         kDebug() << "publishing package under name " << resourceName;
01690         PackageMetadata pm;
01691         pm.setName(d->appletDescription.name());
01692         pm.setDescription(d->appletDescription.comment());
01693         pm.setIcon(d->appletDescription.icon());
01694         d->service->d->publish(methods, resourceName, pm);
01695     } else {
01696         kDebug() << "Can not publish invalid applets.";
01697     }
01698 }
01699 
01700 void Applet::unpublish()
01701 {
01702     if (d->package) {
01703         d->package->d->unpublish();
01704     } else {
01705         if (d->service) {
01706             d->service->d->unpublish();
01707         }
01708     }
01709 }
01710 
01711 bool Applet::isPublished() const
01712 {
01713     if (d->package) {
01714         return d->package->d->isPublished();
01715     } else {
01716         if (d->service) {
01717             return d->service->d->isPublished();
01718         } else {
01719             return false;
01720         }
01721     }
01722 }
01723 
01724 void Applet::setHasConfigurationInterface(bool hasInterface)
01725 {
01726     if (hasInterface == d->hasConfigurationInterface) {
01727         return;
01728     }
01729 
01730     QAction *configAction = d->actions->action("configure");
01731     if (configAction) {
01732         bool enable = hasInterface;
01733         if (enable) {
01734             const bool unlocked = immutability() == Mutable;
01735             enable = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
01736         }
01737         configAction->setEnabled(enable);
01738     }
01739 
01740     d->hasConfigurationInterface = hasInterface;
01741 }
01742 
01743 KActionCollection* AppletPrivate::defaultActions(QObject *parent)
01744 {
01745     KActionCollection *actions = new KActionCollection(parent);
01746     actions->setConfigGroup("Shortcuts-Applet");
01747 
01748     KAction *configAction = actions->addAction("configure");
01749     configAction->setAutoRepeat(false);
01750     configAction->setText(i18n("Widget Settings"));
01751     configAction->setIcon(KIcon("configure"));
01752     configAction->setShortcut(KShortcut("alt+d, s"));
01753     configAction->setData(AbstractToolBox::ConfigureTool);
01754 
01755     KAction *closeApplet = actions->addAction("remove");
01756     closeApplet->setAutoRepeat(false);
01757     closeApplet->setText(i18n("Remove this Widget"));
01758     closeApplet->setIcon(KIcon("edit-delete"));
01759     closeApplet->setShortcut(KShortcut("alt+d, r"));
01760     closeApplet->setData(AbstractToolBox::DestructiveTool);
01761 
01762     KAction *runAssociatedApplication = actions->addAction("run associated application");
01763     runAssociatedApplication->setAutoRepeat(false);
01764     runAssociatedApplication->setText(i18n("Run the Associated Application"));
01765     runAssociatedApplication->setIcon(KIcon("system-run"));
01766     runAssociatedApplication->setShortcut(KShortcut("alt+d, t"));
01767     runAssociatedApplication->setVisible(false);
01768     runAssociatedApplication->setEnabled(false);
01769     runAssociatedApplication->setData(AbstractToolBox::ControlTool);
01770 
01771     return actions;
01772 }
01773 
01774 bool Applet::eventFilter(QObject *o, QEvent *e)
01775 {
01776     return QObject::eventFilter(o, e);
01777 }
01778 
01779 bool Applet::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
01780 {
01781     if (watched == this) {
01782         switch (event->type()) {
01783             case QEvent::GraphicsSceneHoverEnter:
01784                 //kDebug() << "got hoverenterEvent" << immutability() << " " << immutability();
01785                 if (immutability() == Mutable) {
01786                     QGraphicsWidget *pw = this;
01787                     //This is for the rare case of applet in applet (systray)
01788                     //if the applet is in an applet that is not a containment, don't create the handle BUG:301648
01789                     while (pw = pw->parentWidget()) {
01790                         if (qobject_cast<Containment *>(pw)) {
01791                             break;
01792                         } else if (qobject_cast<Applet *>(pw)) {
01793                             return false;
01794                         }
01795                     }
01796 
01797                     QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
01798                     if (d->handle) {
01799                         d->handle.data()->setHoverPos(he->pos());
01800                     } else {
01801                         //kDebug() << "generated applet handle";
01802                         AppletHandle *handle = new AppletHandle(containment(), this, he->pos());
01803                         connect(handle, SIGNAL(disappearDone(AppletHandle*)),
01804                                 this, SLOT(handleDisappeared(AppletHandle*)));
01805                         connect(this, SIGNAL(geometryChanged()),
01806                                 handle, SLOT(appletResized()));
01807                         d->handle = handle;
01808                     }
01809                 }
01810             break;
01811 
01812             case QEvent::GraphicsSceneHoverMove:
01813                 if (d->handle && !d->handle.data()->shown() && immutability() == Mutable) {
01814                     QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
01815                     d->handle.data()->setHoverPos(he->pos());
01816                 }
01817             break;
01818 
01819         default:
01820             break;
01821         }
01822 
01823     }
01824 
01825     switch (event->type()) {
01826     case QEvent::GraphicsSceneMouseMove:
01827     case QEvent::GraphicsSceneMousePress:
01828     case QEvent::GraphicsSceneMouseRelease:
01829     {
01830         // don't move when the containment is not mutable,
01831         // in the rare case the containment doesn't exists consider it as mutable
01832         if ((flags() & ItemIsMovable) && d->registeredAsDragHandle.contains(watched)) {
01833             Containment *c = containment();
01834             if (!c || c->immutability() == Mutable) {
01835                 scene()->sendEvent(this, event);
01836                 return false;
01837             }
01838         }
01839         break;
01840     }
01841 
01842     default:
01843         break;
01844     }
01845 
01846     return QGraphicsItem::sceneEventFilter(watched, event);
01847 }
01848 
01849 void Applet::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
01850 {
01851     if (immutability() == Mutable && formFactor() == Plasma::Planar && (flags() & ItemIsMovable)) {
01852         QGraphicsWidget::mouseMoveEvent(event);
01853     }
01854 }
01855 
01856 void Applet::focusInEvent(QFocusEvent *event)
01857 {
01858     if (!isContainment() && containment()) {
01859         //focusing an applet may trigger this event again, but we won't be here more than twice
01860         containment()->d->focusApplet(this);
01861     }
01862 
01863     QGraphicsWidget::focusInEvent(event);
01864 }
01865 
01866 void Applet::resizeEvent(QGraphicsSceneResizeEvent *event)
01867 {
01868     QGraphicsWidget::resizeEvent(event);
01869 
01870     if (d->background) {
01871         d->background->resizeFrame(boundingRect().size());
01872     }
01873 
01874     updateConstraints(Plasma::SizeConstraint);
01875 
01876     d->scheduleModificationNotification();
01877     emit geometryChanged();
01878 }
01879 
01880 bool Applet::isUserConfiguring() const
01881 {
01882     return KConfigDialog::exists(d->configDialogId());
01883 }
01884 
01885 void Applet::showConfigurationInterface()
01886 {
01887     if (!hasConfigurationInterface()) {
01888         return;
01889     }
01890 
01891     if (immutability() != Mutable && !KAuthorized::authorize("plasma/allow_configure_when_locked")) {
01892         return;
01893     }
01894 
01895     KConfigDialog *dlg = KConfigDialog::exists(d->configDialogId());
01896 
01897     if (dlg) {
01898         KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
01899         dlg->show();
01900         KWindowSystem::activateWindow(dlg->winId());
01901         return;
01902     }
01903 
01904     d->publishUI.publishCheckbox = 0;
01905     if (d->package) {
01906         KConfigDialog *dialog = 0;
01907 
01908         const QString uiFile = d->package->filePath("mainconfigui");
01909         KDesktopFile df(d->package->path() + "/metadata.desktop");
01910         const QStringList kcmPlugins = df.desktopGroup().readEntry("X-Plasma-ConfigPlugins", QStringList());
01911         if (!uiFile.isEmpty() || !kcmPlugins.isEmpty()) {
01912             KConfigSkeleton *configLoader = d->configLoader ? d->configLoader : new KConfigSkeleton(0);
01913             dialog = new AppletConfigDialog(0, d->configDialogId(), configLoader);
01914 
01915             if (!d->configLoader) {
01916                 // delete the temporary when this dialog is done
01917                 configLoader->setParent(dialog);
01918             }
01919 
01920             dialog->setWindowTitle(d->configWindowTitle());
01921             dialog->setAttribute(Qt::WA_DeleteOnClose, true);
01922             bool hasPages = false;
01923 
01924             QFile f(uiFile);
01925             QUiLoader loader;
01926             QWidget *w = loader.load(&f);
01927             if (w) {
01928                 dialog->addPage(w, i18n("Settings"), icon(), i18n("%1 Settings", name()));
01929                 hasPages = true;
01930             }
01931 
01932             foreach (const QString &kcm, kcmPlugins) {
01933 #ifndef PLASMA_NO_KUTILS
01934                 KCModuleProxy *module = new KCModuleProxy(kcm);
01935                 if (module->realModule()) {
01936                     //preemptively load modules to prevent save() crashing on some kcms, like powerdevil ones
01937                     module->load();
01938                     connect(module, SIGNAL(changed(bool)), dialog, SLOT(settingsModified(bool)));
01939                     connect(dialog, SIGNAL(okClicked()),
01940                             module->realModule(), SLOT(save()));
01941                     connect(dialog, SIGNAL(applyClicked()),
01942                             module->realModule(), SLOT(save()));
01943                     dialog->addPage(module, module->moduleInfo().moduleName(), module->moduleInfo().icon());
01944                     hasPages = true;
01945                 } else {
01946                     delete module;
01947                 }
01948 #else
01949                 KService::Ptr service = KService::serviceByStorageId(kcm);
01950                 if (service) {
01951                     QString error;
01952                     KCModule *module = service->createInstance<KCModule>(dialog, QVariantList(), &error);
01953                     if (module) {
01954                         module->load();
01955                         connect(module, SIGNAL(changed(bool)), dialog, SLOT(settingsModified(bool)));
01956                         connect(dialog, SIGNAL(okClicked()),
01957                                 module, SLOT(save()));
01958                         connect(dialog, SIGNAL(applyClicked()), 
01959                                 module, SLOT(save()));
01960                         dialog->addPage(module, service->name(), service->icon());
01961                         hasPages = true;
01962                     } else {
01963 #ifndef NDEBUG
01964                         kDebug() << "failed to load kcm" << kcm << "for" << name();
01965 #endif
01966                     }
01967                 }
01968 #endif
01969             }
01970 
01971             if (hasPages) {
01972                 d->addGlobalShortcutsPage(dialog);
01973                 d->addPublishPage(dialog);
01974                 dialog->show();
01975             } else {
01976                 delete dialog;
01977                 dialog = 0;
01978             }
01979         }
01980 
01981         if (!dialog && d->script) {
01982             d->script->showConfigurationInterface();
01983         }
01984     } else if (d->script) {
01985         d->script->showConfigurationInterface();
01986     } else {
01987         KConfigDialog *dialog = d->generateGenericConfigDialog();
01988         d->addStandardConfigurationPages(dialog);
01989         showConfigurationInterface(dialog);
01990     }
01991 
01992     emit releaseVisualFocus();
01993 }
01994 
01995 void Applet::showConfigurationInterface(QWidget *widget)
01996 {
01997     if (!containment() || !containment()->corona() ||
01998         !containment()->corona()->dialogManager()) {
01999         widget->show();
02000         return;
02001     }
02002 
02003     QMetaObject::invokeMethod(containment()->corona()->dialogManager(), "showDialog", Q_ARG(QWidget *, widget), Q_ARG(Plasma::Applet *, this));
02004 }
02005 
02006 QString AppletPrivate::configDialogId() const
02007 {
02008     return QString("%1settings%2").arg(appletId).arg(q->name());
02009 }
02010 
02011 QString AppletPrivate::configWindowTitle() const
02012 {
02013     return i18nc("@title:window", "%1 Settings", q->name());
02014 }
02015 
02016 QSet<QString> AppletPrivate::knownCategories()
02017 {
02018     // this is to trick the tranlsation tools into making the correct
02019     // strings for translation
02020     QSet<QString> categories = s_customCategories;
02021     categories << QString(I18N_NOOP("Accessibility")).toLower()
02022                << QString(I18N_NOOP("Application Launchers")).toLower()
02023                << QString(I18N_NOOP("Astronomy")).toLower()
02024                << QString(I18N_NOOP("Date and Time")).toLower()
02025                << QString(I18N_NOOP("Development Tools")).toLower()
02026                << QString(I18N_NOOP("Education")).toLower()
02027                << QString(I18N_NOOP("Environment and Weather")).toLower()
02028                << QString(I18N_NOOP("Examples")).toLower()
02029                << QString(I18N_NOOP("File System")).toLower()
02030                << QString(I18N_NOOP("Fun and Games")).toLower()
02031                << QString(I18N_NOOP("Graphics")).toLower()
02032                << QString(I18N_NOOP("Language")).toLower()
02033                << QString(I18N_NOOP("Mapping")).toLower()
02034                << QString(I18N_NOOP("Miscellaneous")).toLower()
02035                << QString(I18N_NOOP("Multimedia")).toLower()
02036                << QString(I18N_NOOP("Online Services")).toLower()
02037                << QString(I18N_NOOP("Productivity")).toLower()
02038                << QString(I18N_NOOP("System Information")).toLower()
02039                << QString(I18N_NOOP("Utilities")).toLower()
02040                << QString(I18N_NOOP("Windows and Tasks")).toLower();
02041     return categories;
02042 }
02043 
02044 KConfigDialog *AppletPrivate::generateGenericConfigDialog()
02045 {
02046     KConfigSkeleton *nullManager = new KConfigSkeleton(0);
02047     KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager);
02048     nullManager->setParent(dialog);
02049     dialog->setFaceType(KPageDialog::Auto);
02050     dialog->setWindowTitle(configWindowTitle());
02051     dialog->setAttribute(Qt::WA_DeleteOnClose, true);
02052     q->createConfigurationInterface(dialog);
02053     dialog->showButton(KDialog::Default, false);
02054     dialog->showButton(KDialog::Help, false);
02055     QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()));
02056     QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()));
02057     return dialog;
02058 }
02059 
02060 void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog)
02061 {
02062     addGlobalShortcutsPage(dialog);
02063     addPublishPage(dialog);
02064 }
02065 
02066 void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog)
02067 {
02068 #ifndef PLASMA_NO_GLOBAL_SHORTCUTS
02069     if (isContainment) {
02070         return;
02071     }
02072 
02073     QWidget *page = new QWidget;
02074     QVBoxLayout *layout = new QVBoxLayout(page);
02075 
02076     if (!shortcutEditor) {
02077         shortcutEditor = new KKeySequenceWidget(page);
02078         QObject::connect(shortcutEditor.data(), SIGNAL(keySequenceChanged(QKeySequence)), dialog, SLOT(settingsModified()));
02079     }
02080 
02081     shortcutEditor.data()->setKeySequence(q->globalShortcut().primary());
02082     layout->addWidget(shortcutEditor.data());
02083     layout->addStretch();
02084     dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard");
02085 
02086     QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
02087     QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
02088 #endif
02089 }
02090 
02091 void AppletPrivate::addPublishPage(KConfigDialog *dialog)
02092 {
02093 #ifdef ENABLE_REMOTE_WIDGETS
02094     QWidget *page = new QWidget;
02095     publishUI.setupUi(page);
02096     publishUI.publishCheckbox->setChecked(q->isPublished());
02097     QObject::connect(publishUI.publishCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
02098     publishUI.allUsersCheckbox->setEnabled(q->isPublished());
02099     QObject::connect(publishUI.allUsersCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
02100 
02101     QString resourceName =
02102     i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
02103           "%1 on %2", q->name(), QHostInfo::localHostName());
02104     if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
02105         publishUI.allUsersCheckbox->setChecked(true);
02106     } else {
02107         publishUI.allUsersCheckbox->setChecked(false);
02108     }
02109 
02110     q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)),
02111                q, SLOT(publishCheckboxStateChanged(int)));
02112     dialog->addPage(page, i18n("Share"), "applications-internet");
02113 #endif
02114 }
02115 
02116 void AppletPrivate::publishCheckboxStateChanged(int state)
02117 {
02118     if (state == Qt::Checked) {
02119         publishUI.allUsersCheckbox->setEnabled(true);
02120     } else {
02121         publishUI.allUsersCheckbox->setEnabled(false);
02122     }
02123 }
02124 
02125 void AppletPrivate::configDialogFinished()
02126 {
02127     if (shortcutEditor) {
02128         QKeySequence sequence = shortcutEditor.data()->keySequence();
02129         if (sequence != q->globalShortcut().primary()) {
02130             q->setGlobalShortcut(KShortcut(sequence));
02131             emit q->configNeedsSaving();
02132         }
02133     }
02134 
02135 #ifdef ENABLE_REMOTE_WIDGETS
02136     if (KConfigDialog::exists(configDialogId()) && publishUI.publishCheckbox) {
02137         q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked());
02138 
02139         if (publishUI.publishCheckbox->isChecked()) {
02140             QString resourceName =
02141                 i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
02142                         "%1 on %2", q->name(), QHostInfo::localHostName());
02143             q->publish(Plasma::ZeroconfAnnouncement, resourceName);
02144             if (publishUI.allUsersCheckbox->isChecked()) {
02145                 if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
02146                     AuthorizationRule *rule = new AuthorizationRule(resourceName, "");
02147                     rule->setPolicy(AuthorizationRule::Allow);
02148                     rule->setTargets(AuthorizationRule::AllUsers);
02149                     AuthorizationManager::self()->d->rules.append(rule);
02150                 }
02151             } else {
02152                 AuthorizationRule *matchingRule =
02153                     AuthorizationManager::self()->d->matchingRule(resourceName, Credentials());
02154                 if (matchingRule) {
02155                     AuthorizationManager::self()->d->rules.removeAll(matchingRule);
02156                 }
02157             }
02158         } else {
02159             q->unpublish();
02160         }
02161     }
02162 #endif
02163 
02164     if (!configLoader) {
02165         // the config loader will trigger this for us, so we don't need to.
02166         propagateConfigChanged();
02167         if (KConfigDialog *dialog = qobject_cast<KConfigDialog *>(q->sender())) {
02168             dialog->enableButton(KDialog::Apply, false);
02169         }
02170     }
02171 }
02172 
02173 void AppletPrivate::updateShortcuts()
02174 {
02175     if (isContainment) {
02176         //a horrible hack to avoid clobbering corona settings
02177         //we pull them out, then read, then put them back
02178         QList<QString> names;
02179         QList<QAction*> qactions;
02180         names << "add sibling containment" << "configure shortcuts" << "lock widgets";
02181         foreach (const QString &name, names) {
02182             QAction *a = actions->action(name);
02183             actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method
02184             qactions << a;
02185         }
02186 
02187         actions->readSettings();
02188 
02189         for (int i = 0; i < names.size(); ++i) {
02190             QAction *a = qactions.at(i);
02191             if (a) {
02192                 actions->addAction(names.at(i), a);
02193             }
02194         }
02195     } else {
02196         actions->readSettings();
02197     }
02198 }
02199 
02200 void AppletPrivate::propagateConfigChanged()
02201 {
02202     if (isContainment) {
02203         Containment *c = qobject_cast<Containment *>(q);
02204         if (c) {
02205             c->d->configChanged();
02206         }
02207     }
02208 
02209     q->configChanged();
02210 }
02211 
02212 void Applet::configChanged()
02213 {
02214     if (d->script) {
02215         if (d->configLoader) {
02216             d->configLoader->readConfig();
02217         }
02218         d->script->configChanged();
02219     }
02220 }
02221 
02222 void Applet::createConfigurationInterface(KConfigDialog *parent)
02223 {
02224     Q_UNUSED(parent)
02225     // virtual method reimplemented by subclasses.
02226     // do not put anything here ...
02227 }
02228 
02229 bool Applet::hasAuthorization(const QString &constraint) const
02230 {
02231     KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
02232     return constraintGroup.readEntry(constraint, true);
02233 }
02234 
02235 void Applet::setAssociatedApplication(const QString &string)
02236 {
02237     AssociatedApplicationManager::self()->setApplication(this, string);
02238 
02239     QAction *runAssociatedApplication = d->actions->action("run associated application");
02240     if (runAssociatedApplication) {
02241         bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02242         valid = valid && hasAuthorization("LaunchApp"); //obey security!
02243         runAssociatedApplication->setVisible(valid);
02244         runAssociatedApplication->setEnabled(valid);
02245     }
02246 }
02247 
02248 void Applet::setAssociatedApplicationUrls(const KUrl::List &urls)
02249 {
02250     AssociatedApplicationManager::self()->setUrls(this, urls);
02251 
02252     QAction *runAssociatedApplication = d->actions->action("run associated application");
02253     if (runAssociatedApplication) {
02254         bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02255         valid = valid && hasAuthorization("LaunchApp"); //obey security!
02256         runAssociatedApplication->setVisible(valid);
02257         runAssociatedApplication->setEnabled(valid);
02258     }
02259 }
02260 
02261 QString Applet::associatedApplication() const
02262 {
02263     return AssociatedApplicationManager::self()->application(this);
02264 }
02265 
02266 KUrl::List Applet::associatedApplicationUrls() const
02267 {
02268     return AssociatedApplicationManager::self()->urls(this);
02269 }
02270 
02271 void Applet::runAssociatedApplication()
02272 {
02273     if (hasAuthorization("LaunchApp")) {
02274         AssociatedApplicationManager::self()->run(this);
02275     }
02276 }
02277 
02278 bool Applet::hasValidAssociatedApplication() const
02279 {
02280     return AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02281 }
02282 
02283 void AppletPrivate::filterOffers(QList<KService::Ptr> &offers)
02284 {
02285     KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
02286     foreach (const QString &key, constraintGroup.keyList()) {
02287         //kDebug() << "security constraint" << key;
02288         if (constraintGroup.readEntry(key, true)) {
02289             continue;
02290         }
02291 
02292         //ugh. a qlist of ksharedptr<kservice>
02293         QMutableListIterator<KService::Ptr> it(offers);
02294         while (it.hasNext()) {
02295             KService::Ptr p = it.next();
02296             QString prop = QString("X-Plasma-Requires-").append(key);
02297             QVariant req = p->property(prop, QVariant::String);
02298             //valid values: Required/Optional/Unused
02299             QString reqValue;
02300             if (req.isValid()) {
02301                 reqValue = req.toString();
02302             } else if (p->property("X-Plasma-API").toString().toLower() == "javascript") {
02303                 //TODO: be able to check whether or not a script engine provides "controled"
02304                 //bindings; for now we just give a pass to the qscript ones
02305                 reqValue = "Unused";
02306             }
02307 
02308             if (!(reqValue == "Optional" || reqValue == "Unused")) {
02309             //if (reqValue == "Required") {
02310                 it.remove();
02311             }
02312         }
02313     }
02314 }
02315 
02316 QString AppletPrivate::parentAppConstraint(const QString &parentApp)
02317 {
02318     if (parentApp.isEmpty()) {
02319         return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')")
02320                       .arg(KGlobal::mainComponent().aboutData()->appName());
02321     }
02322 
02323     return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp);
02324 }
02325 
02326 KPluginInfo::List Applet::listAppletInfo(const QString &category, const QString &parentApp)
02327 {
02328    return PluginLoader::pluginLoader()->listAppletInfo(category, parentApp);
02329 }
02330 
02331 KPluginInfo::List Applet::listAppletInfoForMimetype(const QString &mimetype)
02332 {
02333     QString constraint = AppletPrivate::parentAppConstraint();
02334     constraint.append(QString(" and '%1' in [X-Plasma-DropMimeTypes]").arg(mimetype));
02335     //kDebug() << "listAppletInfoForMimetype with" << mimetype << constraint;
02336     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02337     AppletPrivate::filterOffers(offers);
02338     return KPluginInfo::fromServices(offers);
02339 }
02340 
02341 KPluginInfo::List Applet::listAppletInfoForUrl(const QUrl &url)
02342 {
02343     QString constraint = AppletPrivate::parentAppConstraint();
02344     constraint.append(" and exist [X-Plasma-DropUrlPatterns]");
02345     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02346     AppletPrivate::filterOffers(offers);
02347 
02348     KPluginInfo::List allApplets = KPluginInfo::fromServices(offers);
02349     KPluginInfo::List filtered;
02350     foreach (const KPluginInfo &info, allApplets) {
02351         QStringList urlPatterns = info.property("X-Plasma-DropUrlPatterns").toStringList();
02352         foreach (const QString &glob, urlPatterns) {
02353             QRegExp rx(glob);
02354             rx.setPatternSyntax(QRegExp::Wildcard);
02355             if (rx.exactMatch(url.toString())) {
02356                 kDebug() << info.name() << "matches" << glob << url;
02357                 filtered << info;
02358             }
02359         }
02360     }
02361 
02362     return filtered;
02363 }
02364 
02365 QStringList Applet::listCategories(const QString &parentApp, bool visibleOnly)
02366 {
02367     QString constraint = AppletPrivate::parentAppConstraint(parentApp);
02368     constraint.append(" and exist [X-KDE-PluginInfo-Category]");
02369 
02370     KConfigGroup group(KGlobal::config(), "General");
02371     const QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
02372     foreach (const QString &category, excluded) {
02373         constraint.append(" and [X-KDE-PluginInfo-Category] != '").append(category).append("'");
02374     }
02375 
02376     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02377     AppletPrivate::filterOffers(offers);
02378 
02379     QStringList categories;
02380     QSet<QString> known = AppletPrivate::knownCategories();
02381     foreach (const KService::Ptr &applet, offers) {
02382         QString appletCategory = applet->property("X-KDE-PluginInfo-Category").toString();
02383         if (visibleOnly && applet->noDisplay()) {
02384             // we don't want to show the hidden category
02385             continue;
02386         }
02387 
02388         //kDebug() << "   and we have " << appletCategory;
02389         if (!appletCategory.isEmpty() && !known.contains(appletCategory.toLower())) {
02390             kDebug() << "Unknown category: " << applet->name() << "says it is in the"
02391                      << appletCategory << "category which is unknown to us";
02392             appletCategory.clear();
02393         }
02394 
02395         if (appletCategory.isEmpty()) {
02396             if (!categories.contains(i18nc("misc category", "Miscellaneous"))) {
02397                 categories << i18nc("misc category", "Miscellaneous");
02398             }
02399         } else  if (!categories.contains(appletCategory)) {
02400             categories << appletCategory;
02401         }
02402     }
02403 
02404     categories.sort();
02405     return categories;
02406 }
02407 
02408 void Applet::setCustomCategories(const QStringList &categories)
02409 {
02410     AppletPrivate::s_customCategories = QSet<QString>::fromList(categories);
02411 }
02412 
02413 QStringList Applet::customCategories()
02414 {
02415     return AppletPrivate::s_customCategories.toList();
02416 }
02417 
02418 Applet *Applet::loadPlasmoid(const QString &path, uint appletId, const QVariantList &args)
02419 {
02420     if (QFile::exists(path + "/metadata.desktop")) {
02421         KService service(path + "/metadata.desktop");
02422         const QStringList& types = service.serviceTypes();
02423 
02424         if (types.contains("Plasma/Containment")) {
02425             return new Containment(path, appletId, args);
02426         } else if (types.contains("Plasma/PopupApplet")) {
02427             return new PopupApplet(path, appletId, args);
02428         } else {
02429             return new Applet(path, appletId, args);
02430         }
02431     }
02432 
02433     return 0;
02434 }
02435 
02436 Applet *Applet::load(const QString &appletName, uint appletId, const QVariantList &args)
02437 {
02438     return PluginLoader::pluginLoader()->loadApplet(appletName, appletId, args);
02439 }
02440 
02441 Applet *Applet::load(const KPluginInfo &info, uint appletId, const QVariantList &args)
02442 {
02443     if (!info.isValid()) {
02444         return 0;
02445     }
02446 
02447     return load(info.pluginName(), appletId, args);
02448 }
02449 
02450 QVariant Applet::itemChange(GraphicsItemChange change, const QVariant &value)
02451 {
02452     QVariant ret = QGraphicsWidget::itemChange(change, value);
02453 
02454     //kDebug() << change;
02455     switch (change) {
02456     case ItemSceneHasChanged: {
02457         Corona *newCorona = qobject_cast<Corona *>(qvariant_cast<QGraphicsScene*>(value));
02458         if (newCorona && newCorona->immutability() != Mutable) {
02459             updateConstraints(ImmutableConstraint);
02460         }
02461     }
02462         break;
02463     case ItemParentChange:
02464         if (!d->isContainment) {
02465             Containment *c = containment();
02466             if (d->mainConfig && !c) {
02467                 kWarning() << "Configuration object was requested prior to init(), which is too early. "
02468                     "Please fix this item:" << parentItem() << value.value<QGraphicsItem *>()
02469                     << name();
02470 
02471                 Applet *newC = dynamic_cast<Applet*>(value.value<QGraphicsItem *>());
02472                 if (newC) {
02473                     // if this is an applet, and we've just been assigned to our first containment,
02474                     // but the applet did something stupid like ask for the config() object prior to
02475                     // this happening (e.g. inits ctor) then let's repair that situation for them.
02476                     KConfigGroup *old = d->mainConfig;
02477                     KConfigGroup appletConfig = newC->config();
02478                     appletConfig = KConfigGroup(&appletConfig, "Applets");
02479                     d->mainConfig = new KConfigGroup(&appletConfig, QString::number(d->appletId));
02480                     old->copyTo(d->mainConfig);
02481                     old->deleteGroup();
02482                     delete old;
02483                 }
02484             }
02485         }
02486         break;
02487     case ItemParentHasChanged:
02488         {
02489             if (isContainment()) {
02490                 removeSceneEventFilter(this);
02491             } else {
02492                 Containment *c = containment();
02493                 if (c && c->containmentType() == Containment::DesktopContainment) {
02494                     installSceneEventFilter(this);
02495                 } else {
02496                     removeSceneEventFilter(this);
02497                 }
02498             }
02499         }
02500         break;
02501     case ItemPositionHasChanged:
02502         emit geometryChanged();
02503         // fall through!
02504     case ItemTransformHasChanged:
02505         d->scheduleModificationNotification();
02506         break;
02507     default:
02508         break;
02509     };
02510 
02511     return ret;
02512 }
02513 
02514 QPainterPath Applet::shape() const
02515 {
02516     if (d->script) {
02517         return d->script->shape();
02518     }
02519 
02520     return QGraphicsWidget::shape();
02521 }
02522 
02523 QSizeF Applet::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
02524 {
02525     QSizeF hint = QGraphicsWidget::sizeHint(which, constraint);
02526     const FormFactor ff = formFactor();
02527 
02528     // in panels make sure that the contents won't exit from the panel
02529     if (which == Qt::MinimumSize) {
02530         if (ff == Horizontal) {
02531             hint.setHeight(0);
02532         } else if (ff == Vertical) {
02533             hint.setWidth(0);
02534         }
02535     }
02536 
02537     // enforce a square size in panels
02538     if (d->aspectRatioMode == Plasma::Square) {
02539         if (ff == Horizontal) {
02540             hint.setWidth(size().height());
02541         } else if (ff == Vertical) {
02542             hint.setHeight(size().width());
02543         }
02544     } else if (d->aspectRatioMode == Plasma::ConstrainedSquare) {
02545         //enforce a size not wider than tall
02546         if (ff == Horizontal) {
02547             hint.setWidth(size().height());
02548         //enforce a size not taller than wide
02549         } else if (ff == Vertical && (which == Qt::MaximumSize || size().width() <= KIconLoader::SizeLarge)) {
02550             hint.setHeight(size().width());
02551         }
02552     }
02553 
02554     return hint;
02555 }
02556 
02557 void Applet::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
02558 {
02559     Q_UNUSED(event)
02560 }
02561 
02562 void Applet::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
02563 {
02564     Q_UNUSED(event)
02565 }
02566 
02567 void Applet::timerEvent(QTimerEvent *event)
02568 {
02569     if (d->transient) {
02570         d->constraintsTimer.stop();
02571         d->busyWidgetTimer.stop();
02572         if (d->modificationsTimer) {
02573             d->modificationsTimer->stop();
02574         }
02575         return;
02576     }
02577 
02578     if (event->timerId() == d->constraintsTimer.timerId()) {
02579         d->constraintsTimer.stop();
02580 
02581         // Don't flushPendingConstraints if we're just starting up
02582         // flushPendingConstraints will be called by Corona
02583         if(!(d->pendingConstraints & Plasma::StartupCompletedConstraint)) {
02584             flushPendingConstraintsEvents();
02585         }
02586     } else if (d->modificationsTimer && event->timerId() == d->modificationsTimer->timerId()) {
02587         d->modificationsTimer->stop();
02588         // invalid group, will result in save using the default group
02589         KConfigGroup cg;
02590 
02591         save(cg);
02592         emit configNeedsSaving();
02593     } else if (event->timerId() == d->busyWidgetTimer.timerId()) {
02594         if (!d->busyWidget) {
02595             d->createMessageOverlay(false);
02596             d->messageOverlay->opacity = 0;
02597 
02598             QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(d->messageOverlay);
02599             d->busyWidget = new Plasma::BusyWidget(d->messageOverlay);
02600             d->busyWidget->setAcceptHoverEvents(false);
02601             d->busyWidget->setAcceptedMouseButtons(Qt::NoButton);
02602             d->messageOverlay->setAcceptHoverEvents(false);
02603             d->messageOverlay->setAcceptedMouseButtons(Qt::NoButton);
02604 
02605             mainLayout->addStretch();
02606             mainLayout->addItem(d->busyWidget);
02607             mainLayout->addStretch();
02608         }
02609     }
02610 }
02611 
02612 QRect Applet::screenRect() const
02613 {
02614     QGraphicsView *v = view();
02615 
02616     if (v) {
02617         QPointF bottomRight = pos();
02618         bottomRight.rx() += size().width();
02619         bottomRight.ry() += size().height();
02620 
02621         QPoint tL = v->mapToGlobal(v->mapFromScene(pos()));
02622         QPoint bR = v->mapToGlobal(v->mapFromScene(bottomRight));
02623         return QRect(QPoint(tL.x(), tL.y()), QSize(bR.x() - tL.x(), bR.y() - tL.y()));
02624     }
02625 
02626     //The applet doesn't have a view on it.
02627     //So a screenRect isn't relevant.
02628     return QRect(QPoint(0, 0), QSize(0, 0));
02629 }
02630 
02631 void Applet::raise()
02632 {
02633     setZValue(++AppletPrivate::s_maxZValue);
02634 }
02635 
02636 void Applet::lower()
02637 {
02638     setZValue(--AppletPrivate::s_minZValue);
02639 }
02640 
02641 void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate)
02642 {
02643     if (isContainment == nowIsContainment && !forceUpdate) {
02644         return;
02645     }
02646 
02647     isContainment = nowIsContainment;
02648     //FIXME I do not like this function.
02649     //currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way.
02650     //if someone calls it at some other time it'll cause headaches. :P
02651 
02652     delete mainConfig;
02653     mainConfig = 0;
02654 
02655     Containment *c = q->containment();
02656     if (c) {
02657         c->d->checkContainmentFurniture();
02658     }
02659 }
02660 
02661 bool Applet::isContainment() const
02662 {
02663     return d->isContainment;
02664 }
02665 
02666 // PRIVATE CLASS IMPLEMENTATION
02667 
02668 AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet)
02669         : appletId(uniqueID),
02670           q(applet),
02671           service(0),
02672           preferredBackgroundHints(Applet::StandardBackground),
02673           backgroundHints(Applet::NoBackground),
02674           aspectRatioMode(Plasma::KeepAspectRatio),
02675           immutability(Mutable),
02676           appletDescription(info ? *info : KPluginInfo(service)),
02677           background(0),
02678           mainConfig(0),
02679           pendingConstraints(NoConstraint),
02680           messageOverlay(0),
02681           messageOverlayProxy(0),
02682           busyWidget(0),
02683           script(0),
02684           package(0),
02685           configLoader(0),
02686           actions(AppletPrivate::defaultActions(applet)),
02687           activationAction(0),
02688           itemStatus(UnknownStatus),
02689           preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored),
02690           modificationsTimer(0),
02691           hasConfigurationInterface(false),
02692           failed(false),
02693           isContainment(false),
02694           transient(false),
02695           needsConfig(false),
02696           started(false)
02697 {
02698     if (appletId == 0) {
02699         appletId = ++s_maxAppletId;
02700     } else if (appletId > s_maxAppletId) {
02701         s_maxAppletId = appletId;
02702     }
02703 }
02704 
02705 AppletPrivate::~AppletPrivate()
02706 {
02707     if (activationAction && activationAction->isGlobalShortcutEnabled()) {
02708         //kDebug() << "reseting global action for" << q->name() << activationAction->objectName();
02709         activationAction->forgetGlobalShortcut();
02710     }
02711 
02712     delete extender.data();
02713 
02714     delete script;
02715     script = 0;
02716     delete package;
02717     package = 0;
02718     delete configLoader;
02719     configLoader = 0;
02720     delete mainConfig;
02721     mainConfig = 0;
02722     delete modificationsTimer;
02723 }
02724 
02725 void AppletPrivate::init(const QString &packagePath)
02726 {
02727     // WARNING: do not access config() OR globalConfig() in this method!
02728     //          that requires a scene, which is not available at this point
02729     q->setCacheMode(Applet::DeviceCoordinateCache);
02730     q->setAcceptsHoverEvents(true);
02731     q->setFlag(QGraphicsItem::ItemIsFocusable, true);
02732     q->setFocusPolicy(Qt::ClickFocus);
02733     // FIXME: adding here because nothing seems to be doing it in QGraphicsView,
02734     // but it doesn't actually work anyways =/
02735     q->setLayoutDirection(qApp->layoutDirection());
02736 
02737     //set a default size before any saved settings are read
02738     QSize size(200, 200);
02739     q->setBackgroundHints(Applet::DefaultBackground);
02740     q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor?
02741 
02742     QAction *closeApplet = actions->action("remove");
02743     if (closeApplet) {
02744         closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name()));
02745     }
02746 
02747     QAction *configAction = actions->action("configure");
02748     if (configAction) {
02749         configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name()));
02750     }
02751 
02752     QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus()));
02753     if (!appletDescription.isValid()) {
02754         kDebug() << "Check your constructor! "
02755                  << "You probably want to be passing in a Service::Ptr "
02756                  << "or a QVariantList with a valid storageid as arg[0].";
02757         q->resize(size);
02758         return;
02759     }
02760 
02761     QVariant s = appletDescription.property("X-Plasma-DefaultSize");
02762     if (s.isValid()) {
02763         size = s.toSize();
02764     }
02765     //kDebug() << "size" << size;
02766     q->resize(size);
02767 
02768     QString api = appletDescription.property("X-Plasma-API").toString();
02769 
02770     // we have a scripted plasmoid
02771     if (!api.isEmpty()) {
02772         // find where the Package is
02773         QString path = packagePath;
02774         if (path.isEmpty()) {
02775             QString subPath = q->packageStructure()->defaultPackageRoot() + '/' + appletDescription.pluginName() + '/';
02776             path = KStandardDirs::locate("data", subPath + "metadata.desktop");
02777             if (path.isEmpty()) {
02778                 path = KStandardDirs::locate("data", subPath);
02779             } else {
02780                 path.remove(QString("metadata.desktop"));
02781             }
02782         } else if (!path.endsWith('/')) {
02783             path.append('/');
02784         }
02785 
02786         if (path.isEmpty()) {
02787             q->setFailedToLaunch(
02788                 true,
02789                 i18nc("Package file, name of the widget",
02790                       "Could not locate the %1 package required for the %2 widget.",
02791                       appletDescription.pluginName(), appletDescription.name()));
02792         } else {
02793             // create the package and see if we have something real
02794             //kDebug() << "trying for" << path;
02795             PackageStructure::Ptr structure = Plasma::packageStructure(api, Plasma::AppletComponent);
02796             structure->setPath(path);
02797             package = new Package(path, structure);
02798 
02799             if (package->isValid()) {
02800                 // now we try and set up the script engine.
02801                 // it will be parented to this applet and so will get
02802                 // deleted when the applet does
02803 
02804                 script = Plasma::loadScriptEngine(api, q);
02805                 if (!script) {
02806                     delete package;
02807                     package = 0;
02808                     q->setFailedToLaunch(true,
02809                                          i18nc("API or programming language the widget was written in, name of the widget",
02810                                                "Could not create a %1 ScriptEngine for the %2 widget.",
02811                                                api, appletDescription.name()));
02812                 }
02813             } else {
02814                 q->setFailedToLaunch(true, i18nc("Package file, name of the widget",
02815                                                  "Could not open the %1 package required for the %2 widget.",
02816                                                  appletDescription.pluginName(), appletDescription.name()));
02817                 delete package;
02818                 package = 0;
02819             }
02820         }
02821     }
02822 }
02823 
02824 // put all setup routines for script here. at this point we can assume that
02825 // package exists and that we have a script engine
02826 void AppletPrivate::setupScriptSupport()
02827 {
02828     if (!package) {
02829         return;
02830     }
02831 
02832     kDebug() << "setting up script support, package is in" << package->path()
02833              << "which is a" << package->structure()->type() << "package"
02834              << ", main script is" << package->filePath("mainscript");
02835 
02836     QString translationsPath = package->filePath("translations");
02837     if (!translationsPath.isEmpty()) {
02838         //FIXME: we should _probably_ use a KComponentData to segregate the applets
02839         //       from each other; but I want to get the basics working first :)
02840         KGlobal::dirs()->addResourceDir("locale", translationsPath);
02841         KGlobal::locale()->insertCatalog(package->metadata().pluginName());
02842     }
02843 
02844     QString xmlPath = package->filePath("mainconfigxml");
02845     if (!xmlPath.isEmpty()) {
02846         QFile file(xmlPath);
02847         KConfigGroup config = q->config();
02848         configLoader = new ConfigLoader(&config, &file);
02849         QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged()));
02850     }
02851 
02852     if (!package->filePath("mainconfigui").isEmpty()) {
02853         q->setHasConfigurationInterface(true);
02854     }
02855 }
02856 
02857 QString AppletPrivate::globalName() const
02858 {
02859     if (!appletDescription.isValid()) {
02860         return QString();
02861     }
02862 
02863     return appletDescription.service()->library();
02864 }
02865 
02866 QString AppletPrivate::instanceName()
02867 {
02868     if (!appletDescription.isValid()) {
02869         return QString();
02870     }
02871 
02872     return appletDescription.service()->library() + QString::number(appletId);
02873 }
02874 
02875 void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c)
02876 {
02877     // Don't start up a timer if we're just starting up
02878     // flushPendingConstraints will be called by Corona
02879     if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) {
02880         constraintsTimer.start(0, q);
02881     }
02882 
02883     if (c & Plasma::StartupCompletedConstraint) {
02884         started = true;
02885     }
02886 
02887     pendingConstraints |= c;
02888 }
02889 
02890 void AppletPrivate::scheduleModificationNotification()
02891 {
02892     // modificationsTimer is not allocated until we get our notice of being started
02893     if (modificationsTimer) {
02894         // schedule a save
02895         if (modificationsTimer->isActive()) {
02896             modificationsTimer->stop();
02897         }
02898 
02899         modificationsTimer->start(1000, q);
02900     }
02901 }
02902 
02903 KConfigGroup *AppletPrivate::mainConfigGroup()
02904 {
02905     if (mainConfig) {
02906         return mainConfig;
02907     }
02908 
02909     bool newGroup = false;
02910     if (isContainment) {
02911         Corona *corona = qobject_cast<Corona*>(q->scene());
02912         KConfigGroup containmentConfig;
02913         //kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q;
02914 
02915         if (corona) {
02916             containmentConfig = KConfigGroup(corona->config(), "Containments");
02917         } else {
02918             containmentConfig =  KConfigGroup(KGlobal::config(), "Containments");
02919         }
02920 
02921         if (package && !containmentConfig.hasGroup(QString::number(appletId))) {
02922             newGroup = true;
02923         }
02924 
02925         mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId));
02926     } else {
02927         KConfigGroup appletConfig;
02928 
02929         Containment *c = q->containment();
02930         Applet *parentApplet = qobject_cast<Applet *>(q->parent());
02931         if (parentApplet && parentApplet != static_cast<Applet *>(c)) {
02932             // this applet is nested inside another applet! use it's config
02933             // as the parent group in the config
02934             appletConfig = parentApplet->config();
02935             appletConfig = KConfigGroup(&appletConfig, "Applets");
02936         } else if (c) {
02937             // applet directly in a Containment, as usual
02938             appletConfig = c->config();
02939             appletConfig = KConfigGroup(&appletConfig, "Applets");
02940         } else {
02941             kWarning() << "requesting config for" << q->name() << "without a containment!";
02942             appletConfig = KConfigGroup(KGlobal::config(), "Applets");
02943         }
02944 
02945         if (package && !appletConfig.hasGroup(QString::number(appletId))) {
02946             newGroup = true;
02947         }
02948 
02949         mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId));
02950     }
02951 
02952     if (newGroup) {
02953         //see if we have a default configuration in our package
02954         const QString defaultConfigFile = q->package()->filePath("defaultconfig");
02955         if (!defaultConfigFile.isEmpty()) {
02956             kDebug() << "copying default config: " << q->package()->filePath("defaultconfig");
02957             KConfigGroup defaultConfig(KSharedConfig::openConfig(defaultConfigFile)->group("Configuration"));
02958             defaultConfig.copyTo(mainConfig);
02959         }
02960     }
02961 
02962     return mainConfig;
02963 }
02964 
02965 QString AppletPrivate::visibleFailureText(const QString &reason)
02966 {
02967     QString text;
02968 
02969     if (reason.isEmpty()) {
02970         text = i18n("This object could not be created.");
02971     } else {
02972         text = i18n("This object could not be created for the following reason:<p><b>%1</b></p>", reason);
02973     }
02974 
02975     return text;
02976 }
02977 
02978 void AppletPrivate::themeChanged()
02979 {
02980     if (background) {
02981         //do again the translucent background fallback
02982         q->setBackgroundHints(backgroundHints);
02983 
02984         qreal left;
02985         qreal right;
02986         qreal top;
02987         qreal bottom;
02988         background->getMargins(left, top, right, bottom);
02989         q->setContentsMargins(left, right, top, bottom);
02990     }
02991     q->update();
02992 }
02993 
02994 void AppletPrivate::resetConfigurationObject()
02995 {
02996     // make sure mainConfigGroup exists in all cases
02997     mainConfigGroup();
02998 
02999     mainConfig->deleteGroup();
03000     delete mainConfig;
03001     mainConfig = 0;
03002 
03003     Corona * corona = qobject_cast<Corona*>(q->scene());
03004     if (corona) {
03005         corona->requireConfigSync();
03006     }
03007 }
03008 
03009 void AppletPrivate::handleDisappeared(AppletHandle *h)
03010 {
03011     if (h == handle.data()) {
03012         h->detachApplet();
03013         QGraphicsScene *scene = q->scene();
03014         if (scene && h->scene() == scene) {
03015             scene->removeItem(h);
03016         }
03017         h->deleteLater();
03018     }
03019 }
03020 
03021 void ContainmentPrivate::checkRemoveAction()
03022 {
03023     q->enableAction("remove", q->immutability() == Mutable);
03024 }
03025 
03026 
03027 uint AppletPrivate::s_maxAppletId = 0;
03028 int AppletPrivate::s_maxZValue = 0;
03029 int AppletPrivate::s_minZValue = 0;
03030 PackageStructure::Ptr AppletPrivate::packageStructure(0);
03031 QSet<QString> AppletPrivate::s_customCategories;
03032 
03033 AppletOverlayWidget::AppletOverlayWidget(QGraphicsWidget *parent)
03034     : QGraphicsWidget(parent),
03035       opacity(0.4)
03036 {
03037     resize(parent->size());
03038 }
03039 
03040 void AppletOverlayWidget::destroy()
03041 {
03042     Animation *anim = Plasma::Animator::create(Plasma::Animator::DisappearAnimation);
03043     if (anim) {
03044         connect(anim, SIGNAL(finished()), this, SLOT(overlayAnimationComplete()));
03045         anim->setTargetWidget(this);
03046         anim->start();
03047     } else {
03048         overlayAnimationComplete();
03049     }
03050 }
03051 
03052 void AppletOverlayWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
03053 {
03054     event->accept();
03055 }
03056 
03057 void AppletOverlayWidget::overlayAnimationComplete()
03058 {
03059     if (scene()) {
03060         scene()->removeItem(this);
03061     }
03062     deleteLater();
03063 }
03064 
03065 void AppletOverlayWidget::paint(QPainter *painter,
03066                                 const QStyleOptionGraphicsItem *option,
03067                                 QWidget *widget)
03068 {
03069     Q_UNUSED(option)
03070     Q_UNUSED(widget)
03071 
03072     if (qFuzzyCompare(1, 1+opacity)) {
03073         return;
03074     }
03075 
03076     QColor wash = Plasma::Theme::defaultTheme()->color(Theme::BackgroundColor);
03077     wash.setAlphaF(opacity);
03078 
03079     Applet *applet = qobject_cast<Applet *>(parentWidget());
03080 
03081 
03082     QPainterPath backgroundShape;
03083     if (!applet || applet->backgroundHints() & Applet::StandardBackground) {
03084         //FIXME: a resize here is nasty, but perhaps still better than an eventfilter just for that..
03085         if (parentWidget()->contentsRect().size() != size()) {
03086             resize(parentWidget()->contentsRect().size());
03087         }
03088         backgroundShape = PaintUtils::roundedRectangle(contentsRect(), 5);
03089     } else {
03090         backgroundShape = shape();
03091     }
03092 
03093     painter->setRenderHints(QPainter::Antialiasing);
03094     painter->fillPath(backgroundShape, wash);
03095 }
03096 
03097 #if QT_VERSION >= 0x040700
03098 // in QGraphicsWidget now; preserve BC by implementing it as a protected method
03099 void Applet::geometryChanged()
03100 {
03101     emit QGraphicsWidget::geometryChanged();
03102 }
03103 #endif
03104 
03105 } // Plasma namespace
03106 
03107 #include "applet.moc"
03108 #include "private/applet_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:30:42 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

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

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal