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