• Skip to content
  • Skip to link menu
KDE 4.7 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(propagateConfigChanged()));
00297         d->configLoader->writeConfig();
00298         connect(d->configLoader, SIGNAL(configChanged()), this, SLOT(propagateConfigChanged()));
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 == messageOkButton.data()) {
00649             buttonCode = ButtonOk;
00650         }
00651         if (button == messageYesButton.data()) {
00652             buttonCode = ButtonYes;
00653         }
00654         if (button == messageNoButton.data()) {
00655             buttonCode = ButtonNo;
00656         }
00657         if (button == messageCancelButton.data()) {
00658             buttonCode = ButtonCancel;
00659         }
00660 
00661         emit q->messageButtonPressed(buttonCode);
00662     } else if (q->sender() == messageOverlay) {
00663         emit q->messageButtonPressed(ButtonCancel);
00664     }
00665 }
00666 
00667 ConfigLoader *Applet::configScheme() const
00668 {
00669     return d->configLoader;
00670 }
00671 
00672 DataEngine *Applet::dataEngine(const QString &name) const
00673 {
00674     if (!d->remoteLocation.isEmpty()) {
00675         return d->remoteDataEngine(KUrl(d->remoteLocation), name);
00676     } else if (!package() || package()->metadata().remoteLocation().isEmpty()) {
00677         return d->dataEngine(name);
00678     } else {
00679         return d->remoteDataEngine(KUrl(package()->metadata().remoteLocation()), name);
00680     }
00681 }
00682 
00683 const Package *Applet::package() const
00684 {
00685     return d->package;
00686 }
00687 
00688 QGraphicsView *Applet::view() const
00689 {
00690     // It's assumed that we won't be visible on more than one view here.
00691     // Anything that actually needs view() should only really care about
00692     // one of them anyway though.
00693     if (!scene()) {
00694         return 0;
00695     }
00696 
00697     QGraphicsView *found = 0;
00698     QGraphicsView *possibleFind = 0;
00699     //kDebug() << "looking through" << scene()->views().count() << "views";
00700     foreach (QGraphicsView *view, scene()->views()) {
00701         //kDebug() << "     checking" << view << view->sceneRect()
00702         //         << "against" << sceneBoundingRect() << scenePos();
00703         if (view->sceneRect().intersects(sceneBoundingRect()) ||
00704             view->sceneRect().contains(scenePos())) {
00705             //kDebug() << "     found something!" << view->isActiveWindow();
00706             if (view->isActiveWindow()) {
00707                 found = view;
00708             } else {
00709                 possibleFind = view;
00710             }
00711         }
00712     }
00713 
00714     return found ? found : possibleFind;
00715 }
00716 
00717 QRectF Applet::mapFromView(const QGraphicsView *view, const QRect &rect) const
00718 {
00719     // Why is this adjustment needed? Qt calculation error?
00720     return mapFromScene(view->mapToScene(rect)).boundingRect().adjusted(0, 0, 1, 1);
00721 }
00722 
00723 QRect Applet::mapToView(const QGraphicsView *view, const QRectF &rect) const
00724 {
00725     // Why is this adjustment needed? Qt calculation error?
00726     return view->mapFromScene(mapToScene(rect)).boundingRect().adjusted(0, 0, -1, -1);
00727 }
00728 
00729 QPoint Applet::popupPosition(const QSize &s) const
00730 {
00731     return popupPosition(s, Qt::AlignLeft);
00732 }
00733 
00734 QPoint Applet::popupPosition(const QSize &s, Qt::AlignmentFlag alignment) const
00735 {
00736     Corona * corona = qobject_cast<Corona*>(scene());
00737     Q_ASSERT(corona);
00738 
00739     return corona->popupPosition(this, s, alignment);
00740 }
00741 
00742 void Applet::updateConstraints(Plasma::Constraints constraints)
00743 {
00744     d->scheduleConstraintsUpdate(constraints);
00745 }
00746 
00747 void Applet::constraintsEvent(Plasma::Constraints constraints)
00748 {
00749     //NOTE: do NOT put any code in here that reacts to constraints updates
00750     //      as it will not get called for any applet that reimplements constraintsEvent
00751     //      without calling the Applet:: version as well, which it shouldn't need to.
00752     //      INSTEAD put such code into flushPendingConstraintsEvents
00753     Q_UNUSED(constraints)
00754     //kDebug() << constraints << "constraints are FormFactor: " << formFactor()
00755     //         << ", Location: " << location();
00756     if (d->script) {
00757         d->script->constraintsEvent(constraints);
00758     }
00759 }
00760 
00761 void Applet::initExtenderItem(ExtenderItem *item)
00762 {
00763     if (d->script) {
00764         emit extenderItemRestored(item);
00765     } else {
00766         kWarning() << "Missing implementation of initExtenderItem in the applet "
00767                    << item->config().readEntry("SourceAppletPluginName", "")
00768                    << "!\n Any applet that uses extenders should implement initExtenderItem to "
00769                    << "instantiate a widget. Destroying the item...";
00770         item->destroy();
00771     }
00772 }
00773 
00774 Extender *Applet::extender() const
00775 {
00776     if (!d->extender) {
00777         new Extender(const_cast<Applet*>(this));
00778     }
00779 
00780     return d->extender.data();
00781 }
00782 
00783 void Applet::setBusy(bool busy)
00784 {
00785     if (busy) {
00786         if (!d->busyWidget && !d->busyWidgetTimer.isActive()) {
00787             d->busyWidgetTimer.start(500, this);
00788         }
00789     } else {
00790         d->busyWidgetTimer.stop();
00791         if (d->busyWidget) {
00792             d->busyWidget = 0;
00793             d->destroyMessageOverlay();
00794         }
00795     }
00796 }
00797 
00798 bool Applet::isBusy() const
00799 {
00800     return d->busyWidgetTimer.isActive() || (d->busyWidget && d->busyWidget->isVisible());
00801 }
00802 
00803 QString Applet::name() const
00804 {
00805     if (d->isContainment) {
00806         const Containment *c = qobject_cast<const Containment*>(this);
00807         if (c && c->d->isPanelContainment()) {
00808             return i18n("Panel");
00809         } else if (!d->appletDescription.isValid()) {
00810             return i18n("Unknown");
00811         } else {
00812             return d->appletDescription.name();
00813         }
00814     } else if (!d->appletDescription.isValid()) {
00815         return i18n("Unknown Widget");
00816     }
00817 
00818     return d->appletDescription.name();
00819 }
00820 
00821 QFont Applet::font() const
00822 {
00823     return QApplication::font();
00824 }
00825 
00826 QString Applet::icon() const
00827 {
00828     if (!d->appletDescription.isValid()) {
00829         return QString();
00830     }
00831 
00832     return d->appletDescription.icon();
00833 }
00834 
00835 QString Applet::pluginName() const
00836 {
00837     if (!d->appletDescription.isValid()) {
00838         return QString();
00839     }
00840 
00841     return d->appletDescription.pluginName();
00842 }
00843 
00844 bool Applet::shouldConserveResources() const
00845 {
00846 #ifndef PLASMA_NO_SOLID
00847     return Solid::PowerManagement::appShouldConserveResources();
00848 #else
00849     return true;
00850 #endif
00851 }
00852 
00853 QString Applet::category() const
00854 {
00855     if (!d->appletDescription.isValid()) {
00856         return i18nc("misc category", "Miscellaneous");
00857     }
00858 
00859     return d->appletDescription.category();
00860 }
00861 
00862 QString Applet::category(const KPluginInfo &applet)
00863 {
00864     return applet.property("X-KDE-PluginInfo-Category").toString();
00865 }
00866 
00867 QString Applet::category(const QString &appletName)
00868 {
00869     if (appletName.isEmpty()) {
00870         return QString();
00871     }
00872 
00873     const QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(appletName);
00874     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
00875 
00876     if (offers.isEmpty()) {
00877         return QString();
00878     }
00879 
00880     return offers.first()->property("X-KDE-PluginInfo-Category").toString();
00881 }
00882 
00883 ImmutabilityType Applet::immutability() const
00884 {
00885     // if this object is itself system immutable, then just return that; it's the most
00886     // restrictive setting possible and will override anything that might be happening above it
00887     // in the Corona->Containment->Applet hierarchy
00888     if (d->transient || (d->mainConfig && d->mainConfig->isImmutable())) {
00889         return SystemImmutable;
00890     }
00891 
00892     //Returning the more strict immutability between the applet immutability, Containment and Corona
00893     ImmutabilityType upperImmutability = Mutable;
00894     Containment *cont = d->isContainment ? 0 : containment();
00895 
00896     if (cont) {
00897         upperImmutability = cont->immutability();
00898     } else if (Corona *corona = qobject_cast<Corona*>(scene())) {
00899         upperImmutability = corona->immutability();
00900     }
00901 
00902     if (upperImmutability != Mutable) {
00903         // it's either system or user immutable, and we already check for local system immutability,
00904         // so upperImmutability is guaranteed to be as or more severe as this object's immutability
00905         return upperImmutability;
00906     } else {
00907         return d->immutability;
00908     }
00909 }
00910 
00911 void Applet::setImmutability(const ImmutabilityType immutable)
00912 {
00913     if (d->immutability == immutable || immutable == Plasma::SystemImmutable) {
00914         // we do not store system immutability in d->immutability since that gets saved
00915         // out to the config file; instead, we check with
00916         // the config group itself for this information at all times. this differs from
00917         // corona, where SystemImmutability is stored in d->immutability.
00918         return;
00919     }
00920 
00921     d->immutability = immutable;
00922     updateConstraints(ImmutableConstraint);
00923 }
00924 
00925 Applet::BackgroundHints Applet::backgroundHints() const
00926 {
00927     return d->backgroundHints;
00928 }
00929 
00930 void Applet::setBackgroundHints(const BackgroundHints hints)
00931 {
00932     if (d->backgroundHints == hints) {
00933         return;
00934     }
00935 
00936     d->backgroundHints = hints;
00937     d->preferredBackgroundHints = hints;
00938 
00939     //Draw the standard background?
00940     if ((hints & StandardBackground) || (hints & TranslucentBackground)) {
00941         if (!d->background) {
00942             d->background = new Plasma::FrameSvg(this);
00943             QObject::connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(themeChanged()));
00944         }
00945 
00946         if ((hints & TranslucentBackground) &&
00947             Plasma::Theme::defaultTheme()->currentThemeHasImage("widgets/translucentbackground")) {
00948             d->background->setImagePath("widgets/translucentbackground");
00949         } else {
00950             d->background->setImagePath("widgets/background");
00951         }
00952 
00953         d->background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
00954         qreal left, top, right, bottom;
00955         d->background->getMargins(left, top, right, bottom);
00956         setContentsMargins(left, right, top, bottom);
00957         QSizeF fitSize(left + right, top + bottom);
00958         d->background->resizeFrame(boundingRect().size());
00959 
00960         //if the background has an "overlay" element decide a random position for it and then save it so it's consistent across plasma starts
00961         if (d->background->hasElement("overlay")) {
00962             QSize overlaySize = d->background->elementSize("overlay");
00963 
00964             //position is in the boundaries overlaySize.width()*2, overlaySize.height()
00965             qsrand(id());
00966             d->background->d->overlayPos.rx() = - (overlaySize.width() /2) + (overlaySize.width() /4) * (qrand() % (4 + 1));
00967             d->background->d->overlayPos.ry() = (- (overlaySize.height() /2) + (overlaySize.height() /4) * (qrand() % (4 + 1)))/2;
00968         }
00969     } else if (d->background) {
00970         qreal left, top, right, bottom;
00971         d->background->getMargins(left, top, right, bottom);
00972 
00973         delete d->background;
00974         d->background = 0;
00975         setContentsMargins(0, 0, 0, 0);
00976     }
00977 
00978     update();
00979 }
00980 
00981 bool Applet::hasFailedToLaunch() const
00982 {
00983     return d->failed;
00984 }
00985 
00986 void Applet::paintWindowFrame(QPainter *painter,
00987                               const QStyleOptionGraphicsItem *option, QWidget *widget)
00988 {
00989     Q_UNUSED(painter)
00990     Q_UNUSED(option)
00991     Q_UNUSED(widget)
00992     //Here come the code for the window frame
00993     //kDebug() << windowFrameGeometry();
00994     //painter->drawRoundedRect(windowFrameGeometry(), 5, 5);
00995 }
00996 
00997 bool Applet::configurationRequired() const
00998 {
00999     return d->needsConfig;
01000 }
01001 
01002 void Applet::setConfigurationRequired(bool needsConfig, const QString &reason)
01003 {
01004     if (d->needsConfig == needsConfig) {
01005         return;
01006     }
01007 
01008     d->needsConfig = needsConfig;
01009 
01010     if (!needsConfig) {
01011         d->destroyMessageOverlay();
01012         return;
01013     }
01014 
01015     d->createMessageOverlay(true);
01016     d->messageOverlay->opacity = 0.4;
01017 
01018     QGraphicsGridLayout *configLayout = new QGraphicsGridLayout(d->messageOverlay);
01019     configLayout->setContentsMargins(0, 0, 0, 0);
01020 
01021   //  configLayout->addStretch();
01022     configLayout->setColumnStretchFactor(0, 5);
01023     configLayout->setColumnStretchFactor(2, 5);
01024     configLayout->setRowStretchFactor(0, 5);
01025     configLayout->setRowStretchFactor(3, 5);
01026 
01027     int row = 1;
01028     if (!reason.isEmpty()) {
01029         Label *explanation = new Label(d->messageOverlay);
01030         explanation->setText(reason);
01031         configLayout->addItem(explanation, row, 1);
01032         configLayout->setColumnStretchFactor(1, 5);
01033         ++row;
01034         configLayout->setAlignment(explanation, Qt::AlignBottom | Qt::AlignCenter);
01035     }
01036 
01037     PushButton *configWidget = new PushButton(d->messageOverlay);
01038     if (!qobject_cast<Plasma::PopupApplet *>(this) && (formFactor() == Plasma::Horizontal || formFactor() == Plasma::Vertical)) {
01039         configWidget->setImage("widgets/configuration-icons", "configure");
01040         configWidget->setMaximumSize(24,24);
01041         configWidget->setMinimumSize(24,24);
01042     } else {
01043         configWidget->setText(i18n("Configure..."));
01044     }
01045     connect(configWidget, SIGNAL(clicked()), this, SLOT(showConfigurationInterface()));
01046     configLayout->addItem(configWidget, row, 1);
01047 
01048     //configLayout->setAlignment(configWidget, Qt::AlignTop | Qt::AlignCenter);
01049     //configLayout->addStretch();
01050 
01051     d->messageOverlay->show();
01052 }
01053 
01054 void Applet::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons)
01055 {
01056     if (message.isEmpty()) {
01057         d->destroyMessageOverlay();
01058         return;
01059     }
01060 
01061     Corona *corona = qobject_cast<Corona *>(scene());
01062     QGraphicsWidget *mainWidget = new QGraphicsWidget;
01063 
01064     QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(mainWidget);
01065     mainLayout->setOrientation(Qt::Vertical);
01066     mainLayout->addStretch();
01067 
01068     QGraphicsLinearLayout *messageLayout = new QGraphicsLinearLayout();
01069     messageLayout->setOrientation(Qt::Horizontal);
01070 
01071     QGraphicsLinearLayout *buttonLayout = new QGraphicsLinearLayout();
01072     buttonLayout->setOrientation(Qt::Horizontal);
01073 
01074     mainLayout->addItem(messageLayout);
01075     mainLayout->addItem(buttonLayout);
01076     mainLayout->addStretch();
01077 
01078     IconWidget *messageIcon = new IconWidget(mainWidget);
01079     Label *messageText = new Label(mainWidget);
01080     messageText->nativeWidget()->setWordWrap(true);
01081 
01082     messageLayout->addStretch();
01083     messageLayout->addItem(messageIcon);
01084     messageLayout->addItem(messageText);
01085     messageLayout->addStretch();
01086 
01087     messageIcon->setIcon(icon);
01088     messageText->setText(message);
01089 
01090     buttonLayout->addStretch();
01091 
01092     if (buttons & ButtonOk) {
01093         d->messageOkButton = new PushButton(mainWidget);
01094         d->messageOkButton.data()->setText(i18n("&OK"));
01095         d->messageOkButton.data()->setIcon(KIcon("dialog-ok"));
01096         buttonLayout->addItem(d->messageOkButton.data());
01097         connect(d->messageOkButton.data(), SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01098     }
01099 
01100     if (buttons & ButtonYes) {
01101         d->messageYesButton = new PushButton(mainWidget);
01102         d->messageYesButton.data()->setText(i18n("&Yes"));
01103         buttonLayout->addItem(d->messageYesButton.data());
01104         connect(d->messageYesButton.data(), SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01105     }
01106 
01107     if (buttons & ButtonNo) {
01108         d->messageNoButton = new PushButton(mainWidget);
01109         d->messageNoButton.data()->setText(i18n("&No"));
01110         buttonLayout->addItem(d->messageNoButton.data());
01111         connect(d->messageNoButton.data(), SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01112     }
01113 
01114     if (buttons & ButtonCancel) {
01115         d->messageCancelButton = new PushButton(mainWidget);
01116         d->messageCancelButton.data()->setText(i18n("&Cancel"));
01117         d->messageCancelButton.data()->setIcon(KIcon("dialog-cancel"));
01118         buttonLayout->addItem(d->messageCancelButton.data());
01119         connect(d->messageCancelButton.data(), SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01120     }
01121 
01122     d->messageCloseAction = new QAction(d->messageOverlay);
01123     d->messageCloseAction.data()->setShortcut(Qt::Key_Escape);
01124     mainWidget->addAction(d->messageCloseAction.data());
01125     connect(d->messageCloseAction.data(), SIGNAL(triggered()), this, SLOT(destroyMessageOverlay()));
01126 
01127     buttonLayout->addStretch();
01128 
01129     mainWidget->adjustSize();
01130     QSizeF hint = mainWidget->preferredSize();
01131     if (hint.height() > size().height() || hint.width() > size().width()) {
01132         // either a collapsed popup in h/v form factor or just too small,
01133         // so show it in a dialog associated with ourselves
01134         if (corona) {
01135             corona->addOffscreenWidget(mainWidget);
01136         }
01137 
01138         if (d->messageDialog) {
01139             delete d->messageDialog.data()->graphicsWidget();
01140         } else {
01141             d->messageDialog = new Plasma::Dialog;
01142         }
01143 
01144         ToolTipManager::self()->hide(this);
01145         KWindowSystem::setOnAllDesktops(d->messageDialog.data()->winId(), true);
01146         KWindowSystem::setState(d->messageDialog.data()->winId(), NET::SkipTaskbar | NET::SkipPager);
01147         d->messageDialog.data()->setGraphicsWidget(mainWidget);
01148         connect(d->messageDialog.data(), SIGNAL(destroyed(QObject*)), mainWidget, SLOT(deleteLater()));
01149 
01150         // if we are going to show it in a popup, then at least make sure it can be dismissed
01151         if (buttonLayout->count() < 1) {
01152             PushButton *ok = new PushButton(mainWidget);
01153             ok->setText(i18n("OK"));
01154             ok->setIcon(KIcon("dialog-ok"));
01155             buttonLayout->addItem(ok);
01156             connect(ok, SIGNAL(clicked()), this, SLOT(destroyMessageOverlay()));
01157         }
01158     } else {
01159         delete d->messageDialog.data();
01160         d->createMessageOverlay();
01161         d->messageOverlay->opacity = 0.8;
01162         mainWidget->setParentItem(d->messageOverlay);
01163         QGraphicsLinearLayout *l = new QGraphicsLinearLayout(d->messageOverlay);
01164         l->addItem(mainWidget);
01165     }
01166 
01167     if (d->messageDialog) {
01168         QPoint pos = geometry().topLeft().toPoint();
01169         if (corona) {
01170             pos = corona->popupPosition(this, d->messageDialog.data()->size());
01171         }
01172 
01173         d->messageDialog.data()->move(pos);
01174         d->messageDialog.data()->animatedShow(locationToDirection(location()));
01175     } else {
01176         d->messageOverlay->show();
01177     }
01178 }
01179 
01180 QVariantList Applet::startupArguments() const
01181 {
01182     return d->args;
01183 }
01184 
01185 ItemStatus Applet::status() const
01186 {
01187     return d->itemStatus;
01188 }
01189 
01190 void Applet::setStatus(const ItemStatus status)
01191 {
01192     d->itemStatus = status;
01193     emit newStatus(status);
01194 }
01195 
01196 void Applet::flushPendingConstraintsEvents()
01197 {
01198     if (d->pendingConstraints == NoConstraint) {
01199         return;
01200     }
01201 
01202     if (d->constraintsTimer.isActive()) {
01203         d->constraintsTimer.stop();
01204     }
01205 
01206     //kDebug() << "fushing constraints: " << d->pendingConstraints << "!!!!!!!!!!!!!!!!!!!!!!!!!!!";
01207     Plasma::Constraints c = d->pendingConstraints;
01208     d->pendingConstraints = NoConstraint;
01209 
01210     if (c & Plasma::StartupCompletedConstraint) {
01211         //common actions
01212         bool unlocked = immutability() == Mutable;
01213         QAction *closeApplet = d->actions->action("remove");
01214         if (closeApplet) {
01215             closeApplet->setEnabled(unlocked);
01216             closeApplet->setVisible(unlocked);
01217             connect(closeApplet, SIGNAL(triggered(bool)), this, SLOT(selectItemToDestroy()), Qt::UniqueConnection);
01218         }
01219 
01220         QAction *configAction = d->actions->action("configure");
01221         if (configAction) {
01222             if (d->isContainment) {
01223                 connect(configAction, SIGNAL(triggered(bool)), this, SLOT(requestConfiguration()), Qt::UniqueConnection);
01224             } else {
01225                 connect(configAction, SIGNAL(triggered(bool)), this, SLOT(showConfigurationInterface()), Qt::UniqueConnection);
01226             }
01227 
01228             if (d->hasConfigurationInterface) {
01229                 bool canConfig = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
01230                 configAction->setVisible(canConfig);
01231                 configAction->setEnabled(canConfig);
01232             }
01233         }
01234 
01235         QAction *runAssociatedApplication = d->actions->action("run associated application");
01236         if (runAssociatedApplication) {
01237             connect(runAssociatedApplication, SIGNAL(triggered(bool)), this, SLOT(runAssociatedApplication()), Qt::UniqueConnection);
01238         }
01239 
01240         d->updateShortcuts();
01241         Corona * corona = qobject_cast<Corona*>(scene());
01242         if (corona) {
01243             connect(corona, SIGNAL(shortcutsChanged()), this, SLOT(updateShortcuts()), Qt::UniqueConnection);
01244         }
01245     }
01246 
01247     if (c & Plasma::ImmutableConstraint) {
01248         bool unlocked = immutability() == Mutable;
01249         QAction *action = d->actions->action("remove");
01250         if (action) {
01251             action->setVisible(unlocked);
01252             action->setEnabled(unlocked);
01253         }
01254 
01255         action = d->actions->action("configure");
01256         if (action && d->hasConfigurationInterface) {
01257             bool canConfig = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
01258             action->setVisible(canConfig);
01259             action->setEnabled(canConfig);
01260         }
01261 
01262         if (d->extender) {
01263             foreach (ExtenderItem *item, d->extender.data()->attachedItems()) {
01264                 item->d->setMovable(unlocked);
01265             }
01266         }
01267 
01268         if (!unlocked && d->handle) {
01269             AppletHandle *h = d->handle.data();
01270             disconnect(this);
01271 
01272             QGraphicsScene *s = scene();
01273             if (s && h->scene() == s) {
01274                 s->removeItem(h);
01275             }
01276 
01277             h->deleteLater();
01278         }
01279 
01280         emit immutabilityChanged(immutability());
01281     }
01282 
01283     if (c & Plasma::SizeConstraint) {
01284         d->positionMessageOverlay();
01285 
01286         if (d->started && layout()) {
01287             layout()->updateGeometry();
01288         }
01289     }
01290 
01291     if (c & Plasma::FormFactorConstraint) {
01292         FormFactor f = formFactor();
01293         if (!d->isContainment && f != Vertical && f != Horizontal) {
01294             setBackgroundHints(d->preferredBackgroundHints);
01295         } else {
01296             BackgroundHints hints = d->preferredBackgroundHints;
01297             setBackgroundHints(NoBackground);
01298             d->preferredBackgroundHints = hints;
01299         }
01300 
01301         if (d->failed) {
01302             if (f == Vertical || f == Horizontal) {
01303                 QGraphicsLayoutItem *item = layout()->itemAt(1);
01304                 layout()->removeAt(1);
01305                 delete item;
01306             }
01307         }
01308 
01309         // avoid putting rotated applets in panels
01310         if (f == Vertical || f == Horizontal) {
01311             QTransform at;
01312             at.rotateRadians(0);
01313             setTransform(at);
01314         }
01315 
01316         //was a size saved for a particular form factor?
01317         if (d->sizeForFormFactor.contains(f)) {
01318             resize(d->sizeForFormFactor.value(f));
01319         }
01320     }
01321 
01322     if (!size().isEmpty() &&
01323         ((c & Plasma::StartupCompletedConstraint) || (c & Plasma::SizeConstraint && !(c & Plasma::FormFactorConstraint)))) {
01324         d->sizeForFormFactor[formFactor()] = size();
01325     }
01326 
01327     if (c & Plasma::SizeConstraint || c & Plasma::FormFactorConstraint) {
01328         if (aspectRatioMode() == Plasma::Square || aspectRatioMode() == Plasma::ConstrainedSquare) {
01329             // enforce square size in panels
01330             //save the old size policy. since ignored doesn't (yet) have a valid use case in containments, use it as special unset value
01331             if (d->preferredSizePolicy == QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)) {
01332                 d->preferredSizePolicy = sizePolicy();
01333             }
01334             if (formFactor() == Horizontal) {
01335                 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
01336             } else if (formFactor() == Vertical) {
01337                 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
01338             } else if (d->preferredSizePolicy != QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)) {
01339                 setSizePolicy(d->preferredSizePolicy);
01340             }
01341         }
01342         updateGeometry();
01343     }
01344 
01345     // now take care of constraints in special subclasses: Contaiment and PopupApplet
01346     Containment* containment = qobject_cast<Plasma::Containment*>(this);
01347     if (d->isContainment && containment) {
01348         containment->d->containmentConstraintsEvent(c);
01349     }
01350 
01351     PopupApplet* popup = qobject_cast<Plasma::PopupApplet*>(this);
01352     if (popup) {
01353         popup->d->popupConstraintsEvent(c);
01354     }
01355 
01356     // pass the constraint on to the actual subclass
01357     constraintsEvent(c);
01358 
01359     if (c & StartupCompletedConstraint) {
01360         // start up is done, we can now go do a mod timer
01361         if (d->modificationsTimer) {
01362             if (d->modificationsTimer->isActive()) {
01363                 d->modificationsTimer->stop();
01364             }
01365         } else {
01366             d->modificationsTimer = new QBasicTimer;
01367         }
01368     }
01369 }
01370 
01371 int Applet::type() const
01372 {
01373     return Type;
01374 }
01375 
01376 QList<QAction*> Applet::contextualActions()
01377 {
01378     //kDebug() << "empty context actions";
01379     return d->script ? d->script->contextualActions() : QList<QAction*>();
01380 }
01381 
01382 QAction *Applet::action(QString name) const
01383 {
01384     return d->actions->action(name);
01385 }
01386 
01387 void Applet::addAction(QString name, QAction *action)
01388 {
01389     d->actions->addAction(name, action);
01390 }
01391 
01392 void Applet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
01393 {
01394     if (!d->started) {
01395         //kDebug() << "not started";
01396         return;
01397     }
01398 
01399     if (transform().isRotating()) {
01400         painter->setRenderHint(QPainter::SmoothPixmapTransform);
01401         painter->setRenderHint(QPainter::Antialiasing);
01402     }
01403 
01404     if (d->background &&
01405         formFactor() != Plasma::Vertical &&
01406         formFactor() != Plasma::Horizontal) {
01407         //kDebug() << "option rect is" << option->rect;
01408         d->background->paintFrame(painter);
01409     }
01410 
01411     if (d->failed) {
01412         //kDebug() << "failed!";
01413         return;
01414     }
01415 
01416     qreal left, top, right, bottom;
01417     getContentsMargins(&left, &top, &right, &bottom);
01418     QRect contentsRect = QRectF(QPointF(0, 0),
01419                                 boundingRect().size()).adjusted(left, top, -right, -bottom).toRect();
01420 
01421     if (widget && d->isContainment) {
01422         // note that the widget we get is actually the viewport of the view, not the view itself
01423         View* v = qobject_cast<Plasma::View*>(widget->parent());
01424         Containment* c = qobject_cast<Plasma::Containment*>(this);
01425 
01426         if (!v || v->isWallpaperEnabled()) {
01427 
01428             // paint the wallpaper
01429             if (c && c->drawWallpaper() && c->wallpaper()) {
01430                 Wallpaper *w = c->wallpaper();
01431                 if (!w->isInitialized()) {
01432                     // delayed paper initialization
01433                     KConfigGroup wallpaperConfig = c->config();
01434                     wallpaperConfig = KConfigGroup(&wallpaperConfig, "Wallpaper");
01435                     wallpaperConfig = KConfigGroup(&wallpaperConfig, w->pluginName());
01436                     w->restore(wallpaperConfig);
01437                     disconnect(w, SIGNAL(update(const QRectF&)), this, SLOT(updateRect(const QRectF&)));
01438                     connect(w, SIGNAL(update(const QRectF&)), this, SLOT(updateRect(const QRectF&)));
01439                 }
01440 
01441                 painter->save();
01442                 c->wallpaper()->paint(painter, option->exposedRect);
01443                 painter->restore();
01444             }
01445 
01446             // .. and now paint the actual containment interface, but with
01447             //  a Containment style option based on the one we get
01448             //  the view must be assigned only if its containment is actually our own
01449             Containment::StyleOption coption(*option);
01450             if (v && v->containment() == containment()) {
01451                 coption.view = v;
01452             }
01453             paintInterface(painter, &coption, contentsRect);
01454         }
01455     } else {
01456         //kDebug() << "paint interface of" << (QObject*) this;
01457         // paint the applet's interface
01458         paintInterface(painter, option, contentsRect);
01459     }
01460 }
01461 
01462 void Applet::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
01463 {
01464     if (d->script) {
01465         d->script->paintInterface(painter, option, contentsRect);
01466     } else {
01467         //kDebug() << "Applet::paintInterface() default impl";
01468     }
01469 }
01470 
01471 FormFactor Applet::formFactor() const
01472 {
01473     Containment *c = containment();
01474     QGraphicsWidget *pw = qobject_cast<QGraphicsWidget *>(parent());
01475     if (!pw) {
01476         pw = dynamic_cast<QGraphicsWidget *>(parentItem());
01477     }
01478     Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(pw);
01479     //assumption: this loop is usually is -really- short or doesn't run at all
01480     while (!parentApplet && pw && pw->parentWidget()) {
01481         QGraphicsWidget *parentWidget = qobject_cast<QGraphicsWidget *>(pw->parent());
01482         if (!parentWidget) {
01483             parentWidget = dynamic_cast<QGraphicsWidget *>(pw->parentItem());
01484         }
01485         pw = parentWidget;
01486         parentApplet = qobject_cast<Plasma::Applet *>(pw);
01487     }
01488 
01489 
01490     const PopupApplet *pa = dynamic_cast<const PopupApplet *>(this);
01491 
01492     //if the applet is in a widget that isn't a containment
01493     //try to retrieve the formFactor from the parent size
01494     //we can't use our own sizeHint here because it needs formFactor, so endless recursion.
01495     // a popupapplet can always be constrained.
01496     // a normal applet should to but
01497     //FIXME: not always constrained to not break systemmonitor
01498     if (parentApplet && parentApplet != c && c != this && (pa || layout())) {
01499         if (pa || (parentApplet->size().height() < layout()->effectiveSizeHint(Qt::MinimumSize).height())) {
01500             return Plasma::Horizontal;
01501         } else if (pa || (parentApplet->size().width() < layout()->effectiveSizeHint(Qt::MinimumSize).width())) {
01502             return Plasma::Vertical;
01503         }
01504         return parentApplet->formFactor();
01505     }
01506 
01507     return c ? c->d->formFactor : Plasma::Planar;
01508 }
01509 
01510 Containment *Applet::containment() const
01511 {
01512     if (d->isContainment) {
01513         Containment *c = qobject_cast<Containment*>(const_cast<Applet*>(this));
01514         if (c) {
01515             return c;
01516         }
01517     }
01518 
01519     QGraphicsItem *parent = parentItem();
01520     Containment *c = 0;
01521 
01522     while (parent) {
01523         Containment *possibleC = dynamic_cast<Containment*>(parent);
01524         if (possibleC && possibleC->Applet::d->isContainment) {
01525             c = possibleC;
01526             break;
01527         }
01528         parent = parent->parentItem();
01529     }
01530 
01531     if (!c) {
01532         //if the applet is an offscreen widget its parentItem will be 0, while its parent
01533         //will be its parentWidget, so here we check the QObject hierarchy.
01534         QObject *objParent = this->parent();
01535         while (objParent) {
01536             Containment *possibleC = qobject_cast<Containment*>(objParent);
01537             if (possibleC && possibleC->Applet::d->isContainment) {
01538                 c = possibleC;
01539                 break;
01540             }
01541             objParent = objParent->parent();
01542         }
01543     }
01544 
01545     return c;
01546 }
01547 
01548 void Applet::setGlobalShortcut(const KShortcut &shortcut)
01549 {
01550     if (!d->activationAction) {
01551         d->activationAction = new KAction(this);
01552         d->activationAction->setText(i18n("Activate %1 Widget", name()));
01553         d->activationAction->setObjectName(QString("activate widget %1").arg(id())); // NO I18N
01554         connect(d->activationAction, SIGNAL(triggered()), this, SIGNAL(activate()));
01555         connect(d->activationAction, SIGNAL(globalShortcutChanged(QKeySequence)),
01556                 this, SLOT(globalShortcutChanged()));
01557 
01558         QList<QWidget *> widgets = d->actions->associatedWidgets();
01559         foreach (QWidget *w, widgets) {
01560             w->addAction(d->activationAction);
01561         }
01562     }
01563 
01564     //kDebug() << "before" << shortcut.primary() << d->activationAction->globalShortcut().primary();
01565     d->activationAction->setGlobalShortcut(
01566         shortcut,
01567         KAction::ShortcutTypes(KAction::ActiveShortcut | KAction::DefaultShortcut),
01568         KAction::NoAutoloading);
01569     d->globalShortcutChanged();
01570 }
01571 
01572 void AppletPrivate::globalShortcutChanged()
01573 {
01574     if (!activationAction) {
01575         return;
01576     }
01577 
01578     KConfigGroup shortcutConfig(mainConfigGroup(), "Shortcuts");
01579     shortcutConfig.writeEntry("global", activationAction->globalShortcut().toString());
01580     scheduleModificationNotification();
01581     //kDebug() << "after" << shortcut.primary() << d->activationAction->globalShortcut().primary();
01582 }
01583 
01584 KShortcut Applet::globalShortcut() const
01585 {
01586     if (d->activationAction) {
01587         return d->activationAction->globalShortcut();
01588     }
01589 
01590     return KShortcut();
01591 }
01592 
01593 bool Applet::isPopupShowing() const
01594 {
01595     return false;
01596 }
01597 
01598 void Applet::addAssociatedWidget(QWidget *widget)
01599 {
01600     d->actions->addAssociatedWidget(widget);
01601 }
01602 
01603 void Applet::removeAssociatedWidget(QWidget *widget)
01604 {
01605     d->actions->removeAssociatedWidget(widget);
01606 }
01607 
01608 Location Applet::location() const
01609 {
01610     Containment *c = containment();
01611     return c ? c->d->location : Plasma::Desktop;
01612 }
01613 
01614 Context *Applet::context() const
01615 {
01616     Containment *c = containment();
01617     Q_ASSERT(c);
01618     return c->d->context();
01619 }
01620 
01621 Plasma::AspectRatioMode Applet::aspectRatioMode() const
01622 {
01623     return d->aspectRatioMode;
01624 }
01625 
01626 void Applet::setAspectRatioMode(Plasma::AspectRatioMode mode)
01627 {
01628     PopupApplet *popup = qobject_cast<PopupApplet *>(this);
01629     if (popup && popup->d->dialogPtr) {
01630         popup->d->dialogPtr.data()->setAspectRatioMode(mode);
01631         popup->d->savedAspectRatio = mode;
01632     }
01633 
01634     d->aspectRatioMode = mode;
01635 }
01636 
01637 void Applet::registerAsDragHandle(QGraphicsItem *item)
01638 {
01639     if (!item || d->registeredAsDragHandle.contains(item)) {
01640         return;
01641     }
01642 
01643     d->registeredAsDragHandle.insert(item);
01644     item->installSceneEventFilter(this);
01645 }
01646 
01647 void Applet::unregisterAsDragHandle(QGraphicsItem *item)
01648 {
01649     if (!item) {
01650         return;
01651     }
01652 
01653     if (d->registeredAsDragHandle.remove(item)) {
01654         if (item != this) {
01655             item->removeSceneEventFilter(this);
01656         }
01657     }
01658 }
01659 
01660 bool Applet::isRegisteredAsDragHandle(QGraphicsItem *item)
01661 {
01662     return d->registeredAsDragHandle.contains(item);
01663 }
01664 
01665 bool Applet::hasConfigurationInterface() const
01666 {
01667     return d->hasConfigurationInterface;
01668 }
01669 
01670 void Applet::publish(AnnouncementMethods methods, const QString &resourceName)
01671 {
01672     if (d->package) {
01673         d->package->d->publish(methods);
01674     } else if (d->appletDescription.isValid()) {
01675         if (!d->service) {
01676             d->service = new PlasmoidService(this);
01677         }
01678 
01679         kDebug() << "publishing package under name " << resourceName;
01680         PackageMetadata pm;
01681         pm.setName(d->appletDescription.name());
01682         pm.setDescription(d->appletDescription.comment());
01683         pm.setIcon(d->appletDescription.icon());
01684         d->service->d->publish(methods, resourceName, pm);
01685     } else {
01686         kDebug() << "Can not publish invalid applets.";
01687     }
01688 }
01689 
01690 void Applet::unpublish()
01691 {
01692     if (d->package) {
01693         d->package->d->unpublish();
01694     } else {
01695         if (d->service) {
01696             d->service->d->unpublish();
01697         }
01698     }
01699 }
01700 
01701 bool Applet::isPublished() const
01702 {
01703     if (d->package) {
01704         return d->package->d->isPublished();
01705     } else {
01706         if (d->service) {
01707             return d->service->d->isPublished();
01708         } else {
01709             return false;
01710         }
01711     }
01712 }
01713 
01714 void Applet::setHasConfigurationInterface(bool hasInterface)
01715 {
01716     if (hasInterface == d->hasConfigurationInterface) {
01717         return;
01718     }
01719 
01720     QAction *configAction = d->actions->action("configure");
01721     if (configAction) {
01722         bool enable = hasInterface;
01723         if (enable) {
01724             const bool unlocked = immutability() == Mutable;
01725             enable = unlocked || KAuthorized::authorize("plasma/allow_configure_when_locked");
01726         }
01727         configAction->setEnabled(enable);
01728     }
01729 
01730     d->hasConfigurationInterface = hasInterface;
01731 }
01732 
01733 KActionCollection* AppletPrivate::defaultActions(QObject *parent)
01734 {
01735     KActionCollection *actions = new KActionCollection(parent);
01736     actions->setConfigGroup("Shortcuts-Applet");
01737 
01738     KAction *configAction = actions->addAction("configure");
01739     configAction->setAutoRepeat(false);
01740     configAction->setText(i18n("Widget Settings"));
01741     configAction->setIcon(KIcon("configure"));
01742     configAction->setShortcut(KShortcut("alt+d, s"));
01743     configAction->setData(AbstractToolBox::ConfigureTool);
01744 
01745     KAction *closeApplet = actions->addAction("remove");
01746     closeApplet->setAutoRepeat(false);
01747     closeApplet->setText(i18n("Remove this Widget"));
01748     closeApplet->setIcon(KIcon("edit-delete"));
01749     closeApplet->setShortcut(KShortcut("alt+d, r"));
01750     closeApplet->setData(AbstractToolBox::DestructiveTool);
01751 
01752     KAction *runAssociatedApplication = actions->addAction("run associated application");
01753     runAssociatedApplication->setAutoRepeat(false);
01754     runAssociatedApplication->setText(i18n("Run the Associated Application"));
01755     runAssociatedApplication->setIcon(KIcon("system-run"));
01756     runAssociatedApplication->setShortcut(KShortcut("alt+d, t"));
01757     runAssociatedApplication->setVisible(false);
01758     runAssociatedApplication->setEnabled(false);
01759     runAssociatedApplication->setData(AbstractToolBox::ControlTool);
01760 
01761     return actions;
01762 }
01763 
01764 bool Applet::eventFilter(QObject *o, QEvent *e)
01765 {
01766     return QObject::eventFilter(o, e);
01767 }
01768 
01769 bool Applet::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
01770 {
01771     if (watched == this) {
01772         switch (event->type()) {
01773             case QEvent::GraphicsSceneHoverEnter:
01774                 //kDebug() << "got hoverenterEvent" << immutability() << " " << immutability();
01775                 if (immutability() == Mutable) {
01776                     QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
01777                     if (d->handle) {
01778                         d->handle.data()->setHoverPos(he->pos());
01779                     } else {
01780                         //kDebug() << "generated applet handle";
01781                         AppletHandle *handle = new AppletHandle(containment(), this, he->pos());
01782                         connect(handle, SIGNAL(disappearDone(AppletHandle*)),
01783                                 this, SLOT(handleDisappeared(AppletHandle*)));
01784                         connect(this, SIGNAL(geometryChanged()),
01785                                 handle, SLOT(appletResized()));
01786                         d->handle = handle;
01787                     }
01788                 }
01789             break;
01790 
01791             case QEvent::GraphicsSceneHoverMove:
01792                 if (d->handle && !d->handle.data()->shown() && immutability() == Mutable) {
01793                     QGraphicsSceneHoverEvent *he = static_cast<QGraphicsSceneHoverEvent*>(event);
01794                     d->handle.data()->setHoverPos(he->pos());
01795                 }
01796             break;
01797 
01798         default:
01799             break;
01800         }
01801 
01802     }
01803 
01804     switch (event->type()) {
01805     case QEvent::GraphicsSceneMouseMove:
01806     case QEvent::GraphicsSceneMousePress:
01807     case QEvent::GraphicsSceneMouseRelease:
01808     {
01809         // don't move when the containment is not mutable,
01810         // in the rare case the containment doesn't exists consider it as mutable
01811         if ((flags() & ItemIsMovable) && d->registeredAsDragHandle.contains(watched)) {
01812             Containment *c = containment();
01813             if (!c || c->immutability() == Mutable) {
01814                 scene()->sendEvent(this, event);
01815                 return false;
01816             }
01817         }
01818         break;
01819     }
01820 
01821     default:
01822         break;
01823     }
01824 
01825     return QGraphicsItem::sceneEventFilter(watched, event);
01826 }
01827 
01828 void Applet::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
01829 {
01830     if (immutability() == Mutable && formFactor() == Plasma::Planar && (flags() & ItemIsMovable)) {
01831         QGraphicsWidget::mouseMoveEvent(event);
01832     }
01833 }
01834 
01835 void Applet::focusInEvent(QFocusEvent *event)
01836 {
01837     if (!isContainment() && containment()) {
01838         //focusing an applet may trigger this event again, but we won't be here more than twice
01839         containment()->d->focusApplet(this);
01840     }
01841 
01842     QGraphicsWidget::focusInEvent(event);
01843 }
01844 
01845 void Applet::resizeEvent(QGraphicsSceneResizeEvent *event)
01846 {
01847     QGraphicsWidget::resizeEvent(event);
01848 
01849     if (d->background) {
01850         d->background->resizeFrame(boundingRect().size());
01851     }
01852 
01853     updateConstraints(Plasma::SizeConstraint);
01854 
01855     d->scheduleModificationNotification();
01856     emit geometryChanged();
01857 }
01858 
01859 bool Applet::isUserConfiguring() const
01860 {
01861     return KConfigDialog::exists(d->configDialogId());
01862 }
01863 
01864 void Applet::showConfigurationInterface()
01865 {
01866     if (!hasConfigurationInterface()) {
01867         return;
01868     }
01869 
01870     if (immutability() != Mutable && !KAuthorized::authorize("plasma/allow_configure_when_locked")) {
01871         //FIXME: in 4.3 add an explanatory dialog
01872         return;
01873     }
01874 
01875     KConfigDialog *dlg = KConfigDialog::exists(d->configDialogId());
01876 
01877     if (dlg) {
01878         KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
01879         dlg->show();
01880         KWindowSystem::activateWindow(dlg->winId());
01881         return;
01882     }
01883 
01884     d->publishUI.publishCheckbox = 0;
01885     if (d->package && d->configLoader) {
01886         KConfigDialog *dialog = 0;
01887 
01888         QString uiFile = d->package->filePath("mainconfigui");
01889         if (!uiFile.isEmpty()) {
01890             QFile f(uiFile);
01891             QUiLoader loader;
01892             QWidget *w = loader.load(&f);
01893             if (w) {
01894                 dialog = new AppletConfigDialog(0, d->configDialogId(), d->configLoader);
01895                 dialog->setWindowTitle(d->configWindowTitle());
01896                 dialog->setAttribute(Qt::WA_DeleteOnClose, true);
01897                 dialog->addPage(w, i18n("Settings"), icon(), i18n("%1 Settings", name()));
01898                 d->addGlobalShortcutsPage(dialog);
01899                 d->addPublishPage(dialog);
01900                 dialog->show();
01901             }
01902         }
01903 
01904         if (!dialog && d->script) {
01905             d->script->showConfigurationInterface();
01906         }
01907     } else if (d->script) {
01908         d->script->showConfigurationInterface();
01909     } else {
01910         KConfigDialog *dialog = d->generateGenericConfigDialog();
01911         d->addStandardConfigurationPages(dialog);
01912         showConfigurationInterface(dialog);
01913     }
01914 
01915     emit releaseVisualFocus();
01916 }
01917 
01918 void Applet::showConfigurationInterface(QWidget *widget)
01919 {
01920     if (!containment() || !containment()->corona() ||
01921         !containment()->corona()->dialogManager()) {
01922         widget->show();
01923         return;
01924     }
01925 
01926     QMetaObject::invokeMethod(containment()->corona()->dialogManager(), "showDialog", Q_ARG(QWidget *, widget), Q_ARG(Plasma::Applet *, this));
01927 }
01928 
01929 QString AppletPrivate::configDialogId() const
01930 {
01931     return QString("%1settings%2").arg(appletId).arg(q->name());
01932 }
01933 
01934 QString AppletPrivate::configWindowTitle() const
01935 {
01936     return i18nc("@title:window", "%1 Settings", q->name());
01937 }
01938 
01939 QSet<QString> AppletPrivate::knownCategories()
01940 {
01941     // this is to trick the tranlsation tools into making the correct
01942     // strings for translation
01943     QSet<QString> categories = s_customCategories;
01944     categories << QString(I18N_NOOP("Accessibility")).toLower()
01945                << QString(I18N_NOOP("Application Launchers")).toLower()
01946                << QString(I18N_NOOP("Astronomy")).toLower()
01947                << QString(I18N_NOOP("Date and Time")).toLower()
01948                << QString(I18N_NOOP("Development Tools")).toLower()
01949                << QString(I18N_NOOP("Education")).toLower()
01950                << QString(I18N_NOOP("Environment and Weather")).toLower()
01951                << QString(I18N_NOOP("Examples")).toLower()
01952                << QString(I18N_NOOP("File System")).toLower()
01953                << QString(I18N_NOOP("Fun and Games")).toLower()
01954                << QString(I18N_NOOP("Graphics")).toLower()
01955                << QString(I18N_NOOP("Language")).toLower()
01956                << QString(I18N_NOOP("Mapping")).toLower()
01957                << QString(I18N_NOOP("Miscellaneous")).toLower()
01958                << QString(I18N_NOOP("Multimedia")).toLower()
01959                << QString(I18N_NOOP("Online Services")).toLower()
01960                << QString(I18N_NOOP("Productivity")).toLower()
01961                << QString(I18N_NOOP("System Information")).toLower()
01962                << QString(I18N_NOOP("Utilities")).toLower()
01963                << QString(I18N_NOOP("Windows and Tasks")).toLower();
01964     return categories;
01965 }
01966 
01967 KConfigDialog *AppletPrivate::generateGenericConfigDialog()
01968 {
01969     KConfigSkeleton *nullManager = new KConfigSkeleton(0);
01970     KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager);
01971     dialog->setFaceType(KPageDialog::Auto);
01972     dialog->setWindowTitle(configWindowTitle());
01973     dialog->setAttribute(Qt::WA_DeleteOnClose, true);
01974     q->createConfigurationInterface(dialog);
01975     dialog->showButton(KDialog::Default, false);
01976     QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()));
01977     QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()));
01978     QObject::connect(dialog, SIGNAL(finished()), nullManager, SLOT(deleteLater()));
01979     return dialog;
01980 }
01981 
01982 void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog)
01983 {
01984     addGlobalShortcutsPage(dialog);
01985     addPublishPage(dialog);
01986 }
01987 
01988 void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog)
01989 {
01990     if (isContainment) {
01991         return;
01992     }
01993 
01994     QWidget *page = new QWidget;
01995     QVBoxLayout *layout = new QVBoxLayout(page);
01996 
01997     if (!shortcutEditor) {
01998         shortcutEditor = new KKeySequenceWidget(page);
01999         QObject::connect(shortcutEditor, SIGNAL(destroyed(QObject*)), q, SLOT(clearShortcutEditorPtr()));
02000     }
02001 
02002     shortcutEditor->setKeySequence(q->globalShortcut().primary());
02003     layout->addWidget(shortcutEditor);
02004     layout->addStretch();
02005     dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard");
02006 
02007     QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
02008     QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection);
02009 }
02010 
02011 void AppletPrivate::addPublishPage(KConfigDialog *dialog)
02012 {
02013 #ifdef ENABLE_REMOTE_WIDGETS
02014     QWidget *page = new QWidget;
02015     publishUI.setupUi(page);
02016     publishUI.publishCheckbox->setChecked(q->isPublished());
02017     publishUI.allUsersCheckbox->setEnabled(q->isPublished());
02018 
02019     QString resourceName =
02020     i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
02021           "%1 on %2", q->name(), QHostInfo::localHostName());
02022     if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
02023         publishUI.allUsersCheckbox->setChecked(true);
02024     } else {
02025         publishUI.allUsersCheckbox->setChecked(false);
02026     }
02027 
02028     q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)),
02029                q, SLOT(publishCheckboxStateChanged(int)));
02030     dialog->addPage(page, i18n("Share"), "applications-internet");
02031 #endif
02032 }
02033 
02034 void AppletPrivate::publishCheckboxStateChanged(int state)
02035 {
02036     if (state == Qt::Checked) {
02037         publishUI.allUsersCheckbox->setEnabled(true);
02038     } else {
02039         publishUI.allUsersCheckbox->setEnabled(false);
02040     }
02041 }
02042 
02043 void AppletPrivate::clearShortcutEditorPtr()
02044 {
02045     shortcutEditor = 0;
02046 }
02047 
02048 void AppletPrivate::configDialogFinished()
02049 {
02050     if (shortcutEditor) {
02051         QKeySequence sequence = shortcutEditor->keySequence();
02052         if (sequence != q->globalShortcut().primary()) {
02053             q->setGlobalShortcut(KShortcut(sequence));
02054             emit q->configNeedsSaving();
02055         }
02056     }
02057 
02058 #ifdef ENABLE_REMOTE_WIDGETS
02059     if (publishUI.publishCheckbox) {
02060         q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked());
02061 
02062         if (publishUI.publishCheckbox->isChecked()) {
02063             QString resourceName =
02064                 i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on",
02065                         "%1 on %2", q->name(), QHostInfo::localHostName());
02066             q->publish(Plasma::ZeroconfAnnouncement, resourceName);
02067             if (publishUI.allUsersCheckbox->isChecked()) {
02068                 if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) {
02069                     AuthorizationRule *rule = new AuthorizationRule(resourceName, "");
02070                     rule->setPolicy(AuthorizationRule::Allow);
02071                     rule->setTargets(AuthorizationRule::AllUsers);
02072                     AuthorizationManager::self()->d->rules.append(rule);
02073                 }
02074             } else {
02075                 AuthorizationRule *matchingRule =
02076                     AuthorizationManager::self()->d->matchingRule(resourceName, Credentials());
02077                 if (matchingRule) {
02078                     AuthorizationManager::self()->d->rules.removeAll(matchingRule);
02079                 }
02080             }
02081         } else {
02082             q->unpublish();
02083         }
02084     }
02085 #endif
02086 
02087     if (!configLoader) {
02088         // the config loader will trigger this for us, so we don't need to.
02089         propagateConfigChanged();
02090         if (KConfigDialog *dialog = qobject_cast<KConfigDialog *>(q->sender())) {
02091             dialog->enableButton(KDialog::Apply, false);
02092         }
02093     }
02094 }
02095 
02096 void AppletPrivate::updateShortcuts()
02097 {
02098     if (isContainment) {
02099         //a horrible hack to avoid clobbering corona settings
02100         //we pull them out, then read, then put them back
02101         QList<QString> names;
02102         QList<QAction*> qactions;
02103         names << "add sibling containment" << "configure shortcuts" << "lock widgets";
02104         foreach (const QString &name, names) {
02105             QAction *a = actions->action(name);
02106             actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method
02107             qactions << a;
02108         }
02109 
02110         actions->readSettings();
02111 
02112         for (int i = 0; i < names.size(); ++i) {
02113             QAction *a = qactions.at(i);
02114             if (a) {
02115                 actions->addAction(names.at(i), a);
02116             }
02117         }
02118     } else {
02119         actions->readSettings();
02120     }
02121 }
02122 
02123 void AppletPrivate::propagateConfigChanged()
02124 {
02125     if (script && configLoader) {
02126         configLoader->readConfig();
02127         script->configChanged();
02128     }
02129 
02130     if (isContainment) {
02131         Containment *c = qobject_cast<Containment *>(q);
02132         if (c) {
02133             c->d->configChanged();
02134         }
02135     }
02136 
02137     q->configChanged();
02138 }
02139 
02140 void Applet::configChanged()
02141 {
02142 }
02143 
02144 void Applet::createConfigurationInterface(KConfigDialog *parent)
02145 {
02146     Q_UNUSED(parent)
02147     // virtual method reimplemented by subclasses.
02148     // do not put anything here ...
02149 }
02150 
02151 bool Applet::hasAuthorization(const QString &constraint) const
02152 {
02153     KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
02154     return constraintGroup.readEntry(constraint, true);
02155 }
02156 
02157 void Applet::setAssociatedApplication(const QString &string)
02158 {
02159     AssociatedApplicationManager::self()->setApplication(this, string);
02160 
02161     QAction *runAssociatedApplication = d->actions->action("run associated application");
02162     if (runAssociatedApplication) {
02163         bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02164         valid = valid && hasAuthorization("LaunchApp"); //obey security!
02165         runAssociatedApplication->setVisible(valid);
02166         runAssociatedApplication->setEnabled(valid);
02167     }
02168 }
02169 
02170 void Applet::setAssociatedApplicationUrls(const KUrl::List &urls)
02171 {
02172     AssociatedApplicationManager::self()->setUrls(this, urls);
02173 
02174     QAction *runAssociatedApplication = d->actions->action("run associated application");
02175     if (runAssociatedApplication) {
02176         bool valid = AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02177         valid = valid && hasAuthorization("LaunchApp"); //obey security!
02178         runAssociatedApplication->setVisible(valid);
02179         runAssociatedApplication->setEnabled(valid);
02180     }
02181 }
02182 
02183 QString Applet::associatedApplication() const
02184 {
02185     return AssociatedApplicationManager::self()->application(this);
02186 }
02187 
02188 KUrl::List Applet::associatedApplicationUrls() const
02189 {
02190     return AssociatedApplicationManager::self()->urls(this);
02191 }
02192 
02193 void Applet::runAssociatedApplication()
02194 {
02195     if (hasAuthorization("LaunchApp")) {
02196         AssociatedApplicationManager::self()->run(this);
02197     }
02198 }
02199 
02200 bool Applet::hasValidAssociatedApplication() const
02201 {
02202     return AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this);
02203 }
02204 
02205 void AppletPrivate::filterOffers(QList<KService::Ptr> &offers)
02206 {
02207     KConfigGroup constraintGroup(KGlobal::config(), "Constraints");
02208     foreach (const QString &key, constraintGroup.keyList()) {
02209         //kDebug() << "security constraint" << key;
02210         if (constraintGroup.readEntry(key, true)) {
02211             continue;
02212         }
02213 
02214         //ugh. a qlist of ksharedptr<kservice>
02215         QMutableListIterator<KService::Ptr> it(offers);
02216         while (it.hasNext()) {
02217             KService::Ptr p = it.next();
02218             QString prop = QString("X-Plasma-Requires-").append(key);
02219             QVariant req = p->property(prop, QVariant::String);
02220             //valid values: Required/Optional/Unused
02221             QString reqValue;
02222             if (req.isValid()) {
02223                 reqValue = req.toString();
02224             } else if (p->property("X-Plasma-API").toString().toLower() == "javascript") {
02225                 //TODO: be able to check whether or not a script engine provides "controled"
02226                 //bindings; for now we just give a pass to the qscript ones
02227                 reqValue = "Unused";
02228             }
02229 
02230             if (!(reqValue == "Optional" || reqValue == "Unused")) {
02231             //if (reqValue == "Required") {
02232                 it.remove();
02233             }
02234         }
02235     }
02236 }
02237 
02238 QString AppletPrivate::parentAppConstraint(const QString &parentApp)
02239 {
02240     if (parentApp.isEmpty()) {
02241         return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')")
02242                       .arg(KGlobal::mainComponent().aboutData()->appName());
02243     }
02244 
02245     return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp);
02246 }
02247 
02248 KPluginInfo::List Applet::listAppletInfo(const QString &category, const QString &parentApp)
02249 {
02250    return PluginLoader::pluginLoader()->listAppletInfo(category, parentApp);
02251 }
02252 
02253 KPluginInfo::List Applet::listAppletInfoForMimetype(const QString &mimetype)
02254 {
02255     QString constraint = AppletPrivate::parentAppConstraint();
02256     constraint.append(QString(" and '%1' in [X-Plasma-DropMimeTypes]").arg(mimetype));
02257     //kDebug() << "listAppletInfoForMimetype with" << mimetype << constraint;
02258     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02259     AppletPrivate::filterOffers(offers);
02260     return KPluginInfo::fromServices(offers);
02261 }
02262 
02263 KPluginInfo::List Applet::listAppletInfoForUrl(const QUrl &url)
02264 {
02265     QString constraint = AppletPrivate::parentAppConstraint();
02266     constraint.append(" and exist [X-Plasma-DropUrlPatterns]");
02267     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02268     AppletPrivate::filterOffers(offers);
02269 
02270     KPluginInfo::List allApplets = KPluginInfo::fromServices(offers);
02271     KPluginInfo::List filtered;
02272     foreach (const KPluginInfo &info, allApplets) {
02273         QStringList urlPatterns = info.property("X-Plasma-DropUrlPatterns").toStringList();
02274         foreach (const QString &glob, urlPatterns) {
02275             QRegExp rx(glob);
02276             rx.setPatternSyntax(QRegExp::Wildcard);
02277             if (rx.exactMatch(url.toString())) {
02278                 kDebug() << info.name() << "matches" << glob << url;
02279                 filtered << info;
02280             }
02281         }
02282     }
02283 
02284     return filtered;
02285 }
02286 
02287 QStringList Applet::listCategories(const QString &parentApp, bool visibleOnly)
02288 {
02289     QString constraint = AppletPrivate::parentAppConstraint(parentApp);
02290     constraint.append(" and exist [X-KDE-PluginInfo-Category]");
02291 
02292     KConfigGroup group(KGlobal::config(), "General");
02293     const QStringList excluded = group.readEntry("ExcludeCategories", QStringList());
02294     foreach (const QString &category, excluded) {
02295         constraint.append(" and [X-KDE-PluginInfo-Category] != '").append(category).append("'");
02296     }
02297 
02298     KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
02299     AppletPrivate::filterOffers(offers);
02300 
02301     QStringList categories;
02302     QSet<QString> known = AppletPrivate::knownCategories();
02303     foreach (const KService::Ptr &applet, offers) {
02304         QString appletCategory = applet->property("X-KDE-PluginInfo-Category").toString();
02305         if (visibleOnly && applet->noDisplay()) {
02306             // we don't want to show the hidden category
02307             continue;
02308         }
02309 
02310         //kDebug() << "   and we have " << appletCategory;
02311         if (!appletCategory.isEmpty() && !known.contains(appletCategory.toLower())) {
02312             kDebug() << "Unknown category: " << applet->name() << "says it is in the"
02313                      << appletCategory << "category which is unknown to us";
02314             appletCategory.clear();
02315         }
02316 
02317         if (appletCategory.isEmpty()) {
02318             if (!categories.contains(i18nc("misc category", "Miscellaneous"))) {
02319                 categories << i18nc("misc category", "Miscellaneous");
02320             }
02321         } else  if (!categories.contains(appletCategory)) {
02322             categories << appletCategory;
02323         }
02324     }
02325 
02326     categories.sort();
02327     return categories;
02328 }
02329 
02330 void Applet::setCustomCategories(const QStringList &categories)
02331 {
02332     AppletPrivate::s_customCategories = QSet<QString>::fromList(categories);
02333 }
02334 
02335 QStringList Applet::customCategories()
02336 {
02337     return AppletPrivate::s_customCategories.toList();
02338 }
02339 
02340 Applet *Applet::loadPlasmoid(const QString &path, uint appletId, const QVariantList &args)
02341 {
02342     if (QFile::exists(path + "/metadata.desktop")) {
02343         KService service(path + "/metadata.desktop");
02344         const QStringList& types = service.serviceTypes();
02345 
02346         if (types.contains("Plasma/Containment")) {
02347             return new Containment(path, appletId, args);
02348         } else if (types.contains("Plasma/PopupApplet")) {
02349             return new PopupApplet(path, appletId, args);
02350         } else {
02351             return new Applet(path, appletId, args);
02352         }
02353     }
02354 
02355     return 0;
02356 }
02357 
02358 Applet *Applet::load(const QString &appletName, uint appletId, const QVariantList &args)
02359 {
02360     return PluginLoader::pluginLoader()->loadApplet(appletName, appletId, args);
02361 }
02362 
02363 Applet *Applet::load(const KPluginInfo &info, uint appletId, const QVariantList &args)
02364 {
02365     if (!info.isValid()) {
02366         return 0;
02367     }
02368 
02369     return load(info.pluginName(), appletId, args);
02370 }
02371 
02372 QVariant Applet::itemChange(GraphicsItemChange change, const QVariant &value)
02373 {
02374     QVariant ret = QGraphicsWidget::itemChange(change, value);
02375 
02376     //kDebug() << change;
02377     switch (change) {
02378     case ItemSceneHasChanged: {
02379         Corona *newCorona = qobject_cast<Corona *>(qvariant_cast<QGraphicsScene*>(value));
02380         if (newCorona && newCorona->immutability() != Mutable) {
02381             updateConstraints(ImmutableConstraint);
02382         }
02383     }
02384         break;
02385     case ItemParentChange:
02386         if (!d->isContainment) {
02387             Containment *c = containment();
02388             if (d->mainConfig && !c) {
02389                 kWarning() << "Configuration object was requested prior to init(), which is too early. "
02390                     "Please fix this item:" << parentItem() << value.value<QGraphicsItem *>()
02391                     << name();
02392 
02393                 Applet *newC = dynamic_cast<Applet*>(value.value<QGraphicsItem *>());
02394                 if (newC) {
02395                     // if this is an applet, and we've just been assigned to our first containment,
02396                     // but the applet did something stupid like ask for the config() object prior to
02397                     // this happening (e.g. inits ctor) then let's repair that situation for them.
02398                     KConfigGroup *old = d->mainConfig;
02399                     KConfigGroup appletConfig = newC->config();
02400                     appletConfig = KConfigGroup(&appletConfig, "Applets");
02401                     d->mainConfig = new KConfigGroup(&appletConfig, QString::number(d->appletId));
02402                     old->copyTo(d->mainConfig);
02403                     old->deleteGroup();
02404                     delete old;
02405                 }
02406             }
02407         }
02408         break;
02409     case ItemParentHasChanged:
02410         {
02411             if (isContainment()) {
02412                 removeSceneEventFilter(this);
02413             } else {
02414                 Containment *c = containment();
02415                 if (c && c->containmentType() == Containment::DesktopContainment) {
02416                     installSceneEventFilter(this);
02417                 } else {
02418                     removeSceneEventFilter(this);
02419                 }
02420             }
02421         }
02422         break;
02423     case ItemPositionHasChanged:
02424         emit geometryChanged();
02425         // fall through!
02426     case ItemTransformHasChanged:
02427         d->scheduleModificationNotification();
02428         break;
02429     default:
02430         break;
02431     };
02432 
02433     return ret;
02434 }
02435 
02436 QPainterPath Applet::shape() const
02437 {
02438     if (d->script) {
02439         return d->script->shape();
02440     }
02441 
02442     return QGraphicsWidget::shape();
02443 }
02444 
02445 QSizeF Applet::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
02446 {
02447     QSizeF hint = QGraphicsWidget::sizeHint(which, constraint);
02448     const FormFactor ff = formFactor();
02449 
02450     // in panels make sure that the contents won't exit from the panel
02451     if (which == Qt::MinimumSize) {
02452         if (ff == Horizontal) {
02453             hint.setHeight(0);
02454         } else if (ff == Vertical) {
02455             hint.setWidth(0);
02456         }
02457     }
02458 
02459     // enforce a square size in panels
02460     if (d->aspectRatioMode == Plasma::Square) {
02461         if (ff == Horizontal) {
02462             hint.setWidth(size().height());
02463         } else if (ff == Vertical) {
02464             hint.setHeight(size().width());
02465         }
02466     } else if (d->aspectRatioMode == Plasma::ConstrainedSquare) {
02467         //enforce a size not wider than tall
02468         if (ff == Horizontal && (which == Qt::MaximumSize || size().height() <= KIconLoader::SizeLarge)) {
02469             hint.setWidth(size().height());
02470         //enforce a size not taller than wide
02471         } else if (ff == Vertical && (which == Qt::MaximumSize || size().width() <= KIconLoader::SizeLarge)) {
02472             hint.setHeight(size().width());
02473         }
02474     }
02475 
02476     return hint;
02477 }
02478 
02479 void Applet::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
02480 {
02481     Q_UNUSED(event)
02482 }
02483 
02484 void Applet::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
02485 {
02486     Q_UNUSED(event)
02487 }
02488 
02489 void Applet::timerEvent(QTimerEvent *event)
02490 {
02491     if (d->transient) {
02492         d->constraintsTimer.stop();
02493         d->busyWidgetTimer.stop();
02494         if (d->modificationsTimer) {
02495             d->modificationsTimer->stop();
02496         }
02497         return;
02498     }
02499 
02500     if (event->timerId() == d->constraintsTimer.timerId()) {
02501         d->constraintsTimer.stop();
02502 
02503         // Don't flushPendingConstraints if we're just starting up
02504         // flushPendingConstraints will be called by Corona
02505         if(!(d->pendingConstraints & Plasma::StartupCompletedConstraint)) {
02506             flushPendingConstraintsEvents();
02507         }
02508     } else if (d->modificationsTimer && event->timerId() == d->modificationsTimer->timerId()) {
02509         d->modificationsTimer->stop();
02510         // invalid group, will result in save using the default group
02511         KConfigGroup cg;
02512 
02513         save(cg);
02514         emit configNeedsSaving();
02515     } else if (event->timerId() == d->busyWidgetTimer.timerId()) {
02516         if (!d->busyWidget) {
02517             d->createMessageOverlay(false);
02518             d->messageOverlay->opacity = 0;
02519 
02520             QGraphicsLinearLayout *mainLayout = new QGraphicsLinearLayout(d->messageOverlay);
02521             d->busyWidget = new Plasma::BusyWidget(d->messageOverlay);
02522             d->busyWidget->setAcceptHoverEvents(false);
02523             d->busyWidget->setAcceptedMouseButtons(Qt::NoButton);
02524             d->messageOverlay->setAcceptHoverEvents(false);
02525             d->messageOverlay->setAcceptedMouseButtons(Qt::NoButton);
02526 
02527             mainLayout->addStretch();
02528             mainLayout->addItem(d->busyWidget);
02529             mainLayout->addStretch();
02530         }
02531     }
02532 }
02533 
02534 QRect Applet::screenRect() const
02535 {
02536     QGraphicsView *v = view();
02537 
02538     if (v) {
02539         QPointF bottomRight = pos();
02540         bottomRight.rx() += size().width();
02541         bottomRight.ry() += size().height();
02542 
02543         QPoint tL = v->mapToGlobal(v->mapFromScene(pos()));
02544         QPoint bR = v->mapToGlobal(v->mapFromScene(bottomRight));
02545         return QRect(QPoint(tL.x(), tL.y()), QSize(bR.x() - tL.x(), bR.y() - tL.y()));
02546     }
02547 
02548     //The applet doesn't have a view on it.
02549     //So a screenRect isn't relevant.
02550     return QRect(QPoint(0, 0), QSize(0, 0));
02551 }
02552 
02553 void Applet::raise()
02554 {
02555     setZValue(++AppletPrivate::s_maxZValue);
02556 }
02557 
02558 void Applet::lower()
02559 {
02560     setZValue(--AppletPrivate::s_minZValue);
02561 }
02562 
02563 void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate)
02564 {
02565     if (isContainment == nowIsContainment && !forceUpdate) {
02566         return;
02567     }
02568 
02569     isContainment = nowIsContainment;
02570     //FIXME I do not like this function.
02571     //currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way.
02572     //if someone calls it at some other time it'll cause headaches. :P
02573 
02574     delete mainConfig;
02575     mainConfig = 0;
02576 
02577     Containment *c = q->containment();
02578     if (c) {
02579         c->d->checkContainmentFurniture();
02580     }
02581 }
02582 
02583 bool Applet::isContainment() const
02584 {
02585     return d->isContainment;
02586 }
02587 
02588 // PRIVATE CLASS IMPLEMENTATION
02589 
02590 AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet)
02591         : appletId(uniqueID),
02592           q(applet),
02593           service(0),
02594           preferredBackgroundHints(Applet::StandardBackground),
02595           backgroundHints(Applet::NoBackground),
02596           aspectRatioMode(Plasma::KeepAspectRatio),
02597           immutability(Mutable),
02598           appletDescription(info ? *info : KPluginInfo(service)),
02599           background(0),
02600           mainConfig(0),
02601           pendingConstraints(NoConstraint),
02602           messageOverlay(0),
02603           messageOverlayProxy(0),
02604           busyWidget(0),
02605           script(0),
02606           package(0),
02607           configLoader(0),
02608           actions(AppletPrivate::defaultActions(applet)),
02609           activationAction(0),
02610           shortcutEditor(0),
02611           itemStatus(UnknownStatus),
02612           preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored),
02613           modificationsTimer(0),
02614           hasConfigurationInterface(false),
02615           failed(false),
02616           isContainment(false),
02617           transient(false),
02618           needsConfig(false),
02619           started(false)
02620 {
02621     if (appletId == 0) {
02622         appletId = ++s_maxAppletId;
02623     } else if (appletId > s_maxAppletId) {
02624         s_maxAppletId = appletId;
02625     }
02626 }
02627 
02628 AppletPrivate::~AppletPrivate()
02629 {
02630     if (activationAction && activationAction->isGlobalShortcutEnabled()) {
02631         //kDebug() << "reseting global action for" << q->name() << activationAction->objectName();
02632         activationAction->forgetGlobalShortcut();
02633     }
02634 
02635     delete extender.data();
02636 
02637     delete script;
02638     script = 0;
02639     delete package;
02640     package = 0;
02641     delete configLoader;
02642     configLoader = 0;
02643     delete mainConfig;
02644     mainConfig = 0;
02645     delete modificationsTimer;
02646 }
02647 
02648 void AppletPrivate::init(const QString &packagePath)
02649 {
02650     // WARNING: do not access config() OR globalConfig() in this method!
02651     //          that requires a scene, which is not available at this point
02652     q->setCacheMode(Applet::DeviceCoordinateCache);
02653     q->setAcceptsHoverEvents(true);
02654     q->setFlag(QGraphicsItem::ItemIsFocusable, true);
02655     q->setFocusPolicy(Qt::ClickFocus);
02656     // FIXME: adding here because nothing seems to be doing it in QGraphicsView,
02657     // but it doesn't actually work anyways =/
02658     q->setLayoutDirection(qApp->layoutDirection());
02659 
02660     //set a default size before any saved settings are read
02661     QSize size(200, 200);
02662     q->setBackgroundHints(Applet::DefaultBackground);
02663     q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor?
02664 
02665     QAction *closeApplet = actions->action("remove");
02666     if (closeApplet) {
02667         closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name()));
02668     }
02669 
02670     QAction *configAction = actions->action("configure");
02671     if (configAction) {
02672         configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name()));
02673     }
02674 
02675     QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus()));
02676     if (!appletDescription.isValid()) {
02677         kDebug() << "Check your constructor! "
02678                  << "You probably want to be passing in a Service::Ptr "
02679                  << "or a QVariantList with a valid storageid as arg[0].";
02680         q->resize(size);
02681         return;
02682     }
02683 
02684     QVariant s = appletDescription.property("X-Plasma-DefaultSize");
02685     if (s.isValid()) {
02686         size = s.toSize();
02687     }
02688     //kDebug() << "size" << size;
02689     q->resize(size);
02690 
02691     QString api = appletDescription.property("X-Plasma-API").toString();
02692 
02693     // we have a scripted plasmoid
02694     if (!api.isEmpty()) {
02695         // find where the Package is
02696         QString path = packagePath;
02697         if (path.isEmpty()) {
02698             QString subPath = q->packageStructure()->defaultPackageRoot() + '/' + appletDescription.pluginName() + '/';
02699             path = KStandardDirs::locate("data", subPath + "metadata.desktop");
02700             if (path.isEmpty()) {
02701                 path = KStandardDirs::locate("data", subPath);
02702             } else {
02703                 path.remove(QString("metadata.desktop"));
02704             }
02705         } else if (!path.endsWith('/')) {
02706             path.append('/');
02707         }
02708 
02709         if (path.isEmpty()) {
02710             q->setFailedToLaunch(
02711                 true,
02712                 i18nc("Package file, name of the widget",
02713                       "Could not locate the %1 package required for the %2 widget.",
02714                       appletDescription.pluginName(), appletDescription.name()));
02715         } else {
02716             // create the package and see if we have something real
02717             //kDebug() << "trying for" << path;
02718             PackageStructure::Ptr structure = Plasma::packageStructure(api, Plasma::AppletComponent);
02719             structure->setPath(path);
02720             package = new Package(path, structure);
02721 
02722             if (package->isValid()) {
02723                 // now we try and set up the script engine.
02724                 // it will be parented to this applet and so will get
02725                 // deleted when the applet does
02726 
02727                 script = Plasma::loadScriptEngine(api, q);
02728                 if (!script) {
02729                     delete package;
02730                     package = 0;
02731                     q->setFailedToLaunch(true,
02732                                          i18nc("API or programming language the widget was written in, name of the widget",
02733                                                "Could not create a %1 ScriptEngine for the %2 widget.",
02734                                                api, appletDescription.name()));
02735                 }
02736             } else {
02737                 q->setFailedToLaunch(true, i18nc("Package file, name of the widget",
02738                                                  "Could not open the %1 package required for the %2 widget.",
02739                                                  appletDescription.pluginName(), appletDescription.name()));
02740                 delete package;
02741                 package = 0;
02742             }
02743         }
02744     }
02745 }
02746 
02747 // put all setup routines for script here. at this point we can assume that
02748 // package exists and that we have a script engine
02749 void AppletPrivate::setupScriptSupport()
02750 {
02751     if (!package) {
02752         return;
02753     }
02754 
02755     kDebug() << "setting up script support, package is in" << package->path()
02756              << "which is a" << package->structure()->type() << "package"
02757              << ", main script is" << package->filePath("mainscript");
02758 
02759     QString translationsPath = package->filePath("translations");
02760     if (!translationsPath.isEmpty()) {
02761         //FIXME: we should _probably_ use a KComponentData to segregate the applets
02762         //       from each other; but I want to get the basics working first :)
02763         KGlobal::dirs()->addResourceDir("locale", translationsPath);
02764         KGlobal::locale()->insertCatalog(package->metadata().pluginName());
02765     }
02766 
02767     QString xmlPath = package->filePath("mainconfigxml");
02768     if (!xmlPath.isEmpty()) {
02769         QFile file(xmlPath);
02770         KConfigGroup config = q->config();
02771         configLoader = new ConfigLoader(&config, &file);
02772         QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged()));
02773     }
02774 
02775     if (!package->filePath("mainconfigui").isEmpty()) {
02776         q->setHasConfigurationInterface(true);
02777     }
02778 }
02779 
02780 QString AppletPrivate::globalName() const
02781 {
02782     if (!appletDescription.isValid()) {
02783         return QString();
02784     }
02785 
02786     return appletDescription.service()->library();
02787 }
02788 
02789 QString AppletPrivate::instanceName()
02790 {
02791     if (!appletDescription.isValid()) {
02792         return QString();
02793     }
02794 
02795     return appletDescription.service()->library() + QString::number(appletId);
02796 }
02797 
02798 void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c)
02799 {
02800     // Don't start up a timer if we're just starting up
02801     // flushPendingConstraints will be called by Corona
02802     if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) {
02803         constraintsTimer.start(0, q);
02804     }
02805 
02806     if (c & Plasma::StartupCompletedConstraint) {
02807         started = true;
02808     }
02809 
02810     pendingConstraints |= c;
02811 }
02812 
02813 void AppletPrivate::scheduleModificationNotification()
02814 {
02815     // modificationsTimer is not allocated until we get our notice of being started
02816     if (modificationsTimer) {
02817         // schedule a save
02818         if (modificationsTimer->isActive()) {
02819             modificationsTimer->stop();
02820         }
02821 
02822         modificationsTimer->start(1000, q);
02823     }
02824 }
02825 
02826 KConfigGroup *AppletPrivate::mainConfigGroup()
02827 {
02828     if (mainConfig) {
02829         return mainConfig;
02830     }
02831 
02832     bool newGroup = false;
02833     if (isContainment) {
02834         Corona *corona = qobject_cast<Corona*>(q->scene());
02835         KConfigGroup containmentConfig;
02836         //kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q;
02837 
02838         if (corona) {
02839             containmentConfig = KConfigGroup(corona->config(), "Containments");
02840         } else {
02841             containmentConfig =  KConfigGroup(KGlobal::config(), "Containments");
02842         }
02843 
02844         if (package && !containmentConfig.hasGroup(QString::number(appletId))) {
02845             newGroup = true;
02846         }
02847 
02848         mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId));
02849     } else {
02850         KConfigGroup appletConfig;
02851 
02852         Containment *c = q->containment();
02853         Applet *parentApplet = qobject_cast<Applet *>(q->parent());
02854         if (parentApplet && parentApplet != static_cast<Applet *>(c)) {
02855             // this applet is nested inside another applet! use it's config
02856             // as the parent group in the config
02857             appletConfig = parentApplet->config();
02858             appletConfig = KConfigGroup(&appletConfig, "Applets");
02859         } else if (c) {
02860             // applet directly in a Containment, as usual
02861             appletConfig = c->config();
02862             appletConfig = KConfigGroup(&appletConfig, "Applets");
02863         } else {
02864             kWarning() << "requesting config for" << q->name() << "without a containment!";
02865             appletConfig = KConfigGroup(KGlobal::config(), "Applets");
02866         }
02867 
02868         if (package && !appletConfig.hasGroup(QString::number(appletId))) {
02869             newGroup = true;
02870         }
02871 
02872         mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId));
02873     }
02874 
02875     if (newGroup) {
02876         //see if we have a default configuration in our package
02877         const QString defaultConfigFile = q->package()->filePath("defaultconfig");
02878         if (!defaultConfigFile.isEmpty()) {
02879             kDebug() << "copying default config: " << q->package()->filePath("defaultconfig");
02880             KConfigGroup defaultConfig(KSharedConfig::openConfig(defaultConfigFile)->group("Configuration"));
02881             defaultConfig.copyTo(mainConfig);
02882         }
02883     }
02884 
02885     return mainConfig;
02886 }
02887 
02888 QString AppletPrivate::visibleFailureText(const QString &reason)
02889 {
02890     QString text;
02891 
02892     if (reason.isEmpty()) {
02893         text = i18n("This object could not be created.");
02894     } else {
02895         text = i18n("This object could not be created for the following reason:<p><b>%1</b></p>", reason);
02896     }
02897 
02898     return text;
02899 }
02900 
02901 void AppletPrivate::themeChanged()
02902 {
02903     if (background) {
02904         //do again the translucent background fallback
02905         q->setBackgroundHints(backgroundHints);
02906 
02907         qreal left;
02908         qreal right;
02909         qreal top;
02910         qreal bottom;
02911         background->getMargins(left, top, right, bottom);
02912         q->setContentsMargins(left, right, top, bottom);
02913     }
02914     q->update();
02915 }
02916 
02917 void AppletPrivate::resetConfigurationObject()
02918 {
02919     // make sure mainConfigGroup exists in all cases
02920     mainConfigGroup();
02921 
02922     mainConfig->deleteGroup();
02923     delete mainConfig;
02924     mainConfig = 0;
02925 
02926     Corona * corona = qobject_cast<Corona*>(q->scene());
02927     if (corona) {
02928         corona->requireConfigSync();
02929     }
02930 }
02931 
02932 void AppletPrivate::handleDisappeared(AppletHandle *h)
02933 {
02934     if (h == handle.data()) {
02935         h->detachApplet();
02936         QGraphicsScene *scene = q->scene();
02937         if (scene && h->scene() == scene) {
02938             scene->removeItem(h);
02939         }
02940         h->deleteLater();
02941     }
02942 }
02943 
02944 void ContainmentPrivate::checkRemoveAction()
02945 {
02946     q->enableAction("remove", q->immutability() == Mutable);
02947 }
02948 
02949 
02950 uint AppletPrivate::s_maxAppletId = 0;
02951 int AppletPrivate::s_maxZValue = 0;
02952 int AppletPrivate::s_minZValue = 0;
02953 PackageStructure::Ptr AppletPrivate::packageStructure(0);
02954 QSet<QString> AppletPrivate::s_customCategories;
02955 
02956 AppletOverlayWidget::AppletOverlayWidget(QGraphicsWidget *parent)
02957     : QGraphicsWidget(parent),
02958       opacity(0.4)
02959 {
02960     resize(parent->size());
02961 }
02962 
02963 void AppletOverlayWidget::destroy()
02964 {
02965     Animation *anim = Plasma::Animator::create(Plasma::Animator::DisappearAnimation);
02966     if (anim) {
02967         connect(anim, SIGNAL(finished()), this, SLOT(overlayAnimationComplete()));
02968         anim->setTargetWidget(this);
02969         anim->start();
02970     } else {
02971         overlayAnimationComplete();
02972     }
02973 }
02974 
02975 void AppletOverlayWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
02976 {
02977     event->accept();
02978 }
02979 
02980 void AppletOverlayWidget::overlayAnimationComplete()
02981 {
02982     if (scene()) {
02983         scene()->removeItem(this);
02984     }
02985     deleteLater();
02986 }
02987 
02988 void AppletOverlayWidget::paint(QPainter *painter,
02989                                 const QStyleOptionGraphicsItem *option,
02990                                 QWidget *widget)
02991 {
02992     Q_UNUSED(option)
02993     Q_UNUSED(widget)
02994 
02995     if (qFuzzyCompare(1, 1+opacity)) {
02996         return;
02997     }
02998 
02999     QColor wash = Plasma::Theme::defaultTheme()->color(Theme::BackgroundColor);
03000     wash.setAlphaF(opacity);
03001 
03002     Applet *applet = qobject_cast<Applet *>(parentWidget());
03003 
03004 
03005     QPainterPath backgroundShape;
03006     if (!applet || applet->backgroundHints() & Applet::StandardBackground) {
03007         //FIXME: a resize here is nasty, but perhaps still better than an eventfilter just for that..
03008         if (parentWidget()->contentsRect().size() != size()) {
03009             resize(parentWidget()->contentsRect().size());
03010         }
03011         backgroundShape = PaintUtils::roundedRectangle(contentsRect(), 5);
03012     } else {
03013         backgroundShape = shape();
03014     }
03015 
03016     painter->setRenderHints(QPainter::Antialiasing);
03017     painter->fillPath(backgroundShape, wash);
03018 }
03019 
03020 #if QT_VERSION >= 0x040700
03021 // in QGraphicsWidget now; preserve BC by implementing it as a protected method
03022 void Applet::geometryChanged()
03023 {
03024     emit QGraphicsWidget::geometryChanged();
03025 }
03026 #endif
03027 
03028 } // Plasma namespace
03029 
03030 #include "applet.moc"
03031 #include "private/applet_p.moc"

Plasma

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

kdelibs

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