00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "applet.h"
00023 #include "private/applet_p.h"
00024
00025 #include <cmath>
00026 #include <limits>
00027
00028 #include <QAction>
00029 #include <QApplication>
00030 #include <QEvent>
00031 #include <QFile>
00032 #include <QGraphicsGridLayout>
00033 #include <QGraphicsSceneMouseEvent>
00034 #include <QGraphicsView>
00035 #include <QLabel>
00036 #include <QList>
00037 #include <QGraphicsLinearLayout>
00038 #include <QPainter>
00039 #include <QSize>
00040 #include <QStyleOptionGraphicsItem>
00041 #include <QTextDocument>
00042 #include <QUiLoader>
00043 #include <QVBoxLayout>
00044 #include <QWidget>
00045
00046 #include <kaction.h>
00047 #include <kactioncollection.h>
00048 #include <kauthorized.h>
00049 #include <kcolorscheme.h>
00050 #include <kconfigdialog.h>
00051 #include <kdialog.h>
00052 #include <kicon.h>
00053 #include <kiconloader.h>
00054 #include <kkeysequencewidget.h>
00055 #include <kplugininfo.h>
00056 #include <kstandarddirs.h>
00057 #include <kservice.h>
00058 #include <kservicetypetrader.h>
00059 #include <kshortcut.h>
00060 #include <kwindowsystem.h>
00061 #include <kpushbutton.h>
00062
00063 #include <solid/powermanagement.h>
00064
00065 #include "configloader.h"
00066 #include "containment.h"
00067 #include "corona.h"
00068 #include "dataenginemanager.h"
00069 #include "extender.h"
00070 #include "extenderitem.h"
00071 #include "package.h"
00072 #include "plasma.h"
00073 #include "scripting/appletscript.h"
00074 #include "svg.h"
00075 #include "framesvg.h"
00076 #include "private/framesvg_p.h"
00077 #include "popupapplet.h"
00078 #include "theme.h"
00079 #include "view.h"
00080 #include "widgets/iconwidget.h"
00081 #include "widgets/label.h"
00082 #include "widgets/pushbutton.h"
00083 #include "widgets/busywidget.h"
00084 #include "tooltipmanager.h"
00085 #include "wallpaper.h"
00086
00087 #include "private/containment_p.h"
00088 #include "private/extenderapplet_p.h"
00089 #include "private/packages_p.h"
00090 #include "private/popupapplet_p.h"
00091 #include "private/toolbox_p.h"
00092
00093
00094 namespace Plasma
00095 {
00096
00097 Applet::Applet(QGraphicsItem *parent,
00098 const QString &serviceID,
00099 uint appletId)
00100 : QGraphicsWidget(parent),
00101 d(new AppletPrivate(KService::serviceByStorageId(serviceID), appletId, this))
00102 {
00103
00104
00105 d->init();
00106 }
00107
00108 Applet::Applet(QObject *parentObject, const QVariantList &args)
00109 : QGraphicsWidget(0),
00110 d(new AppletPrivate(
00111 KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()),
00112 args.count() > 1 ? args[1].toInt() : 0, this))
00113 {
00114
00115
00116
00117 QVariantList &mutableArgs = const_cast<QVariantList &>(args);
00118 if (!mutableArgs.isEmpty()) {
00119 mutableArgs.removeFirst();
00120
00121 if (!mutableArgs.isEmpty()) {
00122 mutableArgs.removeFirst();
00123 }
00124 }
00125
00126 setParent(parentObject);
00127
00128
00129
00130 d->init();
00131
00132
00133
00134 }
00135
00136 Applet::~Applet()
00137 {
00138 if (d->transient) {
00139 d->resetConfigurationObject();
00140 } else if (d->extender) {
00141
00142
00143
00144
00145
00146 d->extender->saveState();
00147
00148 foreach (ExtenderItem *item, d->extender->attachedItems()) {
00149 if (item->autoExpireDelay()) {
00150
00151
00152 item->destroy();
00153 }
00154 }
00155 }
00156
00157 delete d;
00158 }
00159
00160 PackageStructure::Ptr Applet::packageStructure()
00161 {
00162 if (!AppletPrivate::packageStructure) {
00163 AppletPrivate::packageStructure = new PlasmoidPackage();
00164 }
00165
00166 return AppletPrivate::packageStructure;
00167 }
00168
00169 void Applet::init()
00170 {
00171 if (d->script && !d->script->init()) {
00172 setFailedToLaunch(true, i18n("Script initialization failed"));
00173 }
00174 }
00175
00176 uint Applet::id() const
00177 {
00178 return d->appletId;
00179 }
00180
00181 void Applet::save(KConfigGroup &g) const
00182 {
00183 if (d->transient) {
00184 return;
00185 }
00186
00187 KConfigGroup group = g;
00188 if (!group.isValid()) {
00189 group = *d->mainConfigGroup();
00190 }
00191
00192
00193
00194
00195 group.writeEntry("immutability", (int)d->immutability);
00196 group.writeEntry("plugin", pluginName());
00197
00198 group.writeEntry("geometry", geometry());
00199 group.writeEntry("zvalue", zValue());
00200
00201 if (!d->started) {
00202 return;
00203 }
00204
00205
00206
00207
00208
00209 if (transform() == QTransform()) {
00210 group.deleteEntry("transform");
00211 } else {
00212 QList<qreal> m;
00213 QTransform t = transform();
00214 m << t.m11() << t.m12() << t.m13() << t.m21() << t.m22() << t.m23() << t.m31() << t.m32() << t.m33();
00215 group.writeEntry("transform", m);
00216
00217 }
00218
00219 KConfigGroup appletConfigGroup(&group, "Configuration");
00220
00221
00222 saveState(appletConfigGroup);
00223
00224 if (d->activationAction) {
00225 KConfigGroup shortcutConfig(&group, "Shortcuts");
00226 shortcutConfig.writeEntry("global", d->activationAction->globalShortcut().toString());
00227 }
00228
00229 if (d->configLoader) {
00230 d->configLoader->writeConfig();
00231 }
00232 }
00233
00234 void Applet::restore(KConfigGroup &group)
00235 {
00236 QList<qreal> m = group.readEntry("transform", QList<qreal>());
00237 if (m.count() == 9) {
00238 QTransform t(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
00239 setTransform(t);
00240 }
00241
00242 qreal z = group.readEntry("zvalue", 0);
00243
00244 if (z >= AppletPrivate::s_maxZValue) {
00245 AppletPrivate::s_maxZValue = z;
00246 }
00247
00248 if (z > 0) {
00249 setZValue(z);
00250 }
00251
00252 setImmutability((ImmutabilityType)group.readEntry("immutability", (int)Mutable));
00253
00254 QRectF geom = group.readEntry("geometry", QRectF());
00255 if (geom.isValid()) {
00256 setGeometry(geom);
00257 }
00258
00259 KConfigGroup shortcutConfig(&group, "Shortcuts");
00260 QString shortcutText = shortcutConfig.readEntryUntranslated("global", QString());
00261 if (!shortcutText.isEmpty()) {
00262 setGlobalShortcut(KShortcut(shortcutText));
00263 kDebug() << "got global shortcut for" << name() << "of" << QKeySequence(shortcutText);
00264 kDebug() << "set to" << d->activationAction->objectName()
00265 << d->activationAction->globalShortcut().primary();
00266 }
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 }
00277
00278 void AppletPrivate::setFocus()
00279 {
00280
00281 q->setFocus(Qt::ShortcutFocusReason);
00282 }
00283
00284 void Applet::setFailedToLaunch(bool failed, const QString &reason)
00285 {
00286 if (d->failed == failed) {
00287 if (failed && !reason.isEmpty()) {
00288 foreach (QGraphicsItem *item, QGraphicsItem::children()) {
00289 Label *l = dynamic_cast<Label *>(item);
00290 if (l) {
00291 l->setText(d->visibleFailureText(reason));
00292 }
00293 }
00294 }
00295 return;
00296 }
00297
00298 d->failed = failed;
00299 prepareGeometryChange();
00300
00301 qDeleteAll(QGraphicsItem::children());
00302 setLayout(0);
00303
00304 if (failed) {
00305 setBackgroundHints(d->backgroundHints|StandardBackground);
00306
00307 QGraphicsLinearLayout *failureLayout = new QGraphicsLinearLayout(this);
00308 failureLayout->setContentsMargins(0, 0, 0, 0);
00309
00310 IconWidget *failureIcon = new IconWidget(this);
00311 failureIcon->setIcon(KIcon("dialog-error"));
00312 failureLayout->addItem(failureIcon);
00313
00314 Label *failureWidget = new Plasma::Label(this);
00315 failureWidget->setText(d->visibleFailureText(reason));
00316 QLabel *label = failureWidget->nativeWidget();
00317 label->setWordWrap(true);
00318 failureLayout->addItem(failureWidget);
00319
00320 Plasma::ToolTipManager::self()->registerWidget(failureIcon);
00321 Plasma::ToolTipContent data(i18n("Unable to load the widget"), reason,
00322 KIcon("dialog-error"));
00323 Plasma::ToolTipManager::self()->setContent(failureIcon, data);
00324
00325 setLayout(failureLayout);
00326 resize(300, 250);
00327 setMinimumSize(failureLayout->minimumSize());
00328 d->background->resizeFrame(geometry().size());
00329 }
00330
00331 update();
00332 }
00333
00334 void Applet::saveState(KConfigGroup &group) const
00335 {
00336 if (group.config()->name() != config().config()->name()) {
00337
00338
00339 KConfigGroup c = config();
00340 c.copyTo(&group);
00341 }
00342 }
00343
00344 KConfigGroup Applet::config(const QString &group) const
00345 {
00346 KConfigGroup cg = config();
00347 return KConfigGroup(&cg, group);
00348 }
00349
00350 KConfigGroup Applet::config() const
00351 {
00352 if (d->isContainment) {
00353 return *(d->mainConfigGroup());
00354 }
00355
00356 return KConfigGroup(d->mainConfigGroup(), "Configuration");
00357 }
00358
00359 KConfigGroup Applet::globalConfig() const
00360 {
00361 KConfigGroup globalAppletConfig;
00362 QString group = isContainment() ? "ContainmentGlobals" : "AppletGlobals";
00363
00364 Corona *corona = qobject_cast<Corona*>(scene());
00365 if (corona) {
00366 KSharedConfig::Ptr coronaConfig = corona->config();
00367 globalAppletConfig = KConfigGroup(coronaConfig, group);
00368 } else {
00369 globalAppletConfig = KConfigGroup(KGlobal::config(), group);
00370 }
00371
00372 return KConfigGroup(&globalAppletConfig, d->globalName());
00373 }
00374
00375 void Applet::destroy()
00376 {
00377 if (immutability() != Mutable || d->transient) {
00378 return;
00379 }
00380
00381 d->transient = true;
00382
00383 if (isContainment()) {
00384 d->cleanUpAndDelete();
00385 } else {
00386 d->resetConfigurationObject();
00387 connect(Animator::self(), SIGNAL(animationFinished(QGraphicsItem*,Plasma::Animator::Animation)),
00388 this, SLOT(appletAnimationComplete(QGraphicsItem*,Plasma::Animator::Animation)));
00389 Animator::self()->animateItem(this, Animator::DisappearAnimation);
00390 }
00391
00392 Corona * corona = qobject_cast<Corona*>(scene());
00393 if (corona) {
00394 corona->requireConfigSync();
00395 }
00396 }
00397
00398 bool Applet::destroyed() const
00399 {
00400 return d->transient;
00401 }
00402
00403 void AppletPrivate::appletAnimationComplete(QGraphicsItem *item, Plasma::Animator::Animation anim)
00404 {
00405 if (anim != Animator::DisappearAnimation || item != q) {
00406 return;
00407 }
00408
00409 cleanUpAndDelete();
00410 }
00411
00412 void AppletPrivate::selectItemToDestroy()
00413 {
00414
00415 if (q->isContainment()) {
00416 QGraphicsView *view = q->view();
00417 if (view && view->transform().isScaling() &&
00418 q->scene()->focusItem() != q) {
00419 QGraphicsItem *focus = q->scene()->focusItem();
00420
00421 if (focus) {
00422 Containment *toDestroy = dynamic_cast<Containment*>(focus->topLevelItem());
00423
00424 if (toDestroy) {
00425 toDestroy->destroy();
00426 return;
00427 }
00428 }
00429 }
00430 }
00431
00432 q->destroy();
00433 }
00434
00435 void AppletPrivate::updateRect(const QRectF &rect)
00436 {
00437 q->update(rect);
00438 }
00439
00440 void AppletPrivate::cleanUpAndDelete()
00441 {
00442
00443 QGraphicsWidget *parent = dynamic_cast<QGraphicsWidget *>(q->parentItem());
00444
00445
00446
00447
00448
00449 if (parent && parent->layout()) {
00450 QGraphicsLayout *l = parent->layout();
00451 for (int i = 0; i < l->count(); ++i) {
00452 if (q == l->itemAt(i)) {
00453 l->removeAt(i);
00454 break;
00455 }
00456 }
00457 }
00458
00459 if (configLoader) {
00460 configLoader->setDefaults();
00461 }
00462
00463 q->scene()->removeItem(q);
00464 q->deleteLater();
00465 }
00466
00467 void AppletPrivate::createMessageOverlay()
00468 {
00469 if (!messageOverlay) {
00470 messageOverlay = new AppletOverlayWidget(q);
00471 } else {
00472 qDeleteAll(messageOverlay->children());
00473 messageOverlay->setLayout(0);
00474 }
00475
00476 messageOverlay->resize(q->contentsRect().size());
00477 messageOverlay->setPos(q->contentsRect().topLeft());
00478
00479
00480 int zValue = 100;
00481 foreach (QGraphicsItem *child, q->QGraphicsItem::children()) {
00482 if (child->zValue() > zValue) {
00483 zValue = child->zValue() + 1;
00484 }
00485 }
00486
00487 messageOverlay->setZValue(zValue);
00488 }
00489
00490 void AppletPrivate::destroyMessageOverlay()
00491 {
00492
00493 QGraphicsWidget *w = messageOverlay;
00494 messageOverlay = 0;
00495 w->hide();
00496 w->deleteLater();
00497 }
00498
00499 ConfigLoader *Applet::configScheme() const
00500 {
00501 return d->configLoader;
00502 }
00503
00504 DataEngine *Applet::dataEngine(const QString &name) const
00505 {
00506 int index = d->loadedEngines.indexOf(name);
00507 if (index != -1) {
00508 return DataEngineManager::self()->engine(name);
00509 }
00510
00511 DataEngine *engine = DataEngineManager::self()->loadEngine(name);
00512 if (engine->isValid()) {
00513 d->loadedEngines.append(name);
00514 }
00515
00516 return engine;
00517 }
00518
00519 const Package *Applet::package() const
00520 {
00521 return d->package;
00522 }
00523
00524 QGraphicsView *Applet::view() const
00525 {
00526
00527
00528
00529 if (!scene()) {
00530 return 0;
00531 }
00532
00533 QGraphicsView *found = 0;
00534 QGraphicsView *possibleFind = 0;
00535
00536 foreach (QGraphicsView *view, scene()->views()) {
00537
00538
00539 if (view->sceneRect().intersects(sceneBoundingRect()) ||
00540 view->sceneRect().contains(scenePos())) {
00541
00542 if (view->isActiveWindow()) {
00543 found = view;
00544 } else {
00545 possibleFind = view;
00546 }
00547 }
00548 }
00549
00550 return found ? found : possibleFind;
00551 }
00552
00553 QRectF Applet::mapFromView(const QGraphicsView *view, const QRect &rect) const
00554 {
00555
00556 return mapFromScene(view->mapToScene(rect)).boundingRect().adjusted(0, 0, 1, 1);
00557 }
00558
00559 QRect Applet::mapToView(const QGraphicsView *view, const QRectF &rect) const
00560 {
00561
00562 return view->mapFromScene(mapToScene(rect)).boundingRect().adjusted(0, 0, -1, -1);
00563 }
00564
00565 QPoint Applet::popupPosition(const QSize &s) const
00566 {
00567 Corona * corona = qobject_cast<Corona*>(scene());
00568 Q_ASSERT(corona);
00569 return corona->popupPosition(this, s);
00570 }
00571
00572 void Applet::updateConstraints(Plasma::Constraints constraints)
00573 {
00574 d->scheduleConstraintsUpdate(constraints);
00575 }
00576
00577 void Applet::constraintsEvent(Plasma::Constraints constraints)
00578 {
00579
00580
00581
00582
00583 Q_UNUSED(constraints)
00584
00585
00586 if (d->script) {
00587 d->script->constraintsEvent(constraints);
00588 }
00589 }
00590
00591 void Applet::initExtenderItem(ExtenderItem *item)
00592 {
00593 kWarning() << "Missing implementation of initExtenderItem in the applet "
00594 << item->config().readEntry("SourceAppletPluginName", "")
00595 << "!\n Any applet that uses extenders should implement initExtenderItem to "
00596 << "instantiate a widget. Destroying the item...";
00597 item->destroy();
00598 }
00599
00600 Extender *Applet::extender() const
00601 {
00602 if (!d->extender) {
00603 new Extender(const_cast<Applet*>(this));
00604 }
00605
00606 return d->extender;
00607 }
00608
00609 void Applet::setBusy(bool busy)
00610 {
00611 if (busy) {
00612 if (!d->busyWidget) {
00613 d->busyWidget = new Plasma::BusyWidget(this);
00614 } else {
00615 d->busyWidget->show();
00616 }
00617 int busySize = qMin(size().width(), size().height())/3;
00618 QRect busyRect(0, 0, busySize, busySize);
00619 busyRect.moveCenter(boundingRect().center().toPoint());
00620 d->busyWidget->setGeometry(busyRect);
00621 } else if (d->busyWidget) {
00622 d->busyWidget->hide();
00623 d->busyWidget->deleteLater();
00624 d->busyWidget = 0;
00625 }
00626 }
00627
00628 bool Applet::isBusy() const
00629 {
00630 return d->busyWidget && d->busyWidget->isVisible();
00631 }
00632
00633 QString Applet::name() const
00634 {
00635 if (isContainment()) {
00636 if (!d->appletDescription.isValid()) {
00637 return i18n("Unknown Activity");
00638 }
00639
00640 const Containment *c = qobject_cast<const Containment*>(this);
00641 if (c && !c->activity().isNull()) {
00642 return i18n("%1 Activity", c->activity());
00643 }
00644 } else if (!d->appletDescription.isValid()) {
00645 return i18n("Unknown Widget");
00646 }
00647
00648 return d->appletDescription.name();
00649 }
00650
00651 QFont Applet::font() const
00652 {
00653 return QApplication::font();
00654 }
00655
00656 QString Applet::icon() const
00657 {
00658 if (!d->appletDescription.isValid()) {
00659 return QString();
00660 }
00661
00662 return d->appletDescription.icon();
00663 }
00664
00665 QString Applet::pluginName() const
00666 {
00667 if (!d->appletDescription.isValid()) {
00668 return QString();
00669 }
00670
00671 return d->appletDescription.pluginName();
00672 }
00673
00674 bool Applet::shouldConserveResources() const
00675 {
00676 return Solid::PowerManagement::appShouldConserveResources();
00677 }
00678
00679 QString Applet::category() const
00680 {
00681 if (!d->appletDescription.isValid()) {
00682 return i18nc("misc category", "Miscellaneous");
00683 }
00684
00685 return d->appletDescription.category();
00686 }
00687
00688 QString Applet::category(const KPluginInfo &applet)
00689 {
00690 return applet.property("X-KDE-PluginInfo-Category").toString();
00691 }
00692
00693 QString Applet::category(const QString &appletName)
00694 {
00695 if (appletName.isEmpty()) {
00696 return QString();
00697 }
00698
00699 QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(appletName);
00700 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
00701
00702 if (offers.isEmpty()) {
00703 return QString();
00704 }
00705
00706 return offers.first()->property("X-KDE-PluginInfo-Category").toString();
00707 }
00708
00709 ImmutabilityType Applet::immutability() const
00710 {
00711
00712 ImmutabilityType coronaImmutability = Mutable;
00713
00714 if (qobject_cast<Corona*>(scene())) {
00715 coronaImmutability = static_cast<Corona*>(scene())->immutability();
00716 }
00717
00718 if (coronaImmutability == SystemImmutable) {
00719 return SystemImmutable;
00720 } else if (coronaImmutability == UserImmutable && d->immutability != SystemImmutable) {
00721 return UserImmutable;
00722 } else {
00723 return d->immutability;
00724 }
00725 }
00726
00727 void Applet::setImmutability(const ImmutabilityType immutable)
00728 {
00729 if (d->immutability == immutable) {
00730 return;
00731 }
00732
00733 d->immutability = immutable;
00734 updateConstraints(ImmutableConstraint);
00735 }
00736
00737 Applet::BackgroundHints Applet::backgroundHints() const
00738 {
00739 return d->backgroundHints;
00740 }
00741
00742 void Applet::setBackgroundHints(const BackgroundHints hints)
00743 {
00744 d->backgroundHints = hints;
00745
00746
00747 if ((hints & StandardBackground) || (hints & TranslucentBackground)) {
00748 if (!d->background) {
00749 d->background = new Plasma::FrameSvg(this);
00750 }
00751
00752 if ((hints & TranslucentBackground) &&
00753 Plasma::Theme::defaultTheme()->currentThemeHasImage("widgets/translucentbackground")) {
00754 d->background->setImagePath("widgets/translucentbackground");
00755 } else {
00756 d->background->setImagePath("widgets/background");
00757 }
00758
00759 d->background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
00760 qreal left, top, right, bottom;
00761 d->background->getMargins(left, top, right, bottom);
00762 setContentsMargins(left, right, top, bottom);
00763 QSizeF fitSize(left + right, top + bottom);
00764 if (minimumSize().expandedTo(fitSize) != minimumSize()) {
00765 setMinimumSize(minimumSize().expandedTo(fitSize));
00766 }
00767 d->background->resizeFrame(boundingRect().size());
00768
00769
00770 if (d->background->hasElement("overlay")) {
00771 QSize overlaySize = d->background->elementSize("overlay");
00772
00773 d->background->d->overlayPos = config().readEntry("overlayposition", QPoint(overlaySize.width()*2, overlaySize.height()*2));
00774
00775
00776 if (d->background->d->overlayPos.x() >= overlaySize.width()*2 ||
00777 d->background->d->overlayPos.y() >= overlaySize.height()*2) {
00778 qsrand(id() + QDateTime::currentDateTime().toTime_t());
00779
00780 d->background->d->overlayPos.rx() = - (overlaySize.width() /4) + (overlaySize.width() /4) * (qrand() % (4 + 1));
00781
00782 d->background->d->overlayPos.ry() = - (overlaySize.height() /4) + (overlaySize.height() /4) * (qrand() % (4 + 1));
00783
00784 config().writeEntry("overlayposition", d->background->d->overlayPos);
00785 }
00786 }
00787
00788 } else if (d->background) {
00789 qreal left, top, right, bottom;
00790 d->background->getMargins(left, top, right, bottom);
00791
00792
00793 setMinimumSize(qMax(minimumSize().width() - left - right, qreal(1.0)),
00794 qMax(minimumSize().height() - top - bottom, qreal(1.0)));
00795
00796 delete d->background;
00797 d->background = 0;
00798 setContentsMargins(0, 0, 0, 0);
00799 }
00800 }
00801
00802 bool Applet::hasFailedToLaunch() const
00803 {
00804 return d->failed;
00805 }
00806
00807 void Applet::paintWindowFrame(QPainter *painter,
00808 const QStyleOptionGraphicsItem *option, QWidget *widget)
00809 {
00810 Q_UNUSED(painter)
00811 Q_UNUSED(option)
00812 Q_UNUSED(widget)
00813
00814
00815
00816 }
00817
00818 bool Applet::configurationRequired() const
00819 {
00820 return d->needsConfig;
00821 }
00822
00823 void Applet::setConfigurationRequired(bool needsConfig, const QString &reason)
00824 {
00825 if (d->needsConfig == needsConfig) {
00826 return;
00827 }
00828
00829 d->needsConfig = needsConfig;
00830
00831 if (!needsConfig) {
00832 d->destroyMessageOverlay();
00833 return;
00834 }
00835
00836 d->createMessageOverlay();
00837
00838 QGraphicsGridLayout *configLayout = new QGraphicsGridLayout(d->messageOverlay);
00839 configLayout->setContentsMargins(0, 0, 0, 0);
00840
00841
00842 configLayout->setColumnStretchFactor(0, 10);
00843 configLayout->setColumnStretchFactor(2, 10);
00844 configLayout->setRowStretchFactor(0, 10);
00845 configLayout->setRowStretchFactor(3, 10);
00846
00847 int row = 1;
00848 if (!reason.isEmpty()) {
00849 Label *explanation = new Label(d->messageOverlay);
00850 explanation->setText(reason);
00851 configLayout->addItem(explanation, row, 1);
00852 configLayout->setColumnStretchFactor(1, 10);
00853 ++row;
00854
00855 }
00856
00857
00858 Plasma::FormFactor f = formFactor();
00859 if (f == Plasma::Horizontal || f == Plasma::Vertical) {
00860 IconWidget *configWidget = new IconWidget(d->messageOverlay);
00861 configWidget->setSvg("widgets/configuration-icons", "configure");
00862 configWidget->setDrawBackground(true);
00863 connect(configWidget, SIGNAL(clicked()), this, SLOT(showConfigurationInterface()));
00864 configLayout->addItem(configWidget, row, 1);
00865
00866 int zValue = 100;
00867 foreach (QGraphicsItem *child, QGraphicsItem::children()) {
00868 if (child->zValue() > zValue) {
00869 zValue = child->zValue() + 1;
00870 }
00871 }
00872 configWidget->setZValue(zValue);
00873 } else {
00874 PushButton *configWidget = new PushButton(d->messageOverlay);
00875 configWidget->setText(i18n("Configure..."));
00876 connect(configWidget, SIGNAL(clicked()), this, SLOT(showConfigurationInterface()));
00877 configLayout->addItem(configWidget, row, 1);
00878 }
00879
00880
00881
00882
00883 d->messageOverlay->show();
00884 }
00885
00886 void Applet::flushPendingConstraintsEvents()
00887 {
00888 if (d->pendingConstraints == NoConstraint) {
00889 return;
00890 }
00891
00892 if (d->constraintsTimerId) {
00893 killTimer(d->constraintsTimerId);
00894 d->constraintsTimerId = 0;
00895 }
00896
00897
00898 Plasma::Constraints c = d->pendingConstraints;
00899 d->pendingConstraints = NoConstraint;
00900
00901 if (c & Plasma::StartupCompletedConstraint) {
00902
00903 bool unlocked = immutability() == Mutable;
00904
00905
00906
00907 QAction *closeApplet = new QAction(this);
00908 closeApplet->setIcon(KIcon("edit-delete"));
00909 closeApplet->setEnabled(unlocked);
00910 closeApplet->setVisible(unlocked);
00911 closeApplet->setShortcutContext(Qt::WidgetShortcut);
00912 closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", name()));
00913 if (isContainment()) {
00914 closeApplet->setShortcut(QKeySequence("ctrl+shift+r"));
00915 } else {
00916 closeApplet->setShortcut(QKeySequence("ctrl+r"));
00917 }
00918 connect(closeApplet, SIGNAL(triggered(bool)), this, SLOT(selectItemToDestroy()));
00919 d->actions.addAction("remove", closeApplet);
00920 }
00921
00922 if (c & Plasma::ImmutableConstraint) {
00923 bool unlocked = immutability() == Mutable;
00924 QAction *action = d->actions.action("remove");
00925 if (action) {
00926 action->setVisible(unlocked);
00927 action->setEnabled(unlocked);
00928 }
00929
00930 bool canConfig = unlocked || KAuthorized::authorize("PlasmaAllowConfigureWhenLocked");
00931 if (canConfig) {
00932 action = d->actions.action("configure");
00933 if (action) {
00934 action->setVisible(canConfig);
00935 action->setEnabled(canConfig);
00936 }
00937 }
00938 }
00939
00940 if (c & Plasma::SizeConstraint) {
00941 if (d->messageOverlay) {
00942 d->messageOverlay->setGeometry(QRectF(QPointF(0, 0), geometry().size()));
00943
00944 QGraphicsItem *button = 0;
00945 QList<QGraphicsItem*> children = d->messageOverlay->QGraphicsItem::children();
00946
00947 if (!children.isEmpty()) {
00948 button = children.first();
00949 }
00950
00951 if (button) {
00952 QSizeF s = button->boundingRect().size();
00953 button->setPos(d->messageOverlay->boundingRect().width() / 2 - s.width() / 2,
00954 d->messageOverlay->boundingRect().height() / 2 - s.height() / 2);
00955 }
00956 }
00957
00958 if (d->busyWidget && d->busyWidget->isVisible()) {
00959 int busySize = qMin(size().width(), size().height())/3;
00960 QRect busyRect(0, 0, busySize, busySize);
00961 busyRect.moveCenter(boundingRect().center().toPoint());
00962 d->busyWidget->setGeometry(busyRect);
00963 }
00964
00965 if (d->started && layout()) {
00966 layout()->updateGeometry();
00967 }
00968 }
00969
00970 if (c & Plasma::FormFactorConstraint) {
00971 FormFactor f = formFactor();
00972 if (!isContainment() && f != Vertical && f != Horizontal) {
00973 setBackgroundHints(d->backgroundHints | StandardBackground);
00974 } else if(d->backgroundHints & StandardBackground) {
00975 setBackgroundHints(d->backgroundHints ^ StandardBackground);
00976 } else if(d->backgroundHints & TranslucentBackground) {
00977 setBackgroundHints(d->backgroundHints ^ TranslucentBackground);
00978 }
00979
00980 if (d->failed) {
00981 if (f == Vertical || f == Horizontal) {
00982 setMinimumSize(0, 0);
00983 QGraphicsLayoutItem *item = layout()->itemAt(1);
00984 layout()->removeAt(1);
00985 delete item;
00986 }
00987 }
00988 }
00989
00990 if (c & Plasma::SizeConstraint || c & Plasma::FormFactorConstraint) {
00991 if (aspectRatioMode() == Plasma::Square) {
00992
00993 if (formFactor() == Horizontal) {
00994 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
00995 } else if (formFactor() == Vertical) {
00996 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
00997 }
00998
00999 updateGeometry();
01000 } else if (aspectRatioMode() == Plasma::ConstrainedSquare) {
01001
01002 if (formFactor() == Horizontal) {
01003 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
01004 } else if (formFactor() == Vertical) {
01005 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
01006 }
01007
01008 updateGeometry();
01009 }
01010 }
01011
01012
01013 Containment* containment = qobject_cast<Plasma::Containment*>(this);
01014 if (isContainment() && containment) {
01015 containment->d->containmentConstraintsEvent(c);
01016 }
01017
01018 PopupApplet* popup = qobject_cast<Plasma::PopupApplet*>(this);
01019 if (popup) {
01020 popup->d->popupConstraintsEvent(c);
01021 }
01022
01023
01024 constraintsEvent(c);
01025
01026 if (c & StartupCompletedConstraint) {
01027
01028 if (d->modificationsTimerId > 0) {
01029 killTimer(d->modificationsTimerId);
01030 }
01031 d->modificationsTimerId = 0;
01032
01033 if (!isContainment()) {
01034 setHasConfigurationInterface(true);
01035 }
01036 }
01037 }
01038
01039 int Applet::type() const
01040 {
01041 return Type;
01042 }
01043
01044 QList<QAction*> Applet::contextualActions()
01045 {
01046
01047 return d->script ? d->script->contextualActions() : QList<QAction*>();
01048 }
01049
01050 QAction *Applet::action(QString name) const
01051 {
01052 return d->actions.action(name);
01053 }
01054
01055 void Applet::addAction(QString name, QAction *action)
01056 {
01057 d->actions.addAction(name, action);
01058 }
01059
01060 void Applet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
01061 {
01062 if (!d->started) {
01063 kDebug() << "not started";
01064 return;
01065 }
01066
01067 if (transform().isRotating()) {
01068 painter->setRenderHint(QPainter::SmoothPixmapTransform);
01069 painter->setRenderHint(QPainter::Antialiasing);
01070 }
01071
01072 if (d->background &&
01073 formFactor() != Plasma::Vertical &&
01074 formFactor() != Plasma::Horizontal) {
01075
01076 d->background->paintFrame(painter);
01077 }
01078
01079 if (d->failed) {
01080 kDebug() << "failed!";
01081 return;
01082 }
01083
01084 qreal left, top, right, bottom;
01085 getContentsMargins(&left, &top, &right, &bottom);
01086 QRect contentsRect = QRectF(QPointF(0, 0),
01087 boundingRect().size()).adjusted(left, top, -right, -bottom).toRect();
01088
01089 if (widget && isContainment()) {
01090
01091 View* v = qobject_cast<Plasma::View*>(widget->parent());
01092 Containment* c = qobject_cast<Plasma::Containment*>(this);
01093
01094
01095 if (c && c->d->toolBox) {
01096 if (c->d->toolBox->viewTransform().isScaling() && !v->transform().isScaling()) {
01097 c->d->positionToolBox();
01098 }
01099 if (v) {
01100 c->d->toolBox->setViewTransform(v->transform());
01101 }
01102 }
01103
01104 if (!v || v->isWallpaperEnabled()) {
01105
01106
01107 if (c && c->drawWallpaper() && c->wallpaper()) {
01108 Wallpaper *w = c->wallpaper();
01109 if (!w->isInitialized()) {
01110
01111 KConfigGroup wallpaperConfig = c->config();
01112 wallpaperConfig = KConfigGroup(&wallpaperConfig, "Wallpaper");
01113 wallpaperConfig = KConfigGroup(&wallpaperConfig, w->pluginName());
01114 w->restore(wallpaperConfig);
01115 }
01116
01117 painter->save();
01118 c->wallpaper()->paint(painter, option->exposedRect);
01119 painter->restore();
01120 }
01121
01122
01123
01124 Containment::StyleOption coption(*option);
01125 coption.view = v;
01126 paintInterface(painter, &coption, contentsRect);
01127 }
01128 } else {
01129
01130
01131 paintInterface(painter, option, contentsRect);
01132 }
01133 }
01134
01135 void Applet::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
01136 {
01137 if (d->script) {
01138 d->script->paintInterface(painter, option, contentsRect);
01139 } else {
01140
01141 }
01142 }
01143
01144 FormFactor Applet::formFactor() const
01145 {
01146 Containment *c = containment();
01147 return c ? c->d->formFactor : Plasma::Planar;
01148 }
01149
01150 Containment *Applet::containment() const
01151 {
01152 if (isContainment()) {
01153 Containment *c = qobject_cast<Containment*>(const_cast<Applet*>(this));
01154 if (c) {
01155 return c;
01156 }
01157 }
01158
01159 QGraphicsItem *parent = parentItem();
01160 Containment *c = 0;
01161
01162 while (parent) {
01163 Containment *possibleC = dynamic_cast<Containment*>(parent);
01164 if (possibleC && possibleC->isContainment()) {
01165 c = possibleC;
01166 break;
01167 }
01168 parent = parent->parentItem();
01169 }
01170
01171 return c;
01172 }
01173
01174 void Applet::setGlobalShortcut(const KShortcut &shortcut)
01175 {
01176 if (!d->activationAction) {
01177 d->activationAction = new KAction(this);
01178 d->activationAction->setText(i18n("Activate %1 Widget", name()));
01179 d->activationAction->setObjectName(QString("activate widget %1").arg(id()));
01180 connect(d->activationAction, SIGNAL(triggered()), this, SIGNAL(activate()));
01181 connect(this, SIGNAL(activate()), this, SLOT(setFocus()));
01182
01183 QList<QWidget *> widgets = d->actions.associatedWidgets();
01184 foreach (QWidget *w, widgets) {
01185 w->addAction(d->activationAction);
01186 }
01187 }
01188
01189
01190 d->activationAction->setGlobalShortcut(
01191 shortcut,
01192 KAction::ShortcutTypes(KAction::ActiveShortcut | KAction::DefaultShortcut),
01193 KAction::NoAutoloading);
01194
01195 }
01196
01197 KShortcut Applet::globalShortcut() const
01198 {
01199 if (d->activationAction) {
01200 return d->activationAction->globalShortcut();
01201 }
01202
01203 return KShortcut();
01204 }
01205
01206 bool Applet::isPopupShowing() const
01207 {
01208 return false;
01209 }
01210
01211 void Applet::addAssociatedWidget(QWidget *widget)
01212 {
01213 d->actions.addAssociatedWidget(widget);
01214 }
01215
01216 void Applet::removeAssociatedWidget(QWidget *widget)
01217 {
01218 d->actions.removeAssociatedWidget(widget);
01219 }
01220
01221 Location Applet::location() const
01222 {
01223 Containment *c = containment();
01224 return c ? c->d->location : Plasma::Desktop;
01225 }
01226
01227 Context *Applet::context() const
01228 {
01229 Containment *c = containment();
01230 Q_ASSERT(c);
01231 return c->d->context();
01232 }
01233
01234 Plasma::AspectRatioMode Applet::aspectRatioMode() const
01235 {
01236 return d->aspectRatioMode;
01237 }
01238
01239 void Applet::setAspectRatioMode(Plasma::AspectRatioMode mode)
01240 {
01241 d->aspectRatioMode = mode;
01242 }
01243
01244 void Applet::registerAsDragHandle(QGraphicsItem *item)
01245 {
01246 if (!item || d->registeredAsDragHandle.contains(item)) {
01247 return;
01248 }
01249
01250 d->registeredAsDragHandle.insert(item);
01251 item->installSceneEventFilter(this);
01252 }
01253
01254 void Applet::unregisterAsDragHandle(QGraphicsItem *item)
01255 {
01256 if (!item) {
01257 return;
01258 }
01259
01260 if (d->registeredAsDragHandle.remove(item)) {
01261 item->removeSceneEventFilter(this);
01262 }
01263 }
01264
01265 bool Applet::isRegisteredAsDragHandle(QGraphicsItem *item)
01266 {
01267 return d->registeredAsDragHandle.contains(item);
01268 }
01269
01270 bool Applet::hasConfigurationInterface() const
01271 {
01272 return d->hasConfigurationInterface;
01273 }
01274
01275 void Applet::setHasConfigurationInterface(bool hasInterface)
01276 {
01277 if (d->hasConfigurationInterface == hasInterface) {
01278 return;
01279 }
01280
01281 d->hasConfigurationInterface = hasInterface;
01282
01283
01284 QAction *configAction = d->actions.action("configure");
01285 if (hasInterface) {
01286 if (!configAction) {
01287 configAction = new QAction(i18n("%1 Settings", name()), this);
01288 configAction->setIcon(KIcon("configure"));
01289 configAction->setShortcutContext(Qt::WidgetShortcut);
01290 bool unlocked = immutability() == Mutable;
01291 bool canConfig = unlocked || KAuthorized::authorize("PlasmaAllowConfigureWhenLocked");
01292 configAction->setVisible(canConfig);
01293 configAction->setEnabled(canConfig);
01294 if (isContainment()) {
01295
01296 configAction->setShortcut(QKeySequence("ctrl+shift+s"));
01297 } else {
01298 configAction->setShortcut(QKeySequence("ctrl+s"));
01299 }
01300 connect(configAction, SIGNAL(triggered(bool)),
01301 this, SLOT(showConfigurationInterface()));
01302 d->actions.addAction("configure", configAction);
01303 }
01304 } else {
01305 d->actions.removeAction(configAction);
01306 }
01307 }
01308
01309 bool Applet::eventFilter(QObject *o, QEvent *e)
01310 {
01311 return QObject::eventFilter(o, e);
01312 }
01313
01314 bool Applet::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
01315 {
01316 switch (event->type()) {
01317 case QEvent::GraphicsSceneMouseMove:
01318 {
01319
01320
01321 if (d->registeredAsDragHandle.contains(watched)) {
01322 Containment *c = containment();
01323 if (!c || c->immutability() == Mutable) {
01324 mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(event));
01325 return true;
01326 }
01327 }
01328 break;
01329 }
01330
01331 default:
01332 break;
01333 }
01334
01335 return QGraphicsItem::sceneEventFilter(watched, event);
01336 }
01337
01338 void Applet::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
01339 {
01340 if (immutability() == Mutable && formFactor() == Plasma::Planar) {
01341 QGraphicsItem *parent = parentItem();
01342 Plasma::Applet *applet = qgraphicsitem_cast<Plasma::Applet*>(parent);
01343
01344 if (applet && applet->isContainment()) {
01345
01346 QPointF curPos = event->pos();
01347 QPointF lastPos = event->lastPos();
01348 QPointF delta = curPos - lastPos;
01349
01350 moveBy(delta.x(), delta.y());
01351 } else if (parent) {
01352
01353
01354
01355 QPointF curPos = parent->transform().map(event->pos());
01356 QPointF lastPos = parent->transform().map(event->lastPos());
01357 QPointF delta = curPos - lastPos;
01358
01359 parent->setPos(parent->pos() + delta);
01360 }
01361 }
01362 }
01363
01364 void Applet::focusInEvent(QFocusEvent *event)
01365 {
01366 if (!isContainment() && containment()) {
01367
01368 containment()->d->focusApplet(this);
01369 }
01370
01371 QGraphicsWidget::focusInEvent(event);
01372 }
01373
01374 void Applet::resizeEvent(QGraphicsSceneResizeEvent *event)
01375 {
01376 QGraphicsWidget::resizeEvent(event);
01377
01378 if (d->background) {
01379 d->background->resizeFrame(boundingRect().size());
01380 }
01381
01382 updateConstraints(Plasma::SizeConstraint);
01383
01384 d->scheduleModificationNotification();
01385 emit geometryChanged();
01386 }
01387
01388 void Applet::showConfigurationInterface()
01389 {
01390 if (!hasConfigurationInterface()) {
01391 return;
01392 }
01393
01394 if (immutability() != Mutable && !KAuthorized::authorize("PlasmaAllowConfigureWhenLocked")) {
01395
01396 return;
01397 }
01398
01399 const QString dialogId = QString("%1settings%2").arg(id()).arg(name());
01400 KConfigDialog * dlg = KConfigDialog::exists(dialogId);
01401
01402 if (dlg) {
01403 KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
01404 dlg->show();
01405 KWindowSystem::activateWindow(dlg->winId());
01406 return;
01407 }
01408
01409 const QString windowTitle = i18nc("@title:window", "%1 Settings", name());
01410 if (d->package && d->configLoader) {
01411 QString uiFile = d->package->filePath("mainconfigui");
01412 if (uiFile.isEmpty()) {
01413 return;
01414 }
01415
01416 KConfigDialog *dialog = new KConfigDialog(0, dialogId, d->configLoader);
01417 dialog->setWindowTitle(windowTitle);
01418 dialog->setAttribute(Qt::WA_DeleteOnClose, true);
01419
01420 QUiLoader loader;
01421 QFile f(uiFile);
01422 if (!f.open(QIODevice::ReadOnly)) {
01423 delete dialog;
01424
01425 if (d->script) {
01426 d->script->showConfigurationInterface();
01427 }
01428 return;
01429 }
01430
01431 QWidget *w = loader.load(&f);
01432 f.close();
01433
01434 dialog->addPage(w, i18n("Settings"), icon(), i18n("%1 Settings", name()));
01435 d->addGlobalShortcutsPage(dialog);
01436 connect(dialog, SIGNAL(applyClicked()), this, SLOT(configDialogFinished()));
01437 connect(dialog, SIGNAL(okClicked()), this, SLOT(configDialogFinished()));
01438
01439 connect(dialog, SIGNAL(finished()), this, SLOT(configDialogFinished()));
01440 dialog->show();
01441 } else if (d->script) {
01442
01443 d->script->showConfigurationInterface();
01444 } else {
01445 KConfigSkeleton *nullManager = new KConfigSkeleton(0);
01446 KConfigDialog *dialog = new KConfigDialog(0, dialogId, nullManager);
01447 dialog->setFaceType(KPageDialog::Auto);
01448 dialog->setWindowTitle(windowTitle);
01449 dialog->setAttribute(Qt::WA_DeleteOnClose, true);
01450 createConfigurationInterface(dialog);
01451 d->addGlobalShortcutsPage(dialog);
01452 connect(dialog, SIGNAL(finished()), nullManager, SLOT(deleteLater()));
01453
01454 dialog->showButton(KDialog::Apply, false);
01455 connect(dialog, SIGNAL(applyClicked()), this, SLOT(configDialogFinished()));
01456 connect(dialog, SIGNAL(okClicked()), this, SLOT(configDialogFinished()));
01457 connect(dialog, SIGNAL(finished()), this, SLOT(configDialogFinished()));
01458 dialog->show();
01459 }
01460
01461 emit releaseVisualFocus();
01462 }
01463
01464 void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog)
01465 {
01466 if (isContainment) {
01467 return;
01468 }
01469
01470 QWidget *page = new QWidget;
01471 QVBoxLayout *layout = new QVBoxLayout(page);
01472
01473 if (!shortcutEditor) {
01474 shortcutEditor = new KKeySequenceWidget(page);
01475 QObject::connect(shortcutEditor, SIGNAL(destroyed(QObject*)), q, SLOT(clearShortcutEditorPtr()));
01476 }
01477
01478 shortcutEditor->setKeySequence(q->globalShortcut().primary());
01479 layout->addWidget(shortcutEditor);
01480 layout->addStretch();
01481 dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard");
01482 }
01483
01484 void AppletPrivate::clearShortcutEditorPtr()
01485 {
01486 shortcutEditor = 0;
01487 }
01488
01489 void AppletPrivate::configDialogFinished()
01490 {
01491 if (shortcutEditor) {
01492 QKeySequence sequence = shortcutEditor->keySequence();
01493 if (sequence != q->globalShortcut().primary()) {
01494 q->setGlobalShortcut(KShortcut(sequence));
01495 emit q->configNeedsSaving();
01496 }
01497 }
01498
01499 q->configChanged();
01500 }
01501
01502 void Applet::configChanged()
01503 {
01504 if (d->script) {
01505 d->script->configChanged();
01506 }
01507 }
01508
01509 void Applet::createConfigurationInterface(KConfigDialog *parent)
01510 {
01511 Q_UNUSED(parent)
01512
01513
01514 }
01515
01516 KPluginInfo::List Applet::listAppletInfo(const QString &category,
01517 const QString &parentApp)
01518 {
01519 QString constraint;
01520
01521 if (parentApp.isEmpty()) {
01522 constraint.append("not exist [X-KDE-ParentApp]");
01523 } else {
01524 constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'");
01525 }
01526
01527 if (!category.isEmpty()) {
01528 if (!constraint.isEmpty()) {
01529 constraint.append(" and ");
01530 }
01531
01532 constraint.append("[X-KDE-PluginInfo-Category] == '").append(category).append("'");
01533 if (category == "Miscellaneous") {
01534 constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
01535 }
01536 }
01537
01538 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
01539
01540
01541 return KPluginInfo::fromServices(offers);
01542 }
01543
01544 KPluginInfo::List Applet::listAppletInfoForMimetype(const QString &mimetype)
01545 {
01546 QString constraint = QString("'%1' in [X-Plasma-DropMimeTypes]").arg(mimetype);
01547
01548 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
01549 return KPluginInfo::fromServices(offers);
01550 }
01551
01552 QStringList Applet::listCategories(const QString &parentApp, bool visibleOnly)
01553 {
01554 QString constraint = "exist [X-KDE-PluginInfo-Category]";
01555
01556 if (parentApp.isEmpty()) {
01557 constraint.append(" and not exist [X-KDE-ParentApp]");
01558 } else {
01559 constraint.append(" and [X-KDE-ParentApp] == '").append(parentApp).append("'");
01560 }
01561
01562 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
01563 QStringList categories;
01564 foreach (const KService::Ptr &applet, offers) {
01565 QString appletCategory = applet->property("X-KDE-PluginInfo-Category").toString();
01566 if (visibleOnly && applet->noDisplay()) {
01567
01568 continue;
01569 }
01570
01571
01572 if (appletCategory.isEmpty()) {
01573 if (!categories.contains(i18nc("misc category", "Miscellaneous"))) {
01574 categories << i18nc("misc category", "Miscellaneous");
01575 }
01576 } else if (!categories.contains(appletCategory)) {
01577 categories << appletCategory;
01578 }
01579 }
01580
01581 categories.sort();
01582 return categories;
01583 }
01584
01585 Applet *Applet::load(const QString &appletName, uint appletId, const QVariantList &args)
01586 {
01587 if (appletName.isEmpty()) {
01588 return 0;
01589 }
01590
01591 QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(appletName);
01592 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint);
01593
01594 bool isContainment = false;
01595 if (offers.isEmpty()) {
01596
01597
01598 offers = KServiceTypeTrader::self()->query("Plasma/Containment", constraint);
01599 isContainment = true;
01600 if (offers.isEmpty()) {
01601 kDebug() << "offers is empty for " << appletName;
01602 return 0;
01603 }
01604 }
01605
01606
01607
01608 KService::Ptr offer = offers.first();
01609
01610 if (appletId == 0) {
01611 appletId = ++AppletPrivate::s_maxAppletId;
01612 }
01613
01614 if (!offer->property("X-Plasma-API").toString().isEmpty()) {
01615 kDebug() << "we have a script using the"
01616 << offer->property("X-Plasma-API").toString() << "API";
01617 if (isContainment) {
01618 return new Containment(0, offer->storageId(), appletId);
01619 }
01620 return new Applet(0, offer->storageId(), appletId);
01621 }
01622
01623 KPluginLoader plugin(*offer);
01624
01625 if (!Plasma::isPluginVersionCompatible(plugin.pluginVersion()) &&
01626 (appletName != "internal:extender")) {
01627 return 0;
01628 }
01629
01630 QVariantList allArgs;
01631 allArgs << offer->storageId() << appletId << args;
01632 QString error;
01633 Applet *applet;
01634
01635 if (appletName == "internal:extender") {
01636 applet = new ExtenderApplet(0, allArgs);
01637 } else {
01638 applet = offer->createInstance<Plasma::Applet>(0, allArgs, &error);
01639 }
01640
01641 if (!applet) {
01642 kDebug() << "Couldn't load applet \"" << appletName << "\"! reason given: " << error;
01643 }
01644
01645 return applet;
01646 }
01647
01648 Applet *Applet::load(const KPluginInfo &info, uint appletId, const QVariantList &args)
01649 {
01650 if (!info.isValid()) {
01651 return 0;
01652 }
01653
01654 return load(info.pluginName(), appletId, args);
01655 }
01656
01657 QVariant Applet::itemChange(GraphicsItemChange change, const QVariant &value)
01658 {
01659 QVariant ret = QGraphicsWidget::itemChange(change, value);
01660
01661
01662 switch (change) {
01663 case ItemSceneHasChanged:
01664 {
01665 QGraphicsScene *newScene = qvariant_cast<QGraphicsScene*>(value);
01666 if (newScene) {
01667 d->checkImmutability();
01668 }
01669 }
01670 break;
01671 case ItemPositionChange:
01672 return (immutability() == Mutable || formFactor() == Horizontal || formFactor() == Vertical) ? value : pos();
01673 break;
01674 case ItemTransformChange:
01675 return immutability() == Mutable ? value : transform();
01676 break;
01677 case ItemPositionHasChanged:
01678 emit geometryChanged();
01679
01680 case ItemTransformHasChanged:
01681 d->scheduleModificationNotification();
01682 break;
01683 default:
01684 break;
01685 };
01686
01687 return ret;
01688 }
01689
01690 QPainterPath Applet::shape() const
01691 {
01692 if (d->script) {
01693 return d->script->shape();
01694 }
01695
01696 return QGraphicsWidget::shape();
01697 }
01698
01699 QSizeF Applet::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
01700 {
01701 QSizeF hint = QGraphicsWidget::sizeHint(which, constraint);
01702
01703
01704 if (formFactor() == Horizontal && which == Qt::MinimumSize) {
01705 hint.setHeight(0);
01706 } else if (formFactor() == Vertical && which == Qt::MinimumSize) {
01707 hint.setWidth(0);
01708 }
01709
01710
01711 if (d->aspectRatioMode == Plasma::Square) {
01712 if (formFactor() == Horizontal) {
01713 hint.setWidth(size().height());
01714 } else if (formFactor() == Vertical) {
01715 hint.setHeight(size().width());
01716 }
01717 } else if (d->aspectRatioMode == Plasma::ConstrainedSquare) {
01718
01719 if (formFactor() == Horizontal &&
01720 (which == Qt::MaximumSize || size().height() <= KIconLoader::SizeLarge)) {
01721 hint.setWidth(size().height());
01722
01723 } else if (formFactor() == Vertical &&
01724 (which == Qt::MaximumSize || size().width() <= KIconLoader::SizeLarge)) {
01725 hint.setHeight(size().width());
01726 }
01727 }
01728
01729 return hint;
01730 }
01731
01732 void Applet::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
01733 {
01734 Q_UNUSED(event)
01735 }
01736
01737 void Applet::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
01738 {
01739 Q_UNUSED(event)
01740 }
01741
01742 void Applet::timerEvent(QTimerEvent *event)
01743 {
01744 if (d->transient) {
01745 killTimer(d->constraintsTimerId);
01746 killTimer(d->modificationsTimerId);
01747 return;
01748 }
01749
01750 if (event->timerId() == d->constraintsTimerId) {
01751 killTimer(d->constraintsTimerId);
01752 d->constraintsTimerId = 0;
01753
01754
01755
01756 if(!(d->pendingConstraints & Plasma::StartupCompletedConstraint)) {
01757 flushPendingConstraintsEvents();
01758 }
01759 } else if (event->timerId() == d->modificationsTimerId) {
01760 killTimer(d->modificationsTimerId);
01761 d->modificationsTimerId = 0;
01762
01763 KConfigGroup cg;
01764 save(cg);
01765 emit configNeedsSaving();
01766 }
01767 }
01768
01769 QRect Applet::screenRect() const
01770 {
01771 QGraphicsView *v = view();
01772
01773 if (v) {
01774 QPointF bottomRight = pos();
01775 bottomRight.rx() += size().width();
01776 bottomRight.ry() += size().height();
01777
01778 QPoint tL = v->mapToGlobal(v->mapFromScene(pos()));
01779 QPoint bR = v->mapToGlobal(v->mapFromScene(bottomRight));
01780 return QRect(QPoint(tL.x(), tL.y()), QSize(bR.x() - tL.x(), bR.y() - tL.y()));
01781 }
01782
01783
01784
01785 return QRect(QPoint(0, 0), QSize(0, 0));
01786 }
01787
01788 void Applet::raise()
01789 {
01790 setZValue(++AppletPrivate::s_maxZValue);
01791 }
01792
01793 void Applet::lower()
01794 {
01795 setZValue(--AppletPrivate::s_minZValue);
01796 }
01797
01798 void AppletPrivate::setIsContainment(bool nowIsContainment)
01799 {
01800 if (isContainment == nowIsContainment) {
01801 return;
01802 }
01803
01804 isContainment = nowIsContainment;
01805
01806 Containment *c = qobject_cast<Containment*>(q);
01807 if (c) {
01808 if (isContainment) {
01809
01810 c->d->createToolBox();
01811 } else {
01812 delete c->d->toolBox;
01813 c->d->toolBox = 0;
01814 }
01815 }
01816 }
01817
01818 bool Applet::isContainment() const
01819 {
01820 return d->isContainment;
01821 }
01822
01823
01824
01825 AppletPrivate::AppletPrivate(KService::Ptr service, int uniqueID, Applet *applet)
01826 : appletId(uniqueID),
01827 q(applet),
01828 extender(0),
01829 backgroundHints(Applet::StandardBackground),
01830 appletDescription(service),
01831 messageOverlay(0),
01832 busyWidget(0),
01833 background(0),
01834 script(0),
01835 package(0),
01836 configLoader(0),
01837 mainConfig(0),
01838 pendingConstraints(NoConstraint),
01839 aspectRatioMode(Plasma::KeepAspectRatio),
01840 immutability(Mutable),
01841 actions(applet),
01842 activationAction(0),
01843 shortcutEditor(0),
01844 constraintsTimerId(0),
01845 modificationsTimerId(-1),
01846 hasConfigurationInterface(false),
01847 failed(false),
01848 isContainment(false),
01849 transient(false),
01850 needsConfig(false),
01851 started(false)
01852 {
01853 if (appletId == 0) {
01854 appletId = ++s_maxAppletId;
01855 } else if (appletId > s_maxAppletId) {
01856 s_maxAppletId = appletId;
01857 }
01858 }
01859
01860 AppletPrivate::~AppletPrivate()
01861 {
01862 modificationsTimerId = -1;
01863
01864 if (activationAction && activationAction->isGlobalShortcutEnabled()) {
01865
01866 activationAction->forgetGlobalShortcut();
01867 }
01868
01869 foreach (const QString &engine, loadedEngines) {
01870 DataEngineManager::self()->unloadEngine(engine);
01871 }
01872
01873 if (extender) {
01874 delete extender;
01875 extender = 0;
01876 }
01877
01878 delete script;
01879 script = 0;
01880 delete package;
01881 package = 0;
01882 delete configLoader;
01883 configLoader = 0;
01884 delete mainConfig;
01885 mainConfig = 0;
01886 }
01887
01888 void AppletPrivate::init()
01889 {
01890
01891
01892 q->setCacheMode(Applet::DeviceCoordinateCache);
01893 q->setAcceptsHoverEvents(true);
01894 q->setFlag(QGraphicsItem::ItemIsFocusable, true);
01895 q->setFocusPolicy(Qt::ClickFocus);
01896
01897
01898 q->setLayoutDirection(qApp->layoutDirection());
01899
01900 if (!appletDescription.isValid()) {
01901 kDebug() << "Check your constructor! "
01902 << "You probably want to be passing in a Service::Ptr "
01903 << "or a QVariantList with a valid storageid as arg[0].";
01904 return;
01905 }
01906
01907 QString api = appletDescription.property("X-Plasma-API").toString();
01908
01909
01910 if (!api.isEmpty()) {
01911
01912 QString path = KStandardDirs::locate(
01913 "data",
01914 "plasma/plasmoids/" + appletDescription.pluginName() + '/');
01915
01916 if (path.isEmpty()) {
01917 q->setFailedToLaunch(
01918 true,
01919 i18nc("Package file, name of the widget",
01920 "Could not locate the %1 package required for the %2 widget.",
01921 appletDescription.pluginName(), appletDescription.name()));
01922 } else {
01923
01924
01925 PackageStructure::Ptr structure =
01926 Plasma::packageStructure(api, Plasma::AppletComponent);
01927 structure->setPath(path);
01928 package = new Package(path, structure);
01929
01930 if (package->isValid()) {
01931
01932
01933
01934
01935 script = Plasma::loadScriptEngine(api, q);
01936 if (!script) {
01937 delete package;
01938 package = 0;
01939 q->setFailedToLaunch(true,
01940 i18nc("API or programming language the widget was written in, name of the widget",
01941 "Could not create a %1 ScriptEngine for the %2 widget.",
01942 api, appletDescription.name()));
01943 }
01944 } else {
01945 q->setFailedToLaunch(true, i18nc("Package file, name of the widget",
01946 "Could not open the %1 package required for the %2 widget.",
01947 appletDescription.pluginName(), appletDescription.name()));
01948 delete package;
01949 package = 0;
01950 }
01951
01952 if (package) {
01953 setupScriptSupport();
01954 }
01955 }
01956 }
01957
01958 q->setBackgroundHints(Applet::DefaultBackground);
01959
01960 QObject::connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), q, SLOT(themeChanged()));
01961 }
01962
01963
01964
01965 void AppletPrivate::setupScriptSupport()
01966 {
01967 Q_ASSERT(package);
01968 kDebug() << "setting up script support, package is in" << package->path()
01969 << "which is a" << package->structure()->type() << "package"
01970 << ", main script is" << package->filePath("mainscript");
01971
01972 QString xmlPath = package->filePath("mainconfigxml");
01973 if (!xmlPath.isEmpty()) {
01974 QFile file(xmlPath);
01975 KConfigGroup config = q->config();
01976 configLoader = new ConfigLoader(&config, &file);
01977 QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(configChanged()));
01978 }
01979
01980 if (!package->filePath("mainconfigui").isEmpty()) {
01981 q->setHasConfigurationInterface(true);
01982 }
01983
01984
01985 QSize size = appletDescription.property("X-Plasma-DefaultSize").toSize();
01986 if (size.isEmpty()) {
01987 size = QSize(200,200);
01988 }
01989
01990 q->resize(size);
01991
01992 }
01993
01994 QString AppletPrivate::globalName() const
01995 {
01996 if (!appletDescription.isValid()) {
01997 return QString();
01998 }
01999
02000 return appletDescription.service()->library();
02001 }
02002
02003 QString AppletPrivate::instanceName()
02004 {
02005 if (!appletDescription.isValid()) {
02006 return QString();
02007 }
02008
02009 return appletDescription.service()->library() + QString::number(appletId);
02010 }
02011
02012 void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c)
02013 {
02014
02015
02016 if (started && !constraintsTimerId && !(c & Plasma::StartupCompletedConstraint)) {
02017 constraintsTimerId = q->startTimer(0);
02018 }
02019
02020 if (c & Plasma::StartupCompletedConstraint) {
02021 started = true;
02022 }
02023
02024 pendingConstraints |= c;
02025 }
02026
02027 void AppletPrivate::scheduleModificationNotification()
02028 {
02029
02030 if (modificationsTimerId != -1) {
02031
02032 if (modificationsTimerId) {
02033 q->killTimer(modificationsTimerId);
02034 }
02035
02036 modificationsTimerId = q->startTimer(1000);
02037 }
02038 }
02039
02040 KConfigGroup *AppletPrivate::mainConfigGroup()
02041 {
02042 if (mainConfig) {
02043 return mainConfig;
02044 }
02045
02046 if (isContainment) {
02047 Corona *corona = qobject_cast<Corona*>(q->scene());
02048 KConfigGroup containmentConfig;
02049
02050
02051 if (corona) {
02052 containmentConfig = KConfigGroup(corona->config(), "Containments");
02053 } else {
02054 containmentConfig = KConfigGroup(KGlobal::config(), "Containments");
02055 }
02056
02057 mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId));
02058 } else {
02059 KConfigGroup appletConfig;
02060 if (q->containment()) {
02061 appletConfig = q->containment()->config();
02062 appletConfig = KConfigGroup(&appletConfig, "Applets");
02063 } else {
02064 kWarning() << "requesting config for" << q->name() << "without a containment!";
02065 appletConfig = KConfigGroup(KGlobal::config(), "Applets");
02066 }
02067
02068 mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId));
02069 }
02070
02071 return mainConfig;
02072 }
02073
02074 QString AppletPrivate::visibleFailureText(const QString &reason)
02075 {
02076 QString text;
02077
02078 if (reason.isEmpty()) {
02079 text = i18n("This object could not be created.");
02080 } else {
02081 text = i18n("This object could not be created for the following reason:<p><b>%1</b></p>", reason);
02082 }
02083
02084 return text;
02085 }
02086
02087 void AppletPrivate::checkImmutability()
02088 {
02089 const bool systemImmutable = q->globalConfig().isImmutable() || q->config().isImmutable() ||
02090 ((!isContainment && q->containment()) &&
02091 q->containment()->immutability() == SystemImmutable) ||
02092 (qobject_cast<Corona*>(q->scene()) && static_cast<Corona*>(q->scene())->immutability() == SystemImmutable);
02093
02094 if (systemImmutable) {
02095 q->updateConstraints(ImmutableConstraint);
02096 }
02097 }
02098
02099 void AppletPrivate::themeChanged()
02100 {
02101 if (background) {
02102
02103 q->setBackgroundHints(backgroundHints);
02104
02105 qreal left;
02106 qreal right;
02107 qreal top;
02108 qreal bottom;
02109 background->getMargins(left, top, right, bottom);
02110 q->setContentsMargins(left, right, top, bottom);
02111 }
02112 q->update();
02113 }
02114
02115 void AppletPrivate::resetConfigurationObject()
02116 {
02117
02118 mainConfigGroup();
02119
02120 mainConfig->deleteGroup();
02121 delete mainConfig;
02122 mainConfig = 0;
02123 }
02124
02125 uint AppletPrivate::s_maxAppletId = 0;
02126 uint AppletPrivate::s_maxZValue = 0;
02127 uint AppletPrivate::s_minZValue = 0;
02128 PackageStructure::Ptr AppletPrivate::packageStructure(0);
02129
02130 AppletOverlayWidget::AppletOverlayWidget(QGraphicsWidget *parent)
02131 : QGraphicsWidget(parent)
02132 {
02133 resize(parent->size());
02134 }
02135
02136 void AppletOverlayWidget::paint(QPainter *painter,
02137 const QStyleOptionGraphicsItem *option,
02138 QWidget *widget)
02139 {
02140 Q_UNUSED(option)
02141 Q_UNUSED(widget)
02142 painter->setRenderHint(QPainter::Antialiasing);
02143 QColor wash = Plasma::Theme::defaultTheme()->color(Theme::BackgroundColor);
02144 wash.setAlphaF(.6);
02145
02146 Applet *applet = qobject_cast<Applet *>(parentWidget());
02147
02148 if (applet->backgroundHints() & Applet::StandardBackground) {
02149 painter->fillRect(parentWidget()->contentsRect(), wash);
02150 } else {
02151 painter->fillPath(parentItem()->shape(), wash);
02152 }
02153 }
02154
02155 }
02156
02157 #include "applet.moc"