• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 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 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 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                     QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
01787                     if (d->handle) {
01788                         d->handle.data()->setHoverPos(he->pos());
01789                     } else {
01790                         //kDebug() << "generated applet handle";
01791                         AppletHandle *handle = new AppletHandle(containment(), this, he->pos());
01792                         connect(handle, SIGNAL(disappearDone(AppletHandle*)),
01793                                 this, SLOT(handleDisappeared(AppletHandle*)));
01794                         connect(this, SIGNAL(geometryChanged()),
01795                                 handle, SLOT(appletResized()));
01796                         d->handle = handle;
01797                     }
01798                 }
01799             break;
01800 
01801             case QEvent::GraphicsSceneHoverMove:
01802                 if (d->handle && !d->handle.data()->shown() && immutability() == Mutable) {
01803                     QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
01804                     d->handle.data()->setHoverPos(he->pos());
01805                 }
01806             break;
01807 
01808         default:
01809             break;
01810         }
01811 
01812     }
01813 
01814     switch (event->type()) {
01815     case QEvent::GraphicsSceneMouseMove:
01816     case QEvent::GraphicsSceneMousePress:
01817     case QEvent::GraphicsSceneMouseRelease:
01818     {
01819         // don't move when the containment is not mutable,
01820         // in the rare case the containment doesn't exists consider it as mutable
01821         if ((flags() & ItemIsMovable) && d->registeredAsDragHandle.contains(watched)) {
01822             Containment *c = containment();
01823             if (!c || c->immutability() == Mutable) {
01824                 scene()->sendEvent(this, event);
01825                 return false;
01826             }
01827         }
01828         break;
01829     }
01830 
01831     default:
01832         break;
01833     }
01834 
01835     return QGraphicsItem::sceneEventFilter(watched, event);
01836 }
01837 
01838 void Applet::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
01839 {
01840     if (immutability() == Mutable && formFactor() == Plasma::Planar && (flags() & ItemIsMovable)) {
01841         QGraphicsWidget::mouseMoveEvent(event);
01842     }
01843 }
01844 
01845 void Applet::focusInEvent(QFocusEvent *event)
01846 {
01847     if (!isContainment() && containment()) {
01848         //focusing an applet may trigger this event again, but we won't be here more than twice
01849         containment()->d->focusApplet(this);
01850     }
01851 
01852     QGraphicsWidget::focusInEvent(event);
01853 }
01854 
01855 void Applet::resizeEvent(QGraphicsSceneResizeEvent *event)
01856 {
01857     QGraphicsWidget::resizeEvent(event);
01858 
01859     if (d->background) {
01860         d->background->resizeFrame(boundingRect().size());
01861     }
01862 
01863     updateConstraints(Plasma::SizeConstraint);
01864 
01865     d->scheduleModificationNotification();
01866     emit geometryChanged();
01867 }
01868 
01869 bool Applet::isUserConfiguring() const
01870 {
01871     return KConfigDialog::exists(d->configDialogId());
01872 }
01873 
01874 void Applet::showConfigurationInterface()
01875 {
01876     if (!hasConfigurationInterface()) {
01877         return;
01878     }
01879 
01880     if (immutability() != Mutable && !KAuthorized::authorize("plasma/allow_configure_when_locked")) {
01881         return;
01882     }
01883 
01884     KConfigDialog *dlg = KConfigDialog::exists(d->configDialogId());
01885 
01886     if (dlg) {
01887         KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
01888         dlg->show();
01889         KWindowSystem::activateWindow(dlg->winId());
01890         return;
01891     }
01892 
01893     d->publishUI.publishCheckbox = 0;
01894     if (d->package) {
01895         KConfigDialog *dialog = 0;
01896 
01897         const QString uiFile = d->package->filePath("mainconfigui");
01898         KDesktopFile df(d->package->path() + "/metadata.desktop");
01899         const QStringList kcmPlugins = df.desktopGroup().readEntry("X-Plasma-ConfigPlugins", QStringList());
01900         if (!uiFile.isEmpty() || !kcmPlugins.isEmpty()) {
01901             KConfigSkeleton *configLoader = d->configLoader ? d->configLoader : new KConfigSkeleton(0);
01902             dialog = new AppletConfigDialog(0, d->configDialogId(), configLoader);
01903 
01904             if (!d->configLoader) {
01905                 // delete the temporary when this dialog is done
01906                 configLoader->setParent(dialog);
01907             }
01908 
01909             dialog->setWindowTitle(d->configWindowTitle());
01910             dialog->setAttribute(Qt::WA_DeleteOnClose, true);
01911             bool hasPages = false;
01912 
01913             QFile f(uiFile);
01914             QUiLoader loader;
01915             QWidget *w = loader.load(&f);
01916             if (w) {
01917                 dialog->addPage(w, i18n("Settings"), icon(), i18n("%1 Settings", name()));
01918                 hasPages = true;
01919             }
01920 
01921             foreach (const QString &kcm, kcmPlugins) {
01922 #ifndef PLASMA_NO_KUTILS
01923                 KCModuleProxy *module = new KCModuleProxy(kcm);
01924                 if (module->realModule()) {
01925                     connect(module, SIGNAL(changed(bool)), dialog, SLOT(settingsModified(bool)));
01926                     dialog->addPage(module, module->moduleInfo().moduleName(), module->moduleInfo().icon());
01927                     hasPages = true;
01928                 } else {
01929                     delete module;
01930                 }
01931 #else
01932                 KService::Ptr service = KService::serviceByStorageId(kcm);
01933                 if (service) {
01934                     QString error;
01935                     KCModule *module = service->createInstance<KCModule>(dialog, QVariantList(), &error);
01936                     if (module) {
01937                         connect(module, SIGNAL(changed(bool)), dialog, SLOT(settingsModified(bool)));
01938                         dialog->addPage(module, service->name(), service->icon());
01939                         hasPages = true;
01940                     } else {
01941 #ifndef NDEBUG
01942                         kDebug() << "failed to load kcm" << kcm << "for" << name();
01943 #endif
01944                     }
01945                 }
01946 #endif
01947             }
01948 
01949             if (hasPages) {
01950                 d->addGlobalShortcutsPage(dialog);
01951                 d->addPublishPage(dialog);
01952                 dialog->show();
01953             } else {
01954                 delete dialog;
01955                 dialog = 0;
01956             }
01957         }
01958 
01959         if (!dialog && d->script) {
01960             d->script->showConfigurationInterface();
01961         }
01962     } else if (d->script) {
01963         d->script->showConfigurationInterface();
01964     } else {
01965         KConfigDialog *dialog = d->generateGenericConfigDialog();
01966         d->addStandardConfigurationPages(dialog);
01967         showConfigurationInterface(dialog);
01968     }
01969 
01970     emit releaseVisualFocus();
01971 }
01972 
01973 void Applet::showConfigurationInterface(QWidget *widget)
01974 {
01975     if (!containment() || !containment()->corona() ||
01976         !containment()->corona()->dialogManager()) {
01977         widget->show();
01978         return;
01979     }
01980 
01981     QMetaObject::invokeMethod(containment()->corona()->dialogManager(), "showDialog", Q_ARG(QWidget *, widget), Q_ARG(Plasma::Applet *, this));
01982 }
01983 
01984 QString AppletPrivate::configDialogId() const
01985 {
01986     return QString("%1settings%2").arg(appletId).arg(q->name());
01987 }
01988 
01989 QString AppletPrivate::configWindowTitle() const
01990 {
01991     return i18nc("@title:window", "%1 Settings", q->name());
01992 }
01993 
01994 QSet<QString> AppletPrivate::knownCategories()
01995 {
01996     // this is to trick the tranlsation tools into making the correct
01997     // strings for translation
01998     QSet<QString> categories = s_customCategories;
01999     categories << QString(I18N_NOOP("Accessibility")).toLower()
02000                << QString(I18N_NOOP("Application Launchers")).toLower()
02001                << QString(I18N_NOOP("Astronomy")).toLower()
02002                << QString(I18N_NOOP("Date and Time")).toLower()
02003                << QString(I18N_NOOP("Development Tools")).toLower()
02004                << QString(I18N_NOOP("Education")).toLower()
02005                << QString(I18N_NOOP("Environment and Weather")).toLower()
02006                << QString(I18N_NOOP("Examples")).toLower()
02007                << QString(I18N_NOOP("File System")).toLower()
02008                << QString(I18N_NOOP("Fun and Games")).toLower()
02009                << QString(I18N_NOOP("Graphics")).toLower()
02010                << QString(I18N_NOOP("Language")).toLower()
02011                << QString(I18N_NOOP("Mapping")).toLower()
02012                << QString(I18N_NOOP("Miscellaneous")).toLower()
02013                << QString(I18N_NOOP("Multimedia")).toLower()
02014                << QString(I18N_NOOP("Online Services")).toLower()
02015                << QString(I18N_NOOP("Productivity")).toLower()
02016                << QString(I18N_NOOP("System Information")).toLower()
02017                << QString(I18N_NOOP("Utilities")).toLower()
02018                << QString(I18N_NOOP("Windows and Tasks")).toLower();
02019     return categories;
02020 }
02021 
02022 KConfigDialog *AppletPrivate::generateGenericConfigDialog()
02023 {
02024     KConfigSkeleton *nullManager = new KConfigSkeleton(0);
02025     KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager);
02026     nullManager->setParent(dialog);
02027     dialog->setFaceType(KPageDialog::Auto);
02028     dialog->setWindowTitle(configWindowTitle());
02029     dialog->setAttribute(Qt::WA_DeleteOnClose, true);
02030     q->createConfigurationInterface(dialog);
02031     dialog->showButton(KDialog::Default, false);
02032     dialog->showButton(KDialog::Help, false);
02033     QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()));
02034     QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()));
02035     return dialog;
02036 }
02037 
02038 void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog)
02039 {
02040     addGlobalShortcutsPage(dialog);
02041     addPublishPage(dialog);
02042 }
02043 
02044 void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog)
02045 {
02046 #ifndef PLASMA_NO_GLOBAL_SHORTCUTS
02047     if (isContainment) {
02048         return;
02049     }
02050 
02051     QWidget *page = new QWidget;
02052     QVBoxLayout *layout = new QVBoxLayout(page);
02053 
02054     if (!shortcutEditor) {
02055         shortcutEditor = new KKeySequenceWidget(page);
02056         QObject::connect(shortcutEditor.data(), SIGNAL(keySequenceChanged(QKeySequence)), dialog, SLOT(settingsModified()));
02057     }
02058 
02059     shortcutEditor.data()->setKeySequence(q->globalShortcut().primary());
02060     layout->addWidget(shortcutEditor.data());
02061     layout->addStretch();
02062     dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard");
02063 
02064     QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
02065     QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
02066 #endif
02067 }
02068 
02069 void AppletPrivate::addPublishPage(KConfigDialog *dialog)
02070 {
02071 #ifdef ENABLE_REMOTE_WIDGETS
02072     QWidget *page = new QWidget;
02073     publishUI.setupUi(page);
02074     publishUI.publishCheckbox->setChecked(q->isPublished());
02075     QObject::connect(publishUI.publishCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
02076     publishUI.allUsersCheckbox->setEnabled(q->isPublished());
02077     QObject::connect(publishUI.allUsersCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified()));
02078 
02079     QString resourceName =
02080     i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
02081           "%1 on %2", q->name(), QHostInfo::localHostName());
02082     if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
02083         publishUI.allUsersCheckbox->setChecked(true);
02084     } else {
02085         publishUI.allUsersCheckbox->setChecked(false);
02086     }
02087 
02088     q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)),
02089                q, SLOT(publishCheckboxStateChanged(int)));
02090     dialog->addPage(page, i18n("Share"), "applications-internet");
02091 #endif
02092 }
02093 
02094 void AppletPrivate::publishCheckboxStateChanged(int state)
02095 {
02096     if (state == Qt::Checked) {
02097         publishUI.allUsersCheckbox->setEnabled(true);
02098     } else {
02099         publishUI.allUsersCheckbox->setEnabled(false);
02100     }
02101 }
02102 
02103 void AppletPrivate::configDialogFinished()
02104 {
02105     if (shortcutEditor) {
02106         QKeySequence sequence = shortcutEditor.data()->keySequence();
02107         if (sequence != q->globalShortcut().primary()) {
02108             q->setGlobalShortcut(KShortcut(sequence));
02109             emit q->configNeedsSaving();
02110         }
02111     }
02112 
02113 #ifdef ENABLE_REMOTE_WIDGETS
02114     if (KConfigDialog::exists(configDialogId()) && publishUI.publishCheckbox) {
02115         q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked());
02116 
02117         if (publishUI.publishCheckbox->isChecked()) {
02118             QString resourceName =
02119                 i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
02120                         "%1 on %2", q->name(), QHostInfo::localHostName());
02121             q->publish(Plasma::ZeroconfAnnouncement, resourceName);
02122             if (publishUI.allUsersCheckbox->isChecked()) {
02123                 if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
02124                     AuthorizationRule *rule = new AuthorizationRule(resourceName, "");
02125                     rule->setPolicy(AuthorizationRule::Allow);
02126                     rule->setTargets(AuthorizationRule::AllUsers);
02127                     AuthorizationManager::self()->d->rules.append(rule);
02128                 }
02129             } else {
02130                 AuthorizationRule *matchingRule =
02131                     AuthorizationManager::self()->d->matchingRule(resourceName, Credentials());
02132                 if (matchingRule) {
02133                     AuthorizationManager::self()->d->rules.removeAll(matchingRule);
02134                 }
02135             }
02136         } else {
02137             q->unpublish();
02138         }
02139     }
02140 #endif
02141 
02142     if (!configLoader) {
02143         // the config loader will trigger this for us, so we don't need to.
02144         propagateConfigChanged();
02145         if (KConfigDialog *dialog = qobject_cast<KConfigDialog *>(q->sender())) {
02146             dialog->enableButton(KDialog::Apply, false);
02147         }
02148     }
02149 }
02150 
02151 void AppletPrivate::updateShortcuts()
02152 {
02153     if (isContainment) {
02154         //a horrible hack to avoid clobbering corona settings
02155         //we pull them out, then read, then put them back
02156         QList<QString> names;
02157         QList<QAction*> qactions;
02158         names << "add sibling containment" << "configure shortcuts" << "lock widgets";
02159         foreach (const QString &name, names) {
02160             QAction *a = actions->action(name);
02161             actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method
02162             qactions << a;
02163         }
02164 
02165         actions->readSettings();
02166 
02167         for (int i = 0; i < names.size(); ++i) {
02168             QAction *a = qactions.at(i);
02169             if (a) {
02170                 actions->addAction(names.at(i), a);
02171             }
02172         }
02173     } else {
02174         actions->readSettings();
02175     }
02176 }
02177 
02178 void AppletPrivate::propagateConfigChanged()
02179 {
02180     if (isContainment) {
02181         Containment *c = qobject_cast<Containment *>(q);
02182         if (c) {
02183             c->d->configChanged();
02184         }
02185     }
02186 
02187     q->configChanged();
02188 }
02189 
02190 void Applet::configChanged()
02191 {
02192     if (d->script) {
02193         if (d->configLoader) {
02194             d->configLoader->readConfig();
02195         }
02196         d->script->configChanged();
02197     }
02198 }
02199 
02200 void Applet::createConfigurationInterface(KConfigDialog *parent)
02201 {
02202     Q_UNUSED(parent)
02203     // virtual method reimplemented by subclasses.
02204     // do not put anything here ...
02205 }
02206 
02207 bool Applet::hasAuthorization(const QString &constraint) const
02208 {
02209     KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
02210     return constraintGroup.readEntry(constraint, true);
02211 }
02212 
02213 void Applet::setAssociatedApplication(const QString &string)
02214 {
02215     AssociatedApplicationManager::self()->setApplication(this, string);
02216 
02217     QAction *runAssociatedApplication = d->actions->action("run associated application");
02218     if (runAssociatedApplication) {
02219         bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02220         valid = valid && hasAuthorization("LaunchApp"); //obey security!
02221         runAssociatedApplication->setVisible(valid);
02222         runAssociatedApplication->setEnabled(valid);
02223     }
02224 }
02225 
02226 void Applet::setAssociatedApplicationUrls(const KUrl::List &urls)
02227 {
02228     AssociatedApplicationManager::self()->setUrls(this, urls);
02229 
02230     QAction *runAssociatedApplication = d->actions->action("run associated application");
02231     if (runAssociatedApplication) {
02232         bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02233         valid = valid && hasAuthorization("LaunchApp"); //obey security!
02234         runAssociatedApplication->setVisible(valid);
02235         runAssociatedApplication->setEnabled(valid);
02236     }
02237 }
02238 
02239 QString Applet::associatedApplication() const
02240 {
02241     return AssociatedApplicationManager::self()->application(this);
02242 }
02243 
02244 KUrl::List Applet::associatedApplicationUrls() const
02245 {
02246     return AssociatedApplicationManager::self()->urls(this);
02247 }
02248 
02249 void Applet::runAssociatedApplication()
02250 {
02251     if (hasAuthorization("LaunchApp")) {
02252         AssociatedApplicationManager::self()->run(this);
02253     }
02254 }
02255 
02256 bool Applet::hasValidAssociatedApplication() const
02257 {
02258     return AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02259 }
02260 
02261 void AppletPrivate::filterOffers(QList<KService::Ptr> &offers)
02262 {
02263     KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
02264     foreach (const QString &key, constraintGroup.keyList()) {
02265         //kDebug() << "security constraint" << key;
02266         if (constraintGroup.readEntry(key, true)) {
02267             continue;
02268         }
02269 
02270         //ugh. a qlist of ksharedptr<kservice>
02271         QMutableListIterator<KService::Ptr> it(offers);
02272         while (it.hasNext()) {
02273             KService::Ptr p = it.next();
02274             QString prop = QString("X-Plasma-Requires-").append(key);
02275             QVariant req = p->property(prop, QVariant::String);
02276             //valid values: Required/Optional/Unused
02277             QString reqValue;
02278             if (req.isValid()) {
02279                 reqValue = req.toString();
02280             } else if (p->property("X-Plasma-API").toString().toLower() == "javascript") {
02281                 //TODO: be able to check whether or not a script engine provides "controled"
02282                 //bindings; for now we just give a pass to the qscript ones
02283                 reqValue = "Unused";
02284             }
02285 
02286             if (!(reqValue == "Optional" || reqValue == "Unused")) {
02287             //if (reqValue == "Required") {
02288                 it.remove();
02289             }
02290         }
02291     }
02292 }
02293 
02294 QString AppletPrivate::parentAppConstraint(const QString &parentApp)
02295 {
02296     if (parentApp.isEmpty()) {
02297         return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')")
02298                       .arg(KGlobal::mainComponent().aboutData()->appName());
02299     }
02300 
02301     return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp);
02302 }
02303 
02304 KPluginInfo::List Applet::listAppletInfo(const QString &category, const QString &parentApp)
02305 {
02306    return PluginLoader::pluginLoader()->listAppletInfo(category, parentApp);
02307 }
02308 
02309 KPluginInfo::List Applet::listAppletInfoForMimetype(const QString &mimetype)
02310 {
02311     QString constraint = AppletPrivate::parentAppConstraint();
02312     constraint.append(QString(" and '%1' in [X-Plasma-DropMimeTypes]").arg(mimetype));
02313     //kDebug() << "listAppletInfoForMimetype with" << mimetype << constraint;
02314     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02315     AppletPrivate::filterOffers(offers);
02316     return KPluginInfo::fromServices(offers);
02317 }
02318 
02319 KPluginInfo::List Applet::listAppletInfoForUrl(const QUrl &url)
02320 {
02321     QString constraint = AppletPrivate::parentAppConstraint();
02322     constraint.append(" and exist [X-Plasma-DropUrlPatterns]");
02323     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02324     AppletPrivate::filterOffers(offers);
02325 
02326     KPluginInfo::List allApplets = KPluginInfo::fromServices(offers);
02327     KPluginInfo::List filtered;
02328     foreach (const KPluginInfo &info, allApplets) {
02329         QStringList urlPatterns = info.property("X-Plasma-DropUrlPatterns").toStringList();
02330         foreach (const QString &glob, urlPatterns) {
02331             QRegExp rx(glob);
02332             rx.setPatternSyntax(QRegExp::Wildcard);
02333             if (rx.exactMatch(url.toString())) {
02334                 kDebug() << info.name() << "matches" << glob << url;
02335                 filtered << info;
02336             }
02337         }
02338     }
02339 
02340     return filtered;
02341 }
02342 
02343 QStringList Applet::listCategories(const QString &parentApp, bool visibleOnly)
02344 {
02345     QString constraint = AppletPrivate::parentAppConstraint(parentApp);
02346     constraint.append(" and exist [X-KDE-PluginInfo-Category]");
02347 
02348     KConfigGroup group(KGlobal::config(), "General");
02349     const QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
02350     foreach (const QString &category, excluded) {
02351         constraint.append(" and [X-KDE-PluginInfo-Category] != '").append(category).append("'");
02352     }
02353 
02354     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02355     AppletPrivate::filterOffers(offers);
02356 
02357     QStringList categories;
02358     QSet<QString> known = AppletPrivate::knownCategories();
02359     foreach (const KService::Ptr &applet, offers) {
02360         QString appletCategory = applet->property("X-KDE-PluginInfo-Category").toString();
02361         if (visibleOnly && applet->noDisplay()) {
02362             // we don't want to show the hidden category
02363             continue;
02364         }
02365 
02366         //kDebug() << "   and we have " << appletCategory;
02367         if (!appletCategory.isEmpty() && !known.contains(appletCategory.toLower())) {
02368             kDebug() << "Unknown category: " << applet->name() << "says it is in the"
02369                      << appletCategory << "category which is unknown to us";
02370             appletCategory.clear();
02371         }
02372 
02373         if (appletCategory.isEmpty()) {
02374             if (!categories.contains(i18nc("misc category", "Miscellaneous"))) {
02375                 categories << i18nc("misc category", "Miscellaneous");
02376             }
02377         } else  if (!categories.contains(appletCategory)) {
02378             categories << appletCategory;
02379         }
02380     }
02381 
02382     categories.sort();
02383     return categories;
02384 }
02385 
02386 void Applet::setCustomCategories(const QStringList &categories)
02387 {
02388     AppletPrivate::s_customCategories = QSet<QString>::fromList(categories);
02389 }
02390 
02391 QStringList Applet::customCategories()
02392 {
02393     return AppletPrivate::s_customCategories.toList();
02394 }
02395 
02396 Applet *Applet::loadPlasmoid(const QString &path, uint appletId, const QVariantList &args)
02397 {
02398     if (QFile::exists(path + "/metadata.desktop")) {
02399         KService service(path + "/metadata.desktop");
02400         const QStringList& types = service.serviceTypes();
02401 
02402         if (types.contains("Plasma/Containment")) {
02403             return new Containment(path, appletId, args);
02404         } else if (types.contains("Plasma/PopupApplet")) {
02405             return new PopupApplet(path, appletId, args);
02406         } else {
02407             return new Applet(path, appletId, args);
02408         }
02409     }
02410 
02411     return 0;
02412 }
02413 
02414 Applet *Applet::load(const QString &appletName, uint appletId, const QVariantList &args)
02415 {
02416     return PluginLoader::pluginLoader()->loadApplet(appletName, appletId, args);
02417 }
02418 
02419 Applet *Applet::load(const KPluginInfo &info, uint appletId, const QVariantList &args)
02420 {
02421     if (!info.isValid()) {
02422         return 0;
02423     }
02424 
02425     return load(info.pluginName(), appletId, args);
02426 }
02427 
02428 QVariant Applet::itemChange(GraphicsItemChange change, const QVariant &value)
02429 {
02430     QVariant ret = QGraphicsWidget::itemChange(change, value);
02431 
02432     //kDebug() << change;
02433     switch (change) {
02434     case ItemSceneHasChanged: {
02435         Corona *newCorona = qobject_cast<Corona *>(qvariant_cast<QGraphicsScene*>(value));
02436         if (newCorona && newCorona->immutability() != Mutable) {
02437             updateConstraints(ImmutableConstraint);
02438         }
02439     }
02440         break;
02441     case ItemParentChange:
02442         if (!d->isContainment) {
02443             Containment *c = containment();
02444             if (d->mainConfig && !c) {
02445                 kWarning() << "Configuration object was requested prior to init(), which is too early. "
02446                     "Please fix this item:" << parentItem() << value.value<QGraphicsItem *>()
02447                     << name();
02448 
02449                 Applet *newC = dynamic_cast<Applet*>(value.value<QGraphicsItem *>());
02450                 if (newC) {
02451                     // if this is an applet, and we've just been assigned to our first containment,
02452                     // but the applet did something stupid like ask for the config() object prior to
02453                     // this happening (e.g. inits ctor) then let's repair that situation for them.
02454                     KConfigGroup *old = d->mainConfig;
02455                     KConfigGroup appletConfig = newC->config();
02456                     appletConfig = KConfigGroup(&appletConfig, "Applets");
02457                     d->mainConfig = new KConfigGroup(&appletConfig, QString::number(d->appletId));
02458                     old->copyTo(d->mainConfig);
02459                     old->deleteGroup();
02460                     delete old;
02461                 }
02462             }
02463         }
02464         break;
02465     case ItemParentHasChanged:
02466         {
02467             if (isContainment()) {
02468                 removeSceneEventFilter(this);
02469             } else {
02470                 Containment *c = containment();
02471                 if (c && c->containmentType() == Containment::DesktopContainment) {
02472                     installSceneEventFilter(this);
02473                 } else {
02474                     removeSceneEventFilter(this);
02475                 }
02476             }
02477         }
02478         break;
02479     case ItemPositionHasChanged:
02480         emit geometryChanged();
02481         // fall through!
02482     case ItemTransformHasChanged:
02483         d->scheduleModificationNotification();
02484         break;
02485     default:
02486         break;
02487     };
02488 
02489     return ret;
02490 }
02491 
02492 QPainterPath Applet::shape() const
02493 {
02494     if (d->script) {
02495         return d->script->shape();
02496     }
02497 
02498     return QGraphicsWidget::shape();
02499 }
02500 
02501 QSizeF Applet::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
02502 {
02503     QSizeF hint = QGraphicsWidget::sizeHint(which, constraint);
02504     const FormFactor ff = formFactor();
02505 
02506     // in panels make sure that the contents won't exit from the panel
02507     if (which == Qt::MinimumSize) {
02508         if (ff == Horizontal) {
02509             hint.setHeight(0);
02510         } else if (ff == Vertical) {
02511             hint.setWidth(0);
02512         }
02513     }
02514 
02515     // enforce a square size in panels
02516     if (d->aspectRatioMode == Plasma::Square) {
02517         if (ff == Horizontal) {
02518             hint.setWidth(size().height());
02519         } else if (ff == Vertical) {
02520             hint.setHeight(size().width());
02521         }
02522     } else if (d->aspectRatioMode == Plasma::ConstrainedSquare) {
02523         //enforce a size not wider than tall
02524         if (ff == Horizontal) {
02525             hint.setWidth(size().height());
02526         //enforce a size not taller than wide
02527         } else if (ff == Vertical && (which == Qt::MaximumSize || size().width() <= KIconLoader::SizeLarge)) {
02528             hint.setHeight(size().width());
02529         }
02530     }
02531 
02532     return hint;
02533 }
02534 
02535 void Applet::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
02536 {
02537     Q_UNUSED(event)
02538 }
02539 
02540 void Applet::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
02541 {
02542     Q_UNUSED(event)
02543 }
02544 
02545 void Applet::timerEvent(QTimerEvent *event)
02546 {
02547     if (d->transient) {
02548         d->constraintsTimer.stop();
02549         d->busyWidgetTimer.stop();
02550         if (d->modificationsTimer) {
02551             d->modificationsTimer->stop();
02552         }
02553         return;
02554     }
02555 
02556     if (event->timerId() == d->constraintsTimer.timerId()) {
02557         d->constraintsTimer.stop();
02558 
02559         // Don't flushPendingConstraints if we're just starting up
02560         // flushPendingConstraints will be called by Corona
02561         if(!(d->pendingConstraints & Plasma::StartupCompletedConstraint)) {
02562             flushPendingConstraintsEvents();
02563         }
02564     } else if (d->modificationsTimer && event->timerId() == d->modificationsTimer->timerId()) {
02565         d->modificationsTimer->stop();
02566         // invalid group, will result in save using the default group
02567         KConfigGroup cg;
02568 
02569         save(cg);
02570         emit configNeedsSaving();
02571     } else if (event->timerId() == d->busyWidgetTimer.timerId()) {
02572         if (!d->busyWidget) {
02573             d->createMessageOverlay(false);
02574             d->messageOverlay->opacity = 0;
02575 
02576             QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(d->messageOverlay);
02577             d->busyWidget = new Plasma::BusyWidget(d->messageOverlay);
02578             d->busyWidget->setAcceptHoverEvents(false);
02579             d->busyWidget->setAcceptedMouseButtons(Qt::NoButton);
02580             d->messageOverlay->setAcceptHoverEvents(false);
02581             d->messageOverlay->setAcceptedMouseButtons(Qt::NoButton);
02582 
02583             mainLayout->addStretch();
02584             mainLayout->addItem(d->busyWidget);
02585             mainLayout->addStretch();
02586         }
02587     }
02588 }
02589 
02590 QRect Applet::screenRect() const
02591 {
02592     QGraphicsView *v = view();
02593 
02594     if (v) {
02595         QPointF bottomRight = pos();
02596         bottomRight.rx() += size().width();
02597         bottomRight.ry() += size().height();
02598 
02599         QPoint tL = v->mapToGlobal(v->mapFromScene(pos()));
02600         QPoint bR = v->mapToGlobal(v->mapFromScene(bottomRight));
02601         return QRect(QPoint(tL.x(), tL.y()), QSize(bR.x() - tL.x(), bR.y() - tL.y()));
02602     }
02603 
02604     //The applet doesn't have a view on it.
02605     //So a screenRect isn't relevant.
02606     return QRect(QPoint(0, 0), QSize(0, 0));
02607 }
02608 
02609 void Applet::raise()
02610 {
02611     setZValue(++AppletPrivate::s_maxZValue);
02612 }
02613 
02614 void Applet::lower()
02615 {
02616     setZValue(--AppletPrivate::s_minZValue);
02617 }
02618 
02619 void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate)
02620 {
02621     if (isContainment == nowIsContainment && !forceUpdate) {
02622         return;
02623     }
02624 
02625     isContainment = nowIsContainment;
02626     //FIXME I do not like this function.
02627     //currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way.
02628     //if someone calls it at some other time it'll cause headaches. :P
02629 
02630     delete mainConfig;
02631     mainConfig = 0;
02632 
02633     Containment *c = q->containment();
02634     if (c) {
02635         c->d->checkContainmentFurniture();
02636     }
02637 }
02638 
02639 bool Applet::isContainment() const
02640 {
02641     return d->isContainment;
02642 }
02643 
02644 // PRIVATE CLASS IMPLEMENTATION
02645 
02646 AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet)
02647         : appletId(uniqueID),
02648           q(applet),
02649           service(0),
02650           preferredBackgroundHints(Applet::StandardBackground),
02651           backgroundHints(Applet::NoBackground),
02652           aspectRatioMode(Plasma::KeepAspectRatio),
02653           immutability(Mutable),
02654           appletDescription(info ? *info : KPluginInfo(service)),
02655           background(0),
02656           mainConfig(0),
02657           pendingConstraints(NoConstraint),
02658           messageOverlay(0),
02659           messageOverlayProxy(0),
02660           busyWidget(0),
02661           script(0),
02662           package(0),
02663           configLoader(0),
02664           actions(AppletPrivate::defaultActions(applet)),
02665           activationAction(0),
02666           itemStatus(UnknownStatus),
02667           preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored),
02668           modificationsTimer(0),
02669           hasConfigurationInterface(false),
02670           failed(false),
02671           isContainment(false),
02672           transient(false),
02673           needsConfig(false),
02674           started(false)
02675 {
02676     if (appletId == 0) {
02677         appletId = ++s_maxAppletId;
02678     } else if (appletId > s_maxAppletId) {
02679         s_maxAppletId = appletId;
02680     }
02681 }
02682 
02683 AppletPrivate::~AppletPrivate()
02684 {
02685     if (activationAction && activationAction->isGlobalShortcutEnabled()) {
02686         //kDebug() << "reseting global action for" << q->name() << activationAction->objectName();
02687         activationAction->forgetGlobalShortcut();
02688     }
02689 
02690     delete extender.data();
02691 
02692     delete script;
02693     script = 0;
02694     delete package;
02695     package = 0;
02696     delete configLoader;
02697     configLoader = 0;
02698     delete mainConfig;
02699     mainConfig = 0;
02700     delete modificationsTimer;
02701 }
02702 
02703 void AppletPrivate::init(const QString &packagePath)
02704 {
02705     // WARNING: do not access config() OR globalConfig() in this method!
02706     //          that requires a scene, which is not available at this point
02707     q->setCacheMode(Applet::DeviceCoordinateCache);
02708     q->setAcceptsHoverEvents(true);
02709     q->setFlag(QGraphicsItem::ItemIsFocusable, true);
02710     q->setFocusPolicy(Qt::ClickFocus);
02711     // FIXME: adding here because nothing seems to be doing it in QGraphicsView,
02712     // but it doesn't actually work anyways =/
02713     q->setLayoutDirection(qApp->layoutDirection());
02714 
02715     //set a default size before any saved settings are read
02716     QSize size(200, 200);
02717     q->setBackgroundHints(Applet::DefaultBackground);
02718     q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor?
02719 
02720     QAction *closeApplet = actions->action("remove");
02721     if (closeApplet) {
02722         closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name()));
02723     }
02724 
02725     QAction *configAction = actions->action("configure");
02726     if (configAction) {
02727         configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name()));
02728     }
02729 
02730     QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus()));
02731     if (!appletDescription.isValid()) {
02732         kDebug() << "Check your constructor! "
02733                  << "You probably want to be passing in a Service::Ptr "
02734                  << "or a QVariantList with a valid storageid as arg[0].";
02735         q->resize(size);
02736         return;
02737     }
02738 
02739     QVariant s = appletDescription.property("X-Plasma-DefaultSize");
02740     if (s.isValid()) {
02741         size = s.toSize();
02742     }
02743     //kDebug() << "size" << size;
02744     q->resize(size);
02745 
02746     QString api = appletDescription.property("X-Plasma-API").toString();
02747 
02748     // we have a scripted plasmoid
02749     if (!api.isEmpty()) {
02750         // find where the Package is
02751         QString path = packagePath;
02752         if (path.isEmpty()) {
02753             QString subPath = q->packageStructure()->defaultPackageRoot() + '/' + appletDescription.pluginName() + '/';
02754             path = KStandardDirs::locate("data", subPath + "metadata.desktop");
02755             if (path.isEmpty()) {
02756                 path = KStandardDirs::locate("data", subPath);
02757             } else {
02758                 path.remove(QString("metadata.desktop"));
02759             }
02760         } else if (!path.endsWith('/')) {
02761             path.append('/');
02762         }
02763 
02764         if (path.isEmpty()) {
02765             q->setFailedToLaunch(
02766                 true,
02767                 i18nc("Package file, name of the widget",
02768                       "Could not locate the %1 package required for the %2 widget.",
02769                       appletDescription.pluginName(), appletDescription.name()));
02770         } else {
02771             // create the package and see if we have something real
02772             //kDebug() << "trying for" << path;
02773             PackageStructure::Ptr structure = Plasma::packageStructure(api, Plasma::AppletComponent);
02774             structure->setPath(path);
02775             package = new Package(path, structure);
02776 
02777             if (package->isValid()) {
02778                 // now we try and set up the script engine.
02779                 // it will be parented to this applet and so will get
02780                 // deleted when the applet does
02781 
02782                 script = Plasma::loadScriptEngine(api, q);
02783                 if (!script) {
02784                     delete package;
02785                     package = 0;
02786                     q->setFailedToLaunch(true,
02787                                          i18nc("API or programming language the widget was written in, name of the widget",
02788                                                "Could not create a %1 ScriptEngine for the %2 widget.",
02789                                                api, appletDescription.name()));
02790                 }
02791             } else {
02792                 q->setFailedToLaunch(true, i18nc("Package file, name of the widget",
02793                                                  "Could not open the %1 package required for the %2 widget.",
02794                                                  appletDescription.pluginName(), appletDescription.name()));
02795                 delete package;
02796                 package = 0;
02797             }
02798         }
02799     }
02800 }
02801 
02802 // put all setup routines for script here. at this point we can assume that
02803 // package exists and that we have a script engine
02804 void AppletPrivate::setupScriptSupport()
02805 {
02806     if (!package) {
02807         return;
02808     }
02809 
02810     kDebug() << "setting up script support, package is in" << package->path()
02811              << "which is a" << package->structure()->type() << "package"
02812              << ", main script is" << package->filePath("mainscript");
02813 
02814     QString translationsPath = package->filePath("translations");
02815     if (!translationsPath.isEmpty()) {
02816         //FIXME: we should _probably_ use a KComponentData to segregate the applets
02817         //       from each other; but I want to get the basics working first :)
02818         KGlobal::dirs()->addResourceDir("locale", translationsPath);
02819         KGlobal::locale()->insertCatalog(package->metadata().pluginName());
02820     }
02821 
02822     QString xmlPath = package->filePath("mainconfigxml");
02823     if (!xmlPath.isEmpty()) {
02824         QFile file(xmlPath);
02825         KConfigGroup config = q->config();
02826         configLoader = new ConfigLoader(&config, &file);
02827         QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged()));
02828     }
02829 
02830     if (!package->filePath("mainconfigui").isEmpty()) {
02831         q->setHasConfigurationInterface(true);
02832     }
02833 }
02834 
02835 QString AppletPrivate::globalName() const
02836 {
02837     if (!appletDescription.isValid()) {
02838         return QString();
02839     }
02840 
02841     return appletDescription.service()->library();
02842 }
02843 
02844 QString AppletPrivate::instanceName()
02845 {
02846     if (!appletDescription.isValid()) {
02847         return QString();
02848     }
02849 
02850     return appletDescription.service()->library() + QString::number(appletId);
02851 }
02852 
02853 void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c)
02854 {
02855     // Don't start up a timer if we're just starting up
02856     // flushPendingConstraints will be called by Corona
02857     if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) {
02858         constraintsTimer.start(0, q);
02859     }
02860 
02861     if (c & Plasma::StartupCompletedConstraint) {
02862         started = true;
02863     }
02864 
02865     pendingConstraints |= c;
02866 }
02867 
02868 void AppletPrivate::scheduleModificationNotification()
02869 {
02870     // modificationsTimer is not allocated until we get our notice of being started
02871     if (modificationsTimer) {
02872         // schedule a save
02873         if (modificationsTimer->isActive()) {
02874             modificationsTimer->stop();
02875         }
02876 
02877         modificationsTimer->start(1000, q);
02878     }
02879 }
02880 
02881 KConfigGroup *AppletPrivate::mainConfigGroup()
02882 {
02883     if (mainConfig) {
02884         return mainConfig;
02885     }
02886 
02887     bool newGroup = false;
02888     if (isContainment) {
02889         Corona *corona = qobject_cast<Corona*>(q->scene());
02890         KConfigGroup containmentConfig;
02891         //kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q;
02892 
02893         if (corona) {
02894             containmentConfig = KConfigGroup(corona->config(), "Containments");
02895         } else {
02896             containmentConfig =  KConfigGroup(KGlobal::config(), "Containments");
02897         }
02898 
02899         if (package && !containmentConfig.hasGroup(QString::number(appletId))) {
02900             newGroup = true;
02901         }
02902 
02903         mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId));
02904     } else {
02905         KConfigGroup appletConfig;
02906 
02907         Containment *c = q->containment();
02908         Applet *parentApplet = qobject_cast<Applet *>(q->parent());
02909         if (parentApplet && parentApplet != static_cast<Applet *>(c)) {
02910             // this applet is nested inside another applet! use it's config
02911             // as the parent group in the config
02912             appletConfig = parentApplet->config();
02913             appletConfig = KConfigGroup(&appletConfig, "Applets");
02914         } else if (c) {
02915             // applet directly in a Containment, as usual
02916             appletConfig = c->config();
02917             appletConfig = KConfigGroup(&appletConfig, "Applets");
02918         } else {
02919             kWarning() << "requesting config for" << q->name() << "without a containment!";
02920             appletConfig = KConfigGroup(KGlobal::config(), "Applets");
02921         }
02922 
02923         if (package && !appletConfig.hasGroup(QString::number(appletId))) {
02924             newGroup = true;
02925         }
02926 
02927         mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId));
02928     }
02929 
02930     if (newGroup) {
02931         //see if we have a default configuration in our package
02932         const QString defaultConfigFile = q->package()->filePath("defaultconfig");
02933         if (!defaultConfigFile.isEmpty()) {
02934             kDebug() << "copying default config: " << q->package()->filePath("defaultconfig");
02935             KConfigGroup defaultConfig(KSharedConfig::openConfig(defaultConfigFile)->group("Configuration"));
02936             defaultConfig.copyTo(mainConfig);
02937         }
02938     }
02939 
02940     return mainConfig;
02941 }
02942 
02943 QString AppletPrivate::visibleFailureText(const QString &reason)
02944 {
02945     QString text;
02946 
02947     if (reason.isEmpty()) {
02948         text = i18n("This object could not be created.");
02949     } else {
02950         text = i18n("This object could not be created for the following reason:<p><b>%1</b></p>", reason);
02951     }
02952 
02953     return text;
02954 }
02955 
02956 void AppletPrivate::themeChanged()
02957 {
02958     if (background) {
02959         //do again the translucent background fallback
02960         q->setBackgroundHints(backgroundHints);
02961 
02962         qreal left;
02963         qreal right;
02964         qreal top;
02965         qreal bottom;
02966         background->getMargins(left, top, right, bottom);
02967         q->setContentsMargins(left, right, top, bottom);
02968     }
02969     q->update();
02970 }
02971 
02972 void AppletPrivate::resetConfigurationObject()
02973 {
02974     // make sure mainConfigGroup exists in all cases
02975     mainConfigGroup();
02976 
02977     mainConfig->deleteGroup();
02978     delete mainConfig;
02979     mainConfig = 0;
02980 
02981     Corona * corona = qobject_cast<Corona*>(q->scene());
02982     if (corona) {
02983         corona->requireConfigSync();
02984     }
02985 }
02986 
02987 void AppletPrivate::handleDisappeared(AppletHandle *h)
02988 {
02989     if (h == handle.data()) {
02990         h->detachApplet();
02991         QGraphicsScene *scene = q->scene();
02992         if (scene && h->scene() == scene) {
02993             scene->removeItem(h);
02994         }
02995         h->deleteLater();
02996     }
02997 }
02998 
02999 void ContainmentPrivate::checkRemoveAction()
03000 {
03001     q->enableAction("remove", q->immutability() == Mutable);
03002 }
03003 
03004 
03005 uint AppletPrivate::s_maxAppletId = 0;
03006 int AppletPrivate::s_maxZValue = 0;
03007 int AppletPrivate::s_minZValue = 0;
03008 PackageStructure::Ptr AppletPrivate::packageStructure(0);
03009 QSet<QString> AppletPrivate::s_customCategories;
03010 
03011 AppletOverlayWidget::AppletOverlayWidget(QGraphicsWidget *parent)
03012     : QGraphicsWidget(parent),
03013       opacity(0.4)
03014 {
03015     resize(parent->size());
03016 }
03017 
03018 void AppletOverlayWidget::destroy()
03019 {
03020     Animation *anim = Plasma::Animator::create(Plasma::Animator::DisappearAnimation);
03021     if (anim) {
03022         connect(anim, SIGNAL(finished()), this, SLOT(overlayAnimationComplete()));
03023         anim->setTargetWidget(this);
03024         anim->start();
03025     } else {
03026         overlayAnimationComplete();
03027     }
03028 }
03029 
03030 void AppletOverlayWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
03031 {
03032     event->accept();
03033 }
03034 
03035 void AppletOverlayWidget::overlayAnimationComplete()
03036 {
03037     if (scene()) {
03038         scene()->removeItem(this);
03039     }
03040     deleteLater();
03041 }
03042 
03043 void AppletOverlayWidget::paint(QPainter *painter,
03044                                 const QStyleOptionGraphicsItem *option,
03045                                 QWidget *widget)
03046 {
03047     Q_UNUSED(option)
03048     Q_UNUSED(widget)
03049 
03050     if (qFuzzyCompare(1, 1+opacity)) {
03051         return;
03052     }
03053 
03054     QColor wash = Plasma::Theme::defaultTheme()->color(Theme::BackgroundColor);
03055     wash.setAlphaF(opacity);
03056 
03057     Applet *applet = qobject_cast<Applet *>(parentWidget());
03058 
03059 
03060     QPainterPath backgroundShape;
03061     if (!applet || applet->backgroundHints() & Applet::StandardBackground) {
03062         //FIXME: a resize here is nasty, but perhaps still better than an eventfilter just for that..
03063         if (parentWidget()->contentsRect().size() != size()) {
03064             resize(parentWidget()->contentsRect().size());
03065         }
03066         backgroundShape = PaintUtils::roundedRectangle(contentsRect(), 5);
03067     } else {
03068         backgroundShape = shape();
03069     }
03070 
03071     painter->setRenderHints(QPainter::Antialiasing);
03072     painter->fillPath(backgroundShape, wash);
03073 }
03074 
03075 #if QT_VERSION >= 0x040700
03076 // in QGraphicsWidget now; preserve BC by implementing it as a protected method
03077 void Applet::geometryChanged()
03078 {
03079     emit QGraphicsWidget::geometryChanged();
03080 }
03081 #endif
03082 
03083 } // Plasma namespace
03084 
03085 #include "applet.moc"
03086 #include "private/applet_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:51:35 by doxygen 1.8.0 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.8.3 API Reference

Skip menu "kdelibs-4.8.3 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