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

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal