diff --git a/CMakeLists.txt b/CMakeLists.txt index 1494bf3d9..c28e8b3ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ set(plasma_LIB_SRCS datacontainer.cpp dataengine.cpp dataenginemanager.cpp - delegate.cpp + package.cpp packagestructure.cpp paintutils.cpp @@ -138,7 +138,8 @@ set(plasma_LIB_SRCS private/wallpaperrenderthread.cpp private/windowpreview.cpp private/windowshadows.cpp - private/kineticscroll.cpp + private/appletprivate.cpp + querymatch.cpp remote/accessmanager.cpp remote/accessappletjob.cpp @@ -168,7 +169,6 @@ set(plasma_LIB_SRCS tooltipcontent.cpp tooltipmanager.cpp version.cpp - view.cpp wallpaper.cpp @@ -189,9 +189,11 @@ set(plasma_LIB_SRCS #FIXME: all these must move into the qgv library private/themedwidgetinterface.cpp widgets/iconwidget.cpp + view.cpp ) set (plasmaqgv_LIB_SRCS + delegate.cpp #FIXME: this is duplicated with libplasma because iconwidget requires it! private/themedwidgetinterface.cpp @@ -218,6 +220,7 @@ set (plasmaqgv_LIB_SRCS private/focusindicator.cpp private/nativetabbar.cpp private/style.cpp + private/kineticscroll.cpp widgets/label.cpp widgets/scrollbar.cpp diff --git a/applet.cpp b/applet.cpp index e4443c6d6..133a4faaf 100644 --- a/applet.cpp +++ b/applet.cpp @@ -324,12 +324,6 @@ void Applet::restore(KConfigGroup &group) */ } -void AppletPrivate::setFocus() -{ - //kDebug() << "setting focus"; - q->setFocus(Qt::ShortcutFocusReason); -} - void Applet::setFailedToLaunch(bool failed, const QString &reason) { d->failed = failed; @@ -395,71 +389,7 @@ bool Applet::destroyed() const return d->transient; } -void AppletPrivate::selectItemToDestroy() -{ - //FIXME: this will not work nicely with multiple screens and being zoomed out! - if (isContainment) { - QGraphicsView *view = q->view(); - if (view && view->transform().isScaling() && - q->scene()->focusItem() != q) { - QGraphicsItem *focus = q->scene()->focusItem(); - if (focus) { - Containment *toDestroy = dynamic_cast(focus->topLevelItem()); - - if (toDestroy) { - toDestroy->destroy(); - return; - } - } - } - } - - q->destroy(); -} - -void AppletPrivate::updateRect(const QRectF &rect) -{ - q->update(rect); -} - -void AppletPrivate::cleanUpAndDelete() -{ - //kDebug() << "???????????????? DESTROYING APPLET" << q->name() << q->scene() << " ???????????????????????????"; - QGraphicsWidget *parent = dynamic_cast(q->parentItem()); - //it probably won't matter, but right now if there are applethandles, *they* are the parent. - //not the containment. - - //is the applet in a containment and does the containment have a layout? - //if yes, we remove the applet in the layout - if (parent && parent->layout()) { - QGraphicsLayout *l = parent->layout(); - for (int i = 0; i < l->count(); ++i) { - if (q == l->itemAt(i)) { - l->removeAt(i); - break; - } - } - } - - if (configLoader) { - configLoader->setDefaults(); - } - - resetConfigurationObject(); - - if (q->scene()) { - if (isContainment) { - // prematurely emit our destruction if we are a Containment, - // giving Corona a chance to remove this Containment from its collection - emit q->QObject::destroyed(q); - } - - q->scene()->removeItem(q); - } - - q->deleteLater(); -} ConfigLoader *Applet::configScheme() const { @@ -1154,56 +1084,6 @@ void Applet::setGlobalShortcut(const KShortcut &shortcut) d->globalShortcutChanged(); } -void AppletPrivate::showConfigurationRequiredMessage(bool show, const QString &reason) -{ - // reimplemented in the UI specific library - Q_UNUSED(show) - Q_UNUSED(reason) -} - -void AppletPrivate::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons) -{ - // reimplemented in the UI specific library - Q_UNUSED(icon) - Q_UNUSED(message) - Q_UNUSED(buttons) -} - -void AppletPrivate::positionMessageOverlay() -{ - // reimplemented in the UI specific library -} - -void AppletPrivate::setBusy(bool busy) -{ - // reimplemented in the UI specific library - Q_UNUSED(busy) -} - -bool AppletPrivate::isBusy() const -{ - // reimplemented in the UI specific library - return false; -} - -void AppletPrivate::updateFailedToLaunch(const QString &reason) -{ - // reimplemented in the UI specific library - Q_UNUSED(reason) -} - -void AppletPrivate::globalShortcutChanged() -{ - if (!activationAction) { - return; - } - - KConfigGroup shortcutConfig(mainConfigGroup(), "Shortcuts"); - shortcutConfig.writeEntry("global", activationAction->globalShortcut().toString()); - scheduleModificationNotification(); - //kDebug() << "after" << shortcut.primary() << d->activationAction->globalShortcut().primary(); -} - KShortcut Applet::globalShortcut() const { if (d->activationAction) { @@ -1339,37 +1219,6 @@ void Applet::setHasConfigurationInterface(bool hasInterface) d->hasConfigurationInterface = hasInterface; } -KActionCollection* AppletPrivate::defaultActions(QObject *parent) -{ - KActionCollection *actions = new KActionCollection(parent); - actions->setConfigGroup("Shortcuts-Applet"); - - KAction *configAction = actions->addAction("configure"); - configAction->setAutoRepeat(false); - configAction->setText(i18n("Widget Settings")); - configAction->setIcon(KIcon("configure")); - configAction->setShortcut(KShortcut("alt+d, s")); - configAction->setData(AbstractToolBox::ConfigureTool); - - KAction *closeApplet = actions->addAction("remove"); - closeApplet->setAutoRepeat(false); - closeApplet->setText(i18n("Remove this Widget")); - closeApplet->setIcon(KIcon("edit-delete")); - closeApplet->setShortcut(KShortcut("alt+d, r")); - closeApplet->setData(AbstractToolBox::DestructiveTool); - - KAction *runAssociatedApplication = actions->addAction("run associated application"); - runAssociatedApplication->setAutoRepeat(false); - runAssociatedApplication->setText(i18n("Run the Associated Application")); - runAssociatedApplication->setIcon(KIcon("system-run")); - runAssociatedApplication->setShortcut(KShortcut("alt+d, t")); - runAssociatedApplication->setVisible(false); - runAssociatedApplication->setEnabled(false); - runAssociatedApplication->setData(AbstractToolBox::ControlTool); - - return actions; -} - bool Applet::sceneEventFilter(QGraphicsItem *watched, QEvent *event) { if (watched == this) { @@ -1575,212 +1424,6 @@ void Applet::showConfigurationInterface(QWidget *widget) QMetaObject::invokeMethod(containment()->corona()->dialogManager(), "showDialog", Q_ARG(QWidget *, widget), Q_ARG(Plasma::Applet *, this)); } -QString AppletPrivate::configDialogId() const -{ - return QString("%1settings%2").arg(appletId).arg(q->name()); -} - -QString AppletPrivate::configWindowTitle() const -{ - return i18nc("@title:window", "%1 Settings", q->name()); -} - -QSet AppletPrivate::knownCategories() -{ - // this is to trick the tranlsation tools into making the correct - // strings for translation - QSet categories = s_customCategories; - categories << QString(I18N_NOOP("Accessibility")).toLower() - << QString(I18N_NOOP("Application Launchers")).toLower() - << QString(I18N_NOOP("Astronomy")).toLower() - << QString(I18N_NOOP("Date and Time")).toLower() - << QString(I18N_NOOP("Development Tools")).toLower() - << QString(I18N_NOOP("Education")).toLower() - << QString(I18N_NOOP("Environment and Weather")).toLower() - << QString(I18N_NOOP("Examples")).toLower() - << QString(I18N_NOOP("File System")).toLower() - << QString(I18N_NOOP("Fun and Games")).toLower() - << QString(I18N_NOOP("Graphics")).toLower() - << QString(I18N_NOOP("Language")).toLower() - << QString(I18N_NOOP("Mapping")).toLower() - << QString(I18N_NOOP("Miscellaneous")).toLower() - << QString(I18N_NOOP("Multimedia")).toLower() - << QString(I18N_NOOP("Online Services")).toLower() - << QString(I18N_NOOP("Productivity")).toLower() - << QString(I18N_NOOP("System Information")).toLower() - << QString(I18N_NOOP("Utilities")).toLower() - << QString(I18N_NOOP("Windows and Tasks")).toLower(); - return categories; -} - -KConfigDialog *AppletPrivate::generateGenericConfigDialog() -{ - KConfigSkeleton *nullManager = new KConfigSkeleton(0); - KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager); - nullManager->setParent(dialog); - dialog->setFaceType(KPageDialog::Auto); - dialog->setWindowTitle(configWindowTitle()); - dialog->setAttribute(Qt::WA_DeleteOnClose, true); - q->createConfigurationInterface(dialog); - dialog->showButton(KDialog::Default, false); - dialog->showButton(KDialog::Help, false); - QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished())); - QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished())); - return dialog; -} - -void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog) -{ - addGlobalShortcutsPage(dialog); - addPublishPage(dialog); -} - -void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog) -{ -#ifndef PLASMA_NO_GLOBAL_SHORTCUTS - if (isContainment) { - return; - } - - QWidget *page = new QWidget; - QVBoxLayout *layout = new QVBoxLayout(page); - - if (!shortcutEditor) { - shortcutEditor = new KKeySequenceWidget(page); - QObject::connect(shortcutEditor.data(), SIGNAL(keySequenceChanged(QKeySequence)), dialog, SLOT(settingsModified())); - } - - shortcutEditor.data()->setKeySequence(q->globalShortcut().primary()); - layout->addWidget(shortcutEditor.data()); - layout->addStretch(); - dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard"); - - QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection); - QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection); -#endif -} - -void AppletPrivate::addPublishPage(KConfigDialog *dialog) -{ -#ifdef ENABLE_REMOTE_WIDGETS - QWidget *page = new QWidget; - publishUI.setupUi(page); - publishUI.publishCheckbox->setChecked(q->isPublished()); - QObject::connect(publishUI.publishCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified())); - publishUI.allUsersCheckbox->setEnabled(q->isPublished()); - QObject::connect(publishUI.allUsersCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified())); - - QString resourceName = - i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on", - "%1 on %2", q->name(), QHostInfo::localHostName()); - if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) { - publishUI.allUsersCheckbox->setChecked(true); - } else { - publishUI.allUsersCheckbox->setChecked(false); - } - - q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)), - q, SLOT(publishCheckboxStateChanged(int))); - dialog->addPage(page, i18n("Share"), "applications-internet"); -#endif -} - -void AppletPrivate::publishCheckboxStateChanged(int state) -{ - if (state == Qt::Checked) { - publishUI.allUsersCheckbox->setEnabled(true); - } else { - publishUI.allUsersCheckbox->setEnabled(false); - } -} - -void AppletPrivate::configDialogFinished() -{ - if (shortcutEditor) { - QKeySequence sequence = shortcutEditor.data()->keySequence(); - if (sequence != q->globalShortcut().primary()) { - q->setGlobalShortcut(KShortcut(sequence)); - emit q->configNeedsSaving(); - } - } - -#ifdef ENABLE_REMOTE_WIDGETS - if (KConfigDialog::exists(configDialogId()) && publishUI.publishCheckbox) { - q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked()); - - if (publishUI.publishCheckbox->isChecked()) { - QString resourceName = - i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on", - "%1 on %2", q->name(), QHostInfo::localHostName()); - q->publish(Plasma::ZeroconfAnnouncement, resourceName); - if (publishUI.allUsersCheckbox->isChecked()) { - if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) { - AuthorizationRule *rule = new AuthorizationRule(resourceName, ""); - rule->setPolicy(AuthorizationRule::Allow); - rule->setTargets(AuthorizationRule::AllUsers); - AuthorizationManager::self()->d->rules.append(rule); - } - } else { - AuthorizationRule *matchingRule = - AuthorizationManager::self()->d->matchingRule(resourceName, Credentials()); - if (matchingRule) { - AuthorizationManager::self()->d->rules.removeAll(matchingRule); - } - } - } else { - q->unpublish(); - } - } -#endif - - if (!configLoader) { - // the config loader will trigger this for us, so we don't need to. - propagateConfigChanged(); - if (KConfigDialog *dialog = qobject_cast(q->sender())) { - dialog->enableButton(KDialog::Apply, false); - } - } -} - -void AppletPrivate::updateShortcuts() -{ - if (isContainment) { - //a horrible hack to avoid clobbering corona settings - //we pull them out, then read, then put them back - QList names; - QList qactions; - names << "add sibling containment" << "configure shortcuts" << "lock widgets"; - foreach (const QString &name, names) { - QAction *a = actions->action(name); - actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method - qactions << a; - } - - actions->readSettings(); - - for (int i = 0; i < names.size(); ++i) { - QAction *a = qactions.at(i); - if (a) { - actions->addAction(names.at(i), a); - } - } - } else { - actions->readSettings(); - } -} - -void AppletPrivate::propagateConfigChanged() -{ - if (isContainment) { - Containment *c = qobject_cast(q); - if (c) { - c->d->configChanged(); - } - } - - q->configChanged(); -} - void Applet::configChanged() { if (d->script) { @@ -1852,49 +1495,6 @@ bool Applet::hasValidAssociatedApplication() const return AssociatedApplicationManager::self()->appletHasValidAssociatedApplication(this); } -void AppletPrivate::filterOffers(QList &offers) -{ - KConfigGroup constraintGroup(KGlobal::config(), "Constraints"); - foreach (const QString &key, constraintGroup.keyList()) { - //kDebug() << "security constraint" << key; - if (constraintGroup.readEntry(key, true)) { - continue; - } - - //ugh. a qlist of ksharedptr - QMutableListIterator it(offers); - while (it.hasNext()) { - KService::Ptr p = it.next(); - QString prop = QString("X-Plasma-Requires-").append(key); - QVariant req = p->property(prop, QVariant::String); - //valid values: Required/Optional/Unused - QString reqValue; - if (req.isValid()) { - reqValue = req.toString(); - } else if (p->property("X-Plasma-API").toString().toLower() == "javascript") { - //TODO: be able to check whether or not a script engine provides "controled" - //bindings; for now we just give a pass to the qscript ones - reqValue = "Unused"; - } - - if (!(reqValue == "Optional" || reqValue == "Unused")) { - //if (reqValue == "Required") { - it.remove(); - } - } - } -} - -QString AppletPrivate::parentAppConstraint(const QString &parentApp) -{ - if (parentApp.isEmpty()) { - return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')") - .arg(KGlobal::mainComponent().aboutData()->appName()); - } - - return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp); -} - KPluginInfo::List Applet::listAppletInfo(const QString &category, const QString &parentApp) { return PluginLoader::self()->listAppletInfo(category, parentApp); @@ -2183,26 +1783,6 @@ void Applet::lower() setZValue(--AppletPrivate::s_minZValue); } -void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate) -{ - if (isContainment == nowIsContainment && !forceUpdate) { - return; - } - - isContainment = nowIsContainment; - //FIXME I do not like this function. - //currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way. - //if someone calls it at some other time it'll cause headaches. :P - - delete mainConfig; - mainConfig = 0; - - Containment *c = q->containment(); - if (c) { - c->d->checkContainmentFurniture(); - } -} - bool Applet::isContainment() const { return d->isContainment; @@ -2210,363 +1790,7 @@ bool Applet::isContainment() const // PRIVATE CLASS IMPLEMENTATION -AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet) - : appletId(uniqueID), - q(applet), - remotingService(0), - preferredBackgroundHints(StandardBackground), - backgroundHints(NoBackground), - aspectRatioMode(Plasma::KeepAspectRatio), - immutability(Mutable), - appletDescription(info ? *info : KPluginInfo(service)), - background(0), - mainConfig(0), - pendingConstraints(NoConstraint), - script(0), - package(0), - configLoader(0), - actions(AppletPrivate::defaultActions(applet)), - activationAction(0), - itemStatus(UnknownStatus), - preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored), - modificationsTimer(0), - hasConfigurationInterface(false), - failed(false), - isContainment(false), - transient(false), - needsConfig(false), - started(false) -{ - if (appletId == 0) { - appletId = ++s_maxAppletId; - } else if (appletId > s_maxAppletId) { - s_maxAppletId = appletId; - } -} -AppletPrivate::~AppletPrivate() -{ - if (activationAction && activationAction->isGlobalShortcutEnabled()) { - //kDebug() << "reseting global action for" << q->name() << activationAction->objectName(); - activationAction->forgetGlobalShortcut(); - } - - delete script; - script = 0; - delete package; - package = 0; - delete configLoader; - configLoader = 0; - delete mainConfig; - mainConfig = 0; - delete modificationsTimer; -} - -void AppletPrivate::init(const QString &packagePath) -{ - // WARNING: do not access config() OR globalConfig() in this method! - // that requires a scene, which is not available at this point - q->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - q->setAcceptsHoverEvents(true); - q->setFlag(QGraphicsItem::ItemIsFocusable, true); - q->setFocusPolicy(Qt::ClickFocus); - // FIXME: adding here because nothing seems to be doing it in QGraphicsView, - // but it doesn't actually work anyways =/ - q->setLayoutDirection(qApp->layoutDirection()); - - //set a default size before any saved settings are read - QSize size(200, 200); - q->setBackgroundHints(DefaultBackground); - q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor? - - QAction *closeApplet = actions->action("remove"); - if (closeApplet) { - closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name())); - } - - QAction *configAction = actions->action("configure"); - if (configAction) { - configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name())); - } - - QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus())); - if (!appletDescription.isValid()) { -#ifndef NDEBUG - kDebug() << "Check your constructor! " - << "You probably want to be passing in a Service::Ptr " - << "or a QVariantList with a valid storageid as arg[0]."; -#endif - q->resize(size); - return; - } - - QVariant s = appletDescription.property("X-Plasma-DefaultSize"); - if (s.isValid()) { - size = s.toSize(); - } - //kDebug() << "size" << size; - q->resize(size); - - QString api = appletDescription.property("X-Plasma-API").toString(); - - // we have a scripted plasmoid - if (api.isEmpty()) { - q->setFailedToLaunch(true, i18n("The %2 widget did not define which ScriptEngine to use.", appletDescription.name())); - return; - } - - - package = new Package(PluginLoader::self()->loadPackage("Plasma/Applet", api)); - - // find where the Package is - QString path = packagePath; - if (path.isEmpty()) { - const QString subPath = package->defaultPackageRoot() + appletDescription.pluginName() + '/'; - path = KStandardDirs::locate("data", subPath + "metadata.desktop"); - if (path.isEmpty()) { - path = KStandardDirs::locate("data", subPath); - } else { - path.remove(QString("metadata.desktop")); - } - } else if (!path.endsWith('/')) { - path.append('/'); - } - - if (path.isEmpty()) { - delete package; - package = 0; - q->setFailedToLaunch(true, - i18nc("Package file, name of the widget", - "Could not locate the %1 package required for the %2 widget.", - appletDescription.pluginName(), appletDescription.name())); - return; - } - - package->setPath(path); - if (!package->isValid()) { - delete package; - package = 0; - q->setFailedToLaunch(true, i18nc("Package file, name of the widget", - "Could not open the %1 package required for the %2 widget.", - appletDescription.pluginName(), appletDescription.name())); - return; - } - - // create the package and see if we have something real - //kDebug() << "trying for" << path; - - // now we try and set up the script engine. - // it will be parented to this applet and so will get - // deleted when the applet does - - script = Plasma::loadScriptEngine(api, q); - if (!script) { - delete package; - package = 0; - q->setFailedToLaunch(true, - i18nc("API or programming language the widget was written in, name of the widget", - "Could not create a %1 ScriptEngine for the %2 widget.", - api, appletDescription.name())); - } -} - -// put all setup routines for script here. at this point we can assume that -// package exists and that we have a script engine -void AppletPrivate::setupScriptSupport() -{ - if (!package) { - return; - } - -#ifndef NDEBUG - kDebug() << "setting up script support, package is in" << package->path() - << ", main script is" << package->filePath("mainscript"); -#endif - - const QString translationsPath = package->filePath("translations"); - if (!translationsPath.isEmpty()) { - KGlobal::dirs()->addResourceDir("locale", translationsPath); - KGlobal::locale()->insertCatalog(appletDescription.pluginName()); - } - - const QString xmlPath = package->filePath("mainconfigxml"); - if (!xmlPath.isEmpty()) { - QFile file(xmlPath); - KConfigGroup config = q->config(); - configLoader = new ConfigLoader(&config, &file); - QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged())); - } - - if (!package->filePath("mainconfigui").isEmpty()) { - q->setHasConfigurationInterface(true); - } -} - -QString AppletPrivate::globalName() const -{ - if (!appletDescription.isValid()) { - return QString(); - } - - return appletDescription.service()->library(); -} - -QString AppletPrivate::instanceName() -{ - if (!appletDescription.isValid()) { - return QString(); - } - - return appletDescription.service()->library() + QString::number(appletId); -} - -void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c) -{ - // Don't start up a timer if we're just starting up - // flushPendingConstraints will be called by Corona - if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) { - constraintsTimer.start(0, q); - } - - if (c & Plasma::StartupCompletedConstraint) { - started = true; - } - - pendingConstraints |= c; -} - -void AppletPrivate::scheduleModificationNotification() -{ - // modificationsTimer is not allocated until we get our notice of being started - if (modificationsTimer) { - // schedule a save - if (modificationsTimer->isActive()) { - modificationsTimer->stop(); - } - - modificationsTimer->start(1000, q); - } -} - -KConfigGroup *AppletPrivate::mainConfigGroup() -{ - if (mainConfig) { - return mainConfig; - } - - bool newGroup = false; - if (isContainment) { - Corona *corona = qobject_cast(q->scene()); - KConfigGroup containmentConfig; - //kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q; - - if (corona) { - containmentConfig = KConfigGroup(corona->config(), "Containments"); - } else { - containmentConfig = KConfigGroup(KGlobal::config(), "Containments"); - } - - if (package && !containmentConfig.hasGroup(QString::number(appletId))) { - newGroup = true; - } - - mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId)); - } else { - KConfigGroup appletConfig; - - Containment *c = q->containment(); - Applet *parentApplet = qobject_cast(q->parent()); - if (parentApplet && parentApplet != static_cast(c)) { - // this applet is nested inside another applet! use it's config - // as the parent group in the config - appletConfig = parentApplet->config(); - appletConfig = KConfigGroup(&appletConfig, "Applets"); - } else if (c) { - // applet directly in a Containment, as usual - appletConfig = c->config(); - appletConfig = KConfigGroup(&appletConfig, "Applets"); - } else { - kWarning() << "requesting config for" << q->name() << "without a containment!"; - appletConfig = KConfigGroup(KGlobal::config(), "Applets"); - } - - if (package && !appletConfig.hasGroup(QString::number(appletId))) { - newGroup = true; - } - - mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId)); - } - - if (newGroup) { - //see if we have a default configuration in our package - const QString defaultConfigFile = package->filePath("defaultconfig"); - if (!defaultConfigFile.isEmpty()) { -#ifndef NDEBUG - kDebug() << "copying default config: " << package->filePath("defaultconfig"); -#endif - KConfigGroup defaultConfig(KSharedConfig::openConfig(defaultConfigFile)->group("Configuration")); - defaultConfig.copyTo(mainConfig); - } - } - - return mainConfig; -} - -QString AppletPrivate::visibleFailureText(const QString &reason) -{ - QString text; - - if (reason.isEmpty()) { - text = i18n("This object could not be created."); - } else { - text = i18n("This object could not be created for the following reason:

%1

", reason); - } - - return text; -} - -void AppletPrivate::themeChanged() -{ - if (background) { - //do again the translucent background fallback - q->setBackgroundHints(backgroundHints); - - qreal left; - qreal right; - qreal top; - qreal bottom; - background->getMargins(left, top, right, bottom); - q->setContentsMargins(left, right, top, bottom); - } - q->update(); -} - -void AppletPrivate::resetConfigurationObject() -{ - // make sure mainConfigGroup exists in all cases - mainConfigGroup(); - - mainConfig->deleteGroup(); - delete mainConfig; - mainConfig = 0; - - Corona * corona = qobject_cast(q->scene()); - if (corona) { - corona->requireConfigSync(); - } -} - -void AppletPrivate::handleDisappeared(AppletHandle *h) -{ - if (h == handle.data()) { - h->detachApplet(); - QGraphicsScene *scene = q->scene(); - if (scene && h->scene() == scene) { - scene->removeItem(h); - } - h->deleteLater(); - } -} void ContainmentPrivate::checkRemoveAction() { @@ -2574,11 +1798,6 @@ void ContainmentPrivate::checkRemoveAction() } -uint AppletPrivate::s_maxAppletId = 0; -int AppletPrivate::s_maxZValue = 0; -int AppletPrivate::s_minZValue = 0; -QSet AppletPrivate::s_customCategories; - } // Plasma namespace #include "moc_applet.cpp" diff --git a/private/appletprivate.cpp b/private/appletprivate.cpp new file mode 100644 index 000000000..ae4e6f2a4 --- /dev/null +++ b/private/appletprivate.cpp @@ -0,0 +1,830 @@ +/* + * Copyright 2005 by Aaron Seigo + * Copyright 2007 by Riccardo Iaconelli + * Copyright 2008 by Ménard Alexis + * Copyright (c) 2009 Chani Armitage + * Copyright 2012 by Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "private/applet_p.h" + +#include +#include + +#include "abstracttoolbox.h" +#include "containment.h" +#include "corona.h" +#include "pluginloader.h" +#include "scripting/scriptengine.h" + +#include "private/containment_p.h" + +#include +#include +#include +#include + +namespace Plasma +{ + +AppletPrivate::AppletPrivate(KService::Ptr service, const KPluginInfo *info, int uniqueID, Applet *applet) + : appletId(uniqueID), + q(applet), + remotingService(0), + preferredBackgroundHints(StandardBackground), + backgroundHints(NoBackground), + aspectRatioMode(Plasma::KeepAspectRatio), + immutability(Mutable), + appletDescription(info ? *info : KPluginInfo(service)), + background(0), + mainConfig(0), + pendingConstraints(NoConstraint), + script(0), + package(0), + configLoader(0), + actions(AppletPrivate::defaultActions(applet)), + activationAction(0), + itemStatus(UnknownStatus), + preferredSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored), + modificationsTimer(0), + hasConfigurationInterface(false), + failed(false), + isContainment(false), + transient(false), + needsConfig(false), + started(false) +{ + if (appletId == 0) { + appletId = ++s_maxAppletId; + } else if (appletId > s_maxAppletId) { + s_maxAppletId = appletId; + } +} + +AppletPrivate::~AppletPrivate() +{ + if (activationAction && activationAction->isGlobalShortcutEnabled()) { + //kDebug() << "reseting global action for" << q->name() << activationAction->objectName(); + activationAction->forgetGlobalShortcut(); + } + + delete script; + script = 0; + delete package; + package = 0; + delete configLoader; + configLoader = 0; + delete mainConfig; + mainConfig = 0; + delete modificationsTimer; +} + +void AppletPrivate::init(const QString &packagePath) +{ + // WARNING: do not access config() OR globalConfig() in this method! + // that requires a scene, which is not available at this point + q->setCacheMode(QGraphicsItem::DeviceCoordinateCache); + q->setAcceptsHoverEvents(true); + q->setFlag(QGraphicsItem::ItemIsFocusable, true); + q->setFocusPolicy(Qt::ClickFocus); + // FIXME: adding here because nothing seems to be doing it in QGraphicsView, + // but it doesn't actually work anyways =/ + q->setLayoutDirection(qApp->layoutDirection()); + + //set a default size before any saved settings are read + QSize size(200, 200); + q->setBackgroundHints(DefaultBackground); + q->setHasConfigurationInterface(true); //FIXME why not default it to true in the constructor? + + QAction *closeApplet = actions->action("remove"); + if (closeApplet) { + closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", q->name())); + } + + QAction *configAction = actions->action("configure"); + if (configAction) { + configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", q->name())); + } + + QObject::connect(q, SIGNAL(activate()), q, SLOT(setFocus())); + if (!appletDescription.isValid()) { +#ifndef NDEBUG + kDebug() << "Check your constructor! " + << "You probably want to be passing in a Service::Ptr " + << "or a QVariantList with a valid storageid as arg[0]."; +#endif + q->resize(size); + return; + } + + QVariant s = appletDescription.property("X-Plasma-DefaultSize"); + if (s.isValid()) { + size = s.toSize(); + } + //kDebug() << "size" << size; + q->resize(size); + + QString api = appletDescription.property("X-Plasma-API").toString(); + + // we have a scripted plasmoid + if (api.isEmpty()) { + q->setFailedToLaunch(true, i18n("The %2 widget did not define which ScriptEngine to use.", appletDescription.name())); + return; + } + + + package = new Package(PluginLoader::self()->loadPackage("Plasma/Applet", api)); + + // find where the Package is + QString path = packagePath; + if (path.isEmpty()) { + const QString subPath = package->defaultPackageRoot() + appletDescription.pluginName() + '/'; + path = KStandardDirs::locate("data", subPath + "metadata.desktop"); + if (path.isEmpty()) { + path = KStandardDirs::locate("data", subPath); + } else { + path.remove(QString("metadata.desktop")); + } + } else if (!path.endsWith('/')) { + path.append('/'); + } + + if (path.isEmpty()) { + delete package; + package = 0; + q->setFailedToLaunch(true, + i18nc("Package file, name of the widget", + "Could not locate the %1 package required for the %2 widget.", + appletDescription.pluginName(), appletDescription.name())); + return; + } + + package->setPath(path); + if (!package->isValid()) { + delete package; + package = 0; + q->setFailedToLaunch(true, i18nc("Package file, name of the widget", + "Could not open the %1 package required for the %2 widget.", + appletDescription.pluginName(), appletDescription.name())); + return; + } + + // create the package and see if we have something real + //kDebug() << "trying for" << path; + + // now we try and set up the script engine. + // it will be parented to this applet and so will get + // deleted when the applet does + + script = Plasma::loadScriptEngine(api, q); + if (!script) { + delete package; + package = 0; + q->setFailedToLaunch(true, + i18nc("API or programming language the widget was written in, name of the widget", + "Could not create a %1 ScriptEngine for the %2 widget.", + api, appletDescription.name())); + } +} + +void AppletPrivate::setFocus() +{ + //kDebug() << "setting focus"; + q->setFocus(Qt::ShortcutFocusReason); +} + +void AppletPrivate::selectItemToDestroy() +{ + //FIXME: this will not work nicely with multiple screens and being zoomed out! + if (isContainment) { + QGraphicsView *view = q->view(); + if (view && view->transform().isScaling() && + q->scene()->focusItem() != q) { + QGraphicsItem *focus = q->scene()->focusItem(); + + if (focus) { + Containment *toDestroy = dynamic_cast(focus->topLevelItem()); + + if (toDestroy) { + toDestroy->destroy(); + return; + } + } + } + } + + q->destroy(); +} + +void AppletPrivate::updateRect(const QRectF &rect) +{ + q->update(rect); +} + +void AppletPrivate::cleanUpAndDelete() +{ + //kDebug() << "???????????????? DESTROYING APPLET" << q->name() << q->scene() << " ???????????????????????????"; + QGraphicsWidget *parent = dynamic_cast(q->parentItem()); + //it probably won't matter, but right now if there are applethandles, *they* are the parent. + //not the containment. + + //is the applet in a containment and does the containment have a layout? + //if yes, we remove the applet in the layout + if (parent && parent->layout()) { + QGraphicsLayout *l = parent->layout(); + for (int i = 0; i < l->count(); ++i) { + if (q == l->itemAt(i)) { + l->removeAt(i); + break; + } + } + } + + if (configLoader) { + configLoader->setDefaults(); + } + + resetConfigurationObject(); + + if (q->scene()) { + if (isContainment) { + // prematurely emit our destruction if we are a Containment, + // giving Corona a chance to remove this Containment from its collection + emit q->QObject::destroyed(q); + } + + q->scene()->removeItem(q); + } + + q->deleteLater(); +} + +void AppletPrivate::showConfigurationRequiredMessage(bool show, const QString &reason) +{ + // reimplemented in the UI specific library + Q_UNUSED(show) + Q_UNUSED(reason) +} + +void AppletPrivate::showMessage(const QIcon &icon, const QString &message, const MessageButtons buttons) +{ + // reimplemented in the UI specific library + Q_UNUSED(icon) + Q_UNUSED(message) + Q_UNUSED(buttons) +} + +void AppletPrivate::positionMessageOverlay() +{ + // reimplemented in the UI specific library +} + +void AppletPrivate::setBusy(bool busy) +{ + // reimplemented in the UI specific library + Q_UNUSED(busy) +} + +bool AppletPrivate::isBusy() const +{ + // reimplemented in the UI specific library + return false; +} + +void AppletPrivate::updateFailedToLaunch(const QString &reason) +{ + // reimplemented in the UI specific library + Q_UNUSED(reason) +} + +void AppletPrivate::globalShortcutChanged() +{ + if (!activationAction) { + return; + } + + KConfigGroup shortcutConfig(mainConfigGroup(), "Shortcuts"); + shortcutConfig.writeEntry("global", activationAction->globalShortcut().toString()); + scheduleModificationNotification(); + //kDebug() << "after" << shortcut.primary() << d->activationAction->globalShortcut().primary(); +} + +KActionCollection* AppletPrivate::defaultActions(QObject *parent) +{ + KActionCollection *actions = new KActionCollection(parent); + actions->setConfigGroup("Shortcuts-Applet"); + + KAction *configAction = actions->addAction("configure"); + configAction->setAutoRepeat(false); + configAction->setText(i18n("Widget Settings")); + configAction->setIcon(KIcon("configure")); + configAction->setShortcut(KShortcut("alt+d, s")); + configAction->setData(AbstractToolBox::ConfigureTool); + + KAction *closeApplet = actions->addAction("remove"); + closeApplet->setAutoRepeat(false); + closeApplet->setText(i18n("Remove this Widget")); + closeApplet->setIcon(KIcon("edit-delete")); + closeApplet->setShortcut(KShortcut("alt+d, r")); + closeApplet->setData(AbstractToolBox::DestructiveTool); + + KAction *runAssociatedApplication = actions->addAction("run associated application"); + runAssociatedApplication->setAutoRepeat(false); + runAssociatedApplication->setText(i18n("Run the Associated Application")); + runAssociatedApplication->setIcon(KIcon("system-run")); + runAssociatedApplication->setShortcut(KShortcut("alt+d, t")); + runAssociatedApplication->setVisible(false); + runAssociatedApplication->setEnabled(false); + runAssociatedApplication->setData(AbstractToolBox::ControlTool); + + return actions; +} + +QString AppletPrivate::configDialogId() const +{ + return QString("%1settings%2").arg(appletId).arg(q->name()); +} + +QString AppletPrivate::configWindowTitle() const +{ + return i18nc("@title:window", "%1 Settings", q->name()); +} + +QSet AppletPrivate::knownCategories() +{ + // this is to trick the tranlsation tools into making the correct + // strings for translation + QSet categories = s_customCategories; + categories << QString(I18N_NOOP("Accessibility")).toLower() + << QString(I18N_NOOP("Application Launchers")).toLower() + << QString(I18N_NOOP("Astronomy")).toLower() + << QString(I18N_NOOP("Date and Time")).toLower() + << QString(I18N_NOOP("Development Tools")).toLower() + << QString(I18N_NOOP("Education")).toLower() + << QString(I18N_NOOP("Environment and Weather")).toLower() + << QString(I18N_NOOP("Examples")).toLower() + << QString(I18N_NOOP("File System")).toLower() + << QString(I18N_NOOP("Fun and Games")).toLower() + << QString(I18N_NOOP("Graphics")).toLower() + << QString(I18N_NOOP("Language")).toLower() + << QString(I18N_NOOP("Mapping")).toLower() + << QString(I18N_NOOP("Miscellaneous")).toLower() + << QString(I18N_NOOP("Multimedia")).toLower() + << QString(I18N_NOOP("Online Services")).toLower() + << QString(I18N_NOOP("Productivity")).toLower() + << QString(I18N_NOOP("System Information")).toLower() + << QString(I18N_NOOP("Utilities")).toLower() + << QString(I18N_NOOP("Windows and Tasks")).toLower(); + return categories; +} + +KConfigDialog *AppletPrivate::generateGenericConfigDialog() +{ + KConfigSkeleton *nullManager = new KConfigSkeleton(0); + KConfigDialog *dialog = new AppletConfigDialog(0, configDialogId(), nullManager); + nullManager->setParent(dialog); + dialog->setFaceType(KPageDialog::Auto); + dialog->setWindowTitle(configWindowTitle()); + dialog->setAttribute(Qt::WA_DeleteOnClose, true); + q->createConfigurationInterface(dialog); + dialog->showButton(KDialog::Default, false); + dialog->showButton(KDialog::Help, false); + QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished())); + QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished())); + return dialog; +} + +void AppletPrivate::addStandardConfigurationPages(KConfigDialog *dialog) +{ + addGlobalShortcutsPage(dialog); + addPublishPage(dialog); +} + +void AppletPrivate::addGlobalShortcutsPage(KConfigDialog *dialog) +{ +#ifndef PLASMA_NO_GLOBAL_SHORTCUTS + if (isContainment) { + return; + } + + QWidget *page = new QWidget; + QVBoxLayout *layout = new QVBoxLayout(page); + + if (!shortcutEditor) { + shortcutEditor = new KKeySequenceWidget(page); + QObject::connect(shortcutEditor.data(), SIGNAL(keySequenceChanged(QKeySequence)), dialog, SLOT(settingsModified())); + } + + shortcutEditor.data()->setKeySequence(q->globalShortcut().primary()); + layout->addWidget(shortcutEditor.data()); + layout->addStretch(); + dialog->addPage(page, i18n("Keyboard Shortcut"), "preferences-desktop-keyboard"); + + QObject::connect(dialog, SIGNAL(applyClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection); + QObject::connect(dialog, SIGNAL(okClicked()), q, SLOT(configDialogFinished()), Qt::UniqueConnection); +#endif +} + +void AppletPrivate::addPublishPage(KConfigDialog *dialog) +{ +#ifdef ENABLE_REMOTE_WIDGETS + QWidget *page = new QWidget; + publishUI.setupUi(page); + publishUI.publishCheckbox->setChecked(q->isPublished()); + QObject::connect(publishUI.publishCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified())); + publishUI.allUsersCheckbox->setEnabled(q->isPublished()); + QObject::connect(publishUI.allUsersCheckbox, SIGNAL(clicked(bool)), dialog, SLOT(settingsModified())); + + QString resourceName = + i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on", + "%1 on %2", q->name(), QHostInfo::localHostName()); + if (AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) { + publishUI.allUsersCheckbox->setChecked(true); + } else { + publishUI.allUsersCheckbox->setChecked(false); + } + + q->connect(publishUI.publishCheckbox, SIGNAL(stateChanged(int)), + q, SLOT(publishCheckboxStateChanged(int))); + dialog->addPage(page, i18n("Share"), "applications-internet"); +#endif +} + +void AppletPrivate::publishCheckboxStateChanged(int state) +{ + if (state == Qt::Checked) { + publishUI.allUsersCheckbox->setEnabled(true); + } else { + publishUI.allUsersCheckbox->setEnabled(false); + } +} + +void AppletPrivate::configDialogFinished() +{ + if (shortcutEditor) { + QKeySequence sequence = shortcutEditor.data()->keySequence(); + if (sequence != q->globalShortcut().primary()) { + q->setGlobalShortcut(KShortcut(sequence)); + emit q->configNeedsSaving(); + } + } + +#ifdef ENABLE_REMOTE_WIDGETS + if (KConfigDialog::exists(configDialogId()) && publishUI.publishCheckbox) { + q->config().writeEntry("Share", publishUI.publishCheckbox->isChecked()); + + if (publishUI.publishCheckbox->isChecked()) { + QString resourceName = + i18nc("%1 is the name of a plasmoid, %2 the name of the machine that plasmoid is published on", + "%1 on %2", q->name(), QHostInfo::localHostName()); + q->publish(Plasma::ZeroconfAnnouncement, resourceName); + if (publishUI.allUsersCheckbox->isChecked()) { + if (!AuthorizationManager::self()->d->matchingRule(resourceName, Credentials())) { + AuthorizationRule *rule = new AuthorizationRule(resourceName, ""); + rule->setPolicy(AuthorizationRule::Allow); + rule->setTargets(AuthorizationRule::AllUsers); + AuthorizationManager::self()->d->rules.append(rule); + } + } else { + AuthorizationRule *matchingRule = + AuthorizationManager::self()->d->matchingRule(resourceName, Credentials()); + if (matchingRule) { + AuthorizationManager::self()->d->rules.removeAll(matchingRule); + } + } + } else { + q->unpublish(); + } + } +#endif + + if (!configLoader) { + // the config loader will trigger this for us, so we don't need to. + propagateConfigChanged(); + if (KConfigDialog *dialog = qobject_cast(q->sender())) { + dialog->enableButton(KDialog::Apply, false); + } + } +} + +void AppletPrivate::updateShortcuts() +{ + if (isContainment) { + //a horrible hack to avoid clobbering corona settings + //we pull them out, then read, then put them back + QList names; + QList qactions; + names << "add sibling containment" << "configure shortcuts" << "lock widgets"; + foreach (const QString &name, names) { + QAction *a = actions->action(name); + actions->takeAction(a); //FIXME this is stupid, KActionCollection needs a takeAction(QString) method + qactions << a; + } + + actions->readSettings(); + + for (int i = 0; i < names.size(); ++i) { + QAction *a = qactions.at(i); + if (a) { + actions->addAction(names.at(i), a); + } + } + } else { + actions->readSettings(); + } +} + +void AppletPrivate::propagateConfigChanged() +{ + if (isContainment) { + Containment *c = qobject_cast(q); + if (c) { + c->d->configChanged(); + } + } + + q->configChanged(); +} + +void AppletPrivate::filterOffers(QList &offers) +{ + KConfigGroup constraintGroup(KGlobal::config(), "Constraints"); + foreach (const QString &key, constraintGroup.keyList()) { + //kDebug() << "security constraint" << key; + if (constraintGroup.readEntry(key, true)) { + continue; + } + + //ugh. a qlist of ksharedptr + QMutableListIterator it(offers); + while (it.hasNext()) { + KService::Ptr p = it.next(); + QString prop = QString("X-Plasma-Requires-").append(key); + QVariant req = p->property(prop, QVariant::String); + //valid values: Required/Optional/Unused + QString reqValue; + if (req.isValid()) { + reqValue = req.toString(); + } else if (p->property("X-Plasma-API").toString().toLower() == "javascript") { + //TODO: be able to check whether or not a script engine provides "controled" + //bindings; for now we just give a pass to the qscript ones + reqValue = "Unused"; + } + + if (!(reqValue == "Optional" || reqValue == "Unused")) { + //if (reqValue == "Required") { + it.remove(); + } + } + } +} + +QString AppletPrivate::parentAppConstraint(const QString &parentApp) +{ + if (parentApp.isEmpty()) { + return QString("((not exist [X-KDE-ParentApp] or [X-KDE-ParentApp] == '') or [X-KDE-ParentApp] == '%1')") + .arg(KGlobal::mainComponent().aboutData()->appName()); + } + + return QString("[X-KDE-ParentApp] == '%1'").arg(parentApp); +} + +void AppletPrivate::setIsContainment(bool nowIsContainment, bool forceUpdate) +{ + if (isContainment == nowIsContainment && !forceUpdate) { + return; + } + + isContainment = nowIsContainment; + //FIXME I do not like this function. + //currently it's only called before ctmt/applet init, with (true,true), and I'm going to assume it stays that way. + //if someone calls it at some other time it'll cause headaches. :P + + delete mainConfig; + mainConfig = 0; + + Containment *c = q->containment(); + if (c) { + c->d->checkContainmentFurniture(); + } +} + +// put all setup routines for script here. at this point we can assume that +// package exists and that we have a script engine +void AppletPrivate::setupScriptSupport() +{ + if (!package) { + return; + } + +#ifndef NDEBUG + kDebug() << "setting up script support, package is in" << package->path() + << ", main script is" << package->filePath("mainscript"); +#endif + + const QString translationsPath = package->filePath("translations"); + if (!translationsPath.isEmpty()) { + KGlobal::dirs()->addResourceDir("locale", translationsPath); + KGlobal::locale()->insertCatalog(appletDescription.pluginName()); + } + + const QString xmlPath = package->filePath("mainconfigxml"); + if (!xmlPath.isEmpty()) { + QFile file(xmlPath); + KConfigGroup config = q->config(); + configLoader = new ConfigLoader(&config, &file); + QObject::connect(configLoader, SIGNAL(configChanged()), q, SLOT(propagateConfigChanged())); + } + + if (!package->filePath("mainconfigui").isEmpty()) { + q->setHasConfigurationInterface(true); + } +} + +QString AppletPrivate::globalName() const +{ + if (!appletDescription.isValid()) { + return QString(); + } + + return appletDescription.service()->library(); +} + +QString AppletPrivate::instanceName() +{ + if (!appletDescription.isValid()) { + return QString(); + } + + return appletDescription.service()->library() + QString::number(appletId); +} + +void AppletPrivate::scheduleConstraintsUpdate(Plasma::Constraints c) +{ + // Don't start up a timer if we're just starting up + // flushPendingConstraints will be called by Corona + if (started && !constraintsTimer.isActive() && !(c & Plasma::StartupCompletedConstraint)) { + constraintsTimer.start(0, q); + } + + if (c & Plasma::StartupCompletedConstraint) { + started = true; + } + + pendingConstraints |= c; +} + +void AppletPrivate::scheduleModificationNotification() +{ + // modificationsTimer is not allocated until we get our notice of being started + if (modificationsTimer) { + // schedule a save + if (modificationsTimer->isActive()) { + modificationsTimer->stop(); + } + + modificationsTimer->start(1000, q); + } +} + +KConfigGroup *AppletPrivate::mainConfigGroup() +{ + if (mainConfig) { + return mainConfig; + } + + bool newGroup = false; + if (isContainment) { + Corona *corona = qobject_cast(q->scene()); + KConfigGroup containmentConfig; + //kDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q; + + if (corona) { + containmentConfig = KConfigGroup(corona->config(), "Containments"); + } else { + containmentConfig = KConfigGroup(KGlobal::config(), "Containments"); + } + + if (package && !containmentConfig.hasGroup(QString::number(appletId))) { + newGroup = true; + } + + mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId)); + } else { + KConfigGroup appletConfig; + + Containment *c = q->containment(); + Applet *parentApplet = qobject_cast(q->parent()); + if (parentApplet && parentApplet != static_cast(c)) { + // this applet is nested inside another applet! use it's config + // as the parent group in the config + appletConfig = parentApplet->config(); + appletConfig = KConfigGroup(&appletConfig, "Applets"); + } else if (c) { + // applet directly in a Containment, as usual + appletConfig = c->config(); + appletConfig = KConfigGroup(&appletConfig, "Applets"); + } else { + kWarning() << "requesting config for" << q->name() << "without a containment!"; + appletConfig = KConfigGroup(KGlobal::config(), "Applets"); + } + + if (package && !appletConfig.hasGroup(QString::number(appletId))) { + newGroup = true; + } + + mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId)); + } + + if (newGroup) { + //see if we have a default configuration in our package + const QString defaultConfigFile = package->filePath("defaultconfig"); + if (!defaultConfigFile.isEmpty()) { +#ifndef NDEBUG + kDebug() << "copying default config: " << package->filePath("defaultconfig"); +#endif + KConfigGroup defaultConfig(KSharedConfig::openConfig(defaultConfigFile)->group("Configuration")); + defaultConfig.copyTo(mainConfig); + } + } + + return mainConfig; +} + +QString AppletPrivate::visibleFailureText(const QString &reason) +{ + QString text; + + if (reason.isEmpty()) { + text = i18n("This object could not be created."); + } else { + text = i18n("This object could not be created for the following reason:

%1

", reason); + } + + return text; +} + +void AppletPrivate::themeChanged() +{ + if (background) { + //do again the translucent background fallback + q->setBackgroundHints(backgroundHints); + + qreal left; + qreal right; + qreal top; + qreal bottom; + background->getMargins(left, top, right, bottom); + q->setContentsMargins(left, right, top, bottom); + } + q->update(); +} + +void AppletPrivate::resetConfigurationObject() +{ + // make sure mainConfigGroup exists in all cases + mainConfigGroup(); + + mainConfig->deleteGroup(); + delete mainConfig; + mainConfig = 0; + + Corona * corona = qobject_cast(q->scene()); + if (corona) { + corona->requireConfigSync(); + } +} + +void AppletPrivate::handleDisappeared(AppletHandle *h) +{ + if (h == handle.data()) { + h->detachApplet(); + QGraphicsScene *scene = q->scene(); + if (scene && h->scene() == scene) { + scene->removeItem(h); + } + h->deleteLater(); + } +} + +uint AppletPrivate::s_maxAppletId = 0; +int AppletPrivate::s_maxZValue = 0; +int AppletPrivate::s_minZValue = 0; +QSet AppletPrivate::s_customCategories; + +} //namespace Plasma