/* * Copyright 2005 by Aaron Seigo * Copyright 2007 by Riccardo Iaconelli * Copyright 2008 by Ménard Alexis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "applet.h" #include "private/applet_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "configloader.h" #include "containment.h" #include "corona.h" #include "dataenginemanager.h" #include "extender.h" #include "extenderitem.h" #include "package.h" #include "plasma.h" #include "scripting/appletscript.h" #include "svg.h" #include "framesvg.h" #include "private/framesvg_p.h" #include "popupapplet.h" #include "theme.h" #include "view.h" #include "widgets/iconwidget.h" #include "widgets/label.h" #include "widgets/pushbutton.h" #include "widgets/busywidget.h" #include "tooltipmanager.h" #include "wallpaper.h" #include "paintutils.h" #include "private/containment_p.h" #include "private/extenderapplet_p.h" #include "private/packages_p.h" #include "private/popupapplet_p.h" #include "private/toolbox_p.h" //#define DYNAMIC_SHADOWS namespace Plasma { Applet::Applet(QGraphicsItem *parent, const QString &serviceID, uint appletId) : QGraphicsWidget(parent), d(new AppletPrivate(KService::serviceByStorageId(serviceID), appletId, this)) { // WARNING: do not access config() OR globalConfig() in this method! // that requires a scene, which is not available at this point d->init(); } Applet::Applet(QGraphicsItem *parent, const QString &serviceID, uint appletId, const QVariantList &args) : QGraphicsWidget(parent), d(new AppletPrivate(KService::serviceByStorageId(serviceID), appletId, this)) { // WARNING: do not access config() OR globalConfig() in this method! // that requires a scene, which is not available at this point QVariantList &mutableArgs = const_cast(args); if (!mutableArgs.isEmpty()) { mutableArgs.removeFirst(); if (!mutableArgs.isEmpty()) { mutableArgs.removeFirst(); } } d->args = mutableArgs; d->init(); } Applet::Applet(QObject *parentObject, const QVariantList &args) : QGraphicsWidget(0), d(new AppletPrivate( KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()), args.count() > 1 ? args[1].toInt() : 0, this)) { // now remove those first two items since those are managed by Applet and subclasses shouldn't // need to worry about them. yes, it violates the constness of this var, but it lets us add // or remove items later while applets can just pretend that their args always start at 0 QVariantList &mutableArgs = const_cast(args); if (!mutableArgs.isEmpty()) { mutableArgs.removeFirst(); if (!mutableArgs.isEmpty()) { mutableArgs.removeFirst(); } } d->args = mutableArgs; setParent(parentObject); // WARNING: do not access config() OR globalConfig() in this method! // that requires a scene, which is not available at this point d->init(); // the brain damage seen in the initialization list is due to the // inflexibility of KService::createInstance } Applet::~Applet() { //let people know that i will die emit appletDestroyed(this); if (!d->transient && d->extender) { //This would probably be nicer if it was located in extender. But in it's dtor, this won't //work since when that get's called, the applet's config() isn't accessible anymore. (same //problem with calling saveState(). Doing this in saveState() might be a possibility, but //that would require every extender savestate implementation to call it's parent function, //which isn't very nice. d->extender->saveState(); foreach (ExtenderItem *item, d->extender->attachedItems()) { if (item->autoExpireDelay()) { //destroy temporary extender items, or items that aren't detached, so their //configuration won't linger after a plasma restart. item->destroy(); } } } // clean up our config dialog, if any delete KConfigDialog::exists(d->configDialogId()); delete d; } PackageStructure::Ptr Applet::packageStructure() { if (!AppletPrivate::packageStructure) { AppletPrivate::packageStructure = new PlasmoidPackage(); } return AppletPrivate::packageStructure; } void Applet::init() { if (d->script && !d->script->init()) { setFailedToLaunch(true, i18n("Script initialization failed")); } } uint Applet::id() const { return d->appletId; } void Applet::save(KConfigGroup &g) const { if (d->transient) { return; } KConfigGroup group = g; if (!group.isValid()) { group = *d->mainConfigGroup(); } //kDebug() << "saving to" << group.name(); // we call the dptr member directly for locked since isImmutable() // also checks kiosk and parent containers group.writeEntry("immutability", (int)d->immutability); group.writeEntry("plugin", pluginName()); group.writeEntry("geometry", geometry()); group.writeEntry("zvalue", zValue()); if (!d->started) { return; } //FIXME: for containments, we need to have some special values here w/regards to // screen affinity (e.g. "bottom of screen 0") //kDebug() << pluginName() << "geometry is" << geometry() // << "pos is" << pos() << "bounding rect is" << boundingRect(); if (transform() == QTransform()) { group.deleteEntry("transform"); } else { QList m; QTransform t = transform(); m << t.m11() << t.m12() << t.m13() << t.m21() << t.m22() << t.m23() << t.m31() << t.m32() << t.m33(); group.writeEntry("transform", m); //group.writeEntry("transform", transformToString(transform())); } KConfigGroup appletConfigGroup(&group, "Configuration"); //FIXME: we need a global save state too saveState(appletConfigGroup); if (d->activationAction) { KConfigGroup shortcutConfig(&group, "Shortcuts"); shortcutConfig.writeEntry("global", d->activationAction->globalShortcut().toString()); } if (d->configLoader) { d->configLoader->writeConfig(); } } void Applet::restore(KConfigGroup &group) { QList m = group.readEntry("transform", QList()); if (m.count() == 9) { QTransform t(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); setTransform(t); } qreal z = group.readEntry("zvalue", 0); if (z >= AppletPrivate::s_maxZValue) { AppletPrivate::s_maxZValue = z; } if (z > 0) { setZValue(z); } setImmutability((ImmutabilityType)group.readEntry("immutability", (int)Mutable)); QRectF geom = group.readEntry("geometry", QRectF()); if (geom.isValid()) { setGeometry(geom); } KConfigGroup shortcutConfig(&group, "Shortcuts"); QString shortcutText = shortcutConfig.readEntryUntranslated("global", QString()); if (!shortcutText.isEmpty()) { setGlobalShortcut(KShortcut(shortcutText)); kDebug() << "got global shortcut for" << name() << "of" << QKeySequence(shortcutText); kDebug() << "set to" << d->activationAction->objectName() << d->activationAction->globalShortcut().primary(); } // local shortcut, if any //TODO: implement; the shortcut will need to be registered with the containment /* shortcutText = shortcutConfig.readEntryUntranslated("local", QString()); if (!shortcutText.isEmpty()) { //TODO: implement; the shortcut } */ } void AppletPrivate::setFocus() { //kDebug() << "setting focus"; q->setFocus(Qt::ShortcutFocusReason); } void Applet::setFailedToLaunch(bool failed, const QString &reason) { if (d->failed == failed) { if (failed && !reason.isEmpty()) { foreach (QGraphicsItem *item, QGraphicsItem::children()) { Label *l = dynamic_cast