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

Plasma

applet.cpp

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

Plasma

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

kdelibs

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