From 9d452dc2ea7aaf091c9317967b88f45a7ca2a025 Mon Sep 17 00:00:00 2001 From: Chani Armitage Date: Mon, 17 Aug 2009 22:30:29 +0000 Subject: [PATCH] a basic plugin skeleton this is based off the wallpaper plugin. lots of copy&paste happened. the dataengine code is still in there, just in case some plugin wants it someday... svn path=/trunk/KDE/kdelibs/; revision=1012635 --- CMakeLists.txt | 3 + contextaction.cpp | 213 ++++++++++++++++++ contextaction.h | 259 ++++++++++++++++++++++ private/contextaction_p.h | 52 +++++ private/packages.cpp | 6 + private/packages_p.h | 10 +- servicetypes/plasma-contextaction.desktop | 6 + 7 files changed, 547 insertions(+), 2 deletions(-) create mode 100644 contextaction.cpp create mode 100644 contextaction.h create mode 100644 private/contextaction_p.h create mode 100644 servicetypes/plasma-contextaction.desktop diff --git a/CMakeLists.txt b/CMakeLists.txt index cbed57f29..d9bc10f81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ set(plasma_LIB_SRCS configloader.cpp containment.cpp context.cpp + contextaction.cpp corona.cpp datacontainer.cpp dataengine.cpp @@ -202,6 +203,7 @@ set(plasma_LIB_INCLUDES configloader.h containment.h context.h + contextaction.h corona.h datacontainer.h dataengine.h @@ -287,6 +289,7 @@ install(FILES servicetypes/plasma-applet.desktop servicetypes/plasma-applet-popupapplet.desktop servicetypes/plasma-containment.desktop + servicetypes/plasma-contextaction.desktop servicetypes/plasma-dataengine.desktop servicetypes/plasma-packagestructure.desktop servicetypes/plasma-runner.desktop diff --git a/contextaction.cpp b/contextaction.cpp new file mode 100644 index 000000000..abad81cdc --- /dev/null +++ b/contextaction.cpp @@ -0,0 +1,213 @@ +/* + * Copyright 2008 by Aaron Seigo + * Copyright 2008 by Petri Damsten + * + * 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 "contextaction.h" + +#include +#include +#include +#include + +#include + +#include "plasma/private/dataengineconsumer_p.h" +#include "plasma/private/packages_p.h" +#include "plasma/private/contextaction_p.h" + +namespace Plasma +{ + +PackageStructure::Ptr ContextActionPrivate::s_packageStructure(0); + +ContextAction::ContextAction(QObject * parentObject) + : d(new ContextActionPrivate(KService::serviceByStorageId(QString()), this)) +{ + setParent(parentObject); +} + +ContextAction::ContextAction(QObject *parentObject, const QVariantList &args) + : d(new ContextActionPrivate(KService::serviceByStorageId(args.count() > 0 ? + args[0].toString() : QString()), this)) +{ + // now remove first item since those are managed by Wallpaper and subclasses shouldn't + // need to worry about them. yes, it violates the constness of this var, but it lets us add + // or remove items later while applets can just pretend that their args always start at 0 + QVariantList &mutableArgs = const_cast(args); + if (!mutableArgs.isEmpty()) { + mutableArgs.removeFirst(); + } + + setParent(parentObject); +} + +ContextAction::~ContextAction() +{ + delete d; +} + +KPluginInfo::List ContextAction::listContextActionInfo() +{ + QString constraint; + + KService::List offers = KServiceTypeTrader::self()->query("Plasma/ContextAction", constraint); + return KPluginInfo::fromServices(offers); +} + +ContextAction *ContextAction::load(const QString &contextActionName, const QVariantList &args) +{ + if (contextActionName.isEmpty()) { + return 0; + } + + QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(contextActionName); + KService::List offers = KServiceTypeTrader::self()->query("Plasma/ContextAction", constraint); + + if (offers.isEmpty()) { + kDebug() << "offers is empty for " << contextActionName; + return 0; + } + + KService::Ptr offer = offers.first(); + KPluginLoader plugin(*offer); + + if (!Plasma::isPluginVersionCompatible(plugin.pluginVersion())) { + return 0; + } + + QVariantList allArgs; + allArgs << offer->storageId() << args; + QString error; + ContextAction *contextAction = offer->createInstance(0, allArgs, &error); + + if (!contextAction) { + kDebug() << "Couldn't load contextAction \"" << contextActionName << "\"! reason given: " << error; + } + + return contextAction; +} + +ContextAction *ContextAction::load(const KPluginInfo &info, const QVariantList &args) +{ + if (!info.isValid()) { + return 0; + } + return load(info.pluginName(), args); +} + +PackageStructure::Ptr ContextAction::packageStructure() +{ + if (!ContextActionPrivate::s_packageStructure) { + ContextActionPrivate::s_packageStructure = new ContextActionPackage(); + } + + return ContextActionPrivate::s_packageStructure; +} + +QString ContextAction::name() const +{ + if (!d->contextActionDescription.isValid()) { + return i18n("Unknown ContextAction"); + } + + return d->contextActionDescription.name(); +} + +QString ContextAction::icon() const +{ + if (!d->contextActionDescription.isValid()) { + return QString(); + } + + return d->contextActionDescription.icon(); +} + +QString ContextAction::pluginName() const +{ + if (!d->contextActionDescription.isValid()) { + return QString(); + } + + return d->contextActionDescription.pluginName(); +} + +bool ContextAction::isInitialized() const +{ + return d->initialized; +} + +void ContextAction::restore(const KConfigGroup &config) +{ + init(config); + d->initialized = true; +} + +void ContextAction::init(const KConfigGroup &config) +{ + Q_UNUSED(config); +} + +void ContextAction::save(KConfigGroup &config) +{ + Q_UNUSED(config); +} + +QWidget *ContextAction::createConfigurationInterface(QWidget *parent) +{ + Q_UNUSED(parent); + return 0; +} + +void ContextAction::contextEvent(QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event) +} + +void ContextAction::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + Q_UNUSED(event) +} + +DataEngine *ContextAction::dataEngine(const QString &name) const +{ + return d->dataEngine(name); +} + +bool ContextAction::configurationRequired() const +{ + return d->needsConfig; +} + +void ContextAction::setConfigurationRequired(bool needsConfig, const QString &reason) +{ + //TODO: implement something for reason. first, we need to decide where/how + // to communicate it to the user + Q_UNUSED(reason) + + if (d->needsConfig == needsConfig) { + return; + } + + d->needsConfig = needsConfig; + emit configurationRequired(needsConfig); +} + +} // Plasma namespace + +#include "contextaction.moc" diff --git a/contextaction.h b/contextaction.h new file mode 100644 index 000000000..5119c3eae --- /dev/null +++ b/contextaction.h @@ -0,0 +1,259 @@ +/* + * Copyright 2008 by Aaron Seigo + * Copyright 2008 by Petri Damsten + + * 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. + */ + +#ifndef PLASMA_CONTEXTACTION_H +#define PLASMA_CONTEXTACTION_H + +#include + +#include +#include +#include + +namespace Plasma +{ + +class DataEngine; +class ContextActionPrivate; + +/** + * @class ContextAction plasma/contextaction.h + * + * @short The base ContextAction class + * + * "ContextActions" are components that provide an action (usually displaying a contextmenu) in + * response to an event with a position (usually a mouse event). + * + * ContextAction plugins are registered using .desktop files. These files should be + * named using the following naming scheme: + * + * plasma-contextaction-\.desktop + * + */ + +class PLASMA_EXPORT ContextAction : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString pluginName READ pluginName) + Q_PROPERTY(QString icon READ icon) + + public: + /** + * Default constructor for an empty or null contextaction + */ + explicit ContextAction(QObject * parent = 0); + + ~ContextAction(); + + /** + * Returns a list of all known contextactions. + * + * @return list of contextactions + **/ + static KPluginInfo::List listContextActionInfo(); + + /** + * Attempts to load a contextaction + * + * Returns a pointer to the contextaction if successful. + * The caller takes responsibility for the contextaction, including + * deleting it when no longer needed. + * + * @param name the plugin name, as returned by KPluginInfo::pluginName() + * @param args to send the contextaction extra arguments + * @return a pointer to the loaded contextaction, or 0 on load failure + **/ + static ContextAction *load(const QString &name, const QVariantList &args = QVariantList()); + + /** + * Attempts to load a contextaction + * + * Returns a pointer to the contextaction if successful. + * The caller takes responsibility for the contextaction, including + * deleting it when no longer needed. + * + * @param info KPluginInfo object for the desired contextaction + * @param args to send the contextaction extra arguments + * @return a pointer to the loaded contextaction, or 0 on load failure + **/ + static ContextAction *load(const KPluginInfo &info, const QVariantList &args = QVariantList()); + + /** + * Returns the Package specialization for contextactions. + */ + static PackageStructure::Ptr packageStructure(); + + /** + * Returns the user-visible name for the contextaction, as specified in the + * .desktop file. + * + * @return the user-visible name for the contextaction. + **/ + QString name() const; + + /** + * Returns the plugin name for the contextaction + */ + QString pluginName() const; + + /** + * Returns the icon related to this contextaction + **/ + QString icon() const; + + /** + * @return true if initialized (usually by calling restore), false otherwise + */ + bool isInitialized() const; + + /** + * This method should be called once the wallpaper is loaded or mode is changed. + * @param config Config group to load settings + * @see init + **/ + void restore(const KConfigGroup &config); + + /** + * This method is called when settings need to be saved. + * @param config Config group to save settings + **/ + virtual void save(KConfigGroup &config); + + /** + * Returns the widget used in the configuration dialog. + * Add the configuration interface of the contextaction to this widget. + * To signal that settings have changed connect to + * settingsChanged(bool modified) in @p parent. + * @code connect(this, SIGNAL(settingsChanged(bool), parent, SLOT(settingsChanged(bool))) + * @endcode + * Emit settingsChanged(true) when the settings are changed and false when the original state is restored. + */ + virtual QWidget *createConfigurationInterface(QWidget *parent); + + /** + * Implement this to respond to a mouse button event. + * The user can configure whatever button and modifier they like, so please don't look at + * those parameters. + * @param event the mouse event object + */ + virtual void contextEvent(QGraphicsSceneMouseEvent *event); + + /** + * Implement this to respond to a wheel event. + * The user can configure which wheel and whatever modifier they like, so please don't look at + * those parameters. + * @param event the mousewheel event object + */ + virtual void wheelEvent(QGraphicsSceneWheelEvent *event); + + /** + * Loads the given DataEngine + * + * Tries to load the data engine given by @p name. Each engine is + * only loaded once, and that instance is re-used on all subsequent + * requests. + * + * If the data engine was not found, an invalid data engine is returned + * (see DataEngine::isValid()). + * + * Note that you should not delete the returned engine. + * + * @param name Name of the data engine to load + * @return pointer to the data engine if it was loaded, + * or an invalid data engine if the requested engine + * could not be loaded + * + */ + Q_INVOKABLE DataEngine *dataEngine(const QString &name) const; + + /** + * @return true if the contextaction currently needs to be configured, + * otherwise, false + */ + bool configurationRequired() const; + + Q_SIGNALS: + /** + * Emitted when the user wants to configure/change the contextaction. + */ + void configureRequested(); + + /** + * Emitted when the state of the contextaction requiring configuration + * changes. + */ + void configurationRequired(bool needsConfig); + + /** + * Emitted when the configuration of the contextaction needs to be saved + * to disk. + */ + void configNeedsSaving(); + + protected: + /** + * This constructor is to be used with the plugin loading systems + * found in KPluginInfo and KService. The argument list is expected + * to have one element: the KService service ID for the desktop entry. + * + * @param parent a QObject parent; you probably want to pass in 0 + * @param args a list of strings containing one entry: the service id + */ + ContextAction(QObject *parent, const QVariantList &args); + + /** + * This method is called once the contextaction is loaded or mode is changed. + * + * The mode can be retrieved using the renderingMode() method. + * + * @param config Config group to load settings + **/ + virtual void init(const KConfigGroup &config); + + /** + * When the contextaction needs to be configured before being usable, this + * method can be called to denote that action is required + * + * @param needsConfiguring true if the applet needs to be configured, + * or false if it doesn't + * @param reason a translated message for the user explaining that the + * applet needs configuring; this should note what needs + * to be configured + */ + void setConfigurationRequired(bool needsConfiguring, const QString &reason = QString()); + + private: + friend class ContextActionPackage; + friend class ContextActionPrivate; + ContextActionPrivate *const d; +}; + +} // Plasma namespace + +/** + * Register a contextaction when it is contained in a loadable module + */ +#define K_EXPORT_PLASMA_CONTEXTACTION(libname, classname) \ +K_PLUGIN_FACTORY(factory, registerPlugin();) \ +K_EXPORT_PLUGIN(factory("plasma_contextaction_" #libname)) \ +K_EXPORT_PLUGIN_VERSION(PLASMA_VERSION) + +#endif // multiple inclusion guard diff --git a/private/contextaction_p.h b/private/contextaction_p.h new file mode 100644 index 000000000..07c289278 --- /dev/null +++ b/private/contextaction_p.h @@ -0,0 +1,52 @@ +/* + * Copyright 2008 by Aaron Seigo + * Copyright 2008 by Petri Damsten + * + * 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. + */ + +#ifndef PLASMA_CONTEXTACTIONPRIVATE_H +#define PLASMA_CONTEXTACTIONPRIVATE_H + +#include "plasma/private/dataengineconsumer_p.h" + +namespace Plasma +{ + +class ContextActionPrivate : public DataEngineConsumer +{ +public: + ContextActionPrivate(KService::Ptr service, ContextAction *contextAction) : + q(contextAction), + contextActionDescription(service), + initialized(false), + needsConfig(false) + { + }; + + static PackageStructure::Ptr s_packageStructure; + + ContextAction *q; + KPluginInfo contextActionDescription; + Package *package; + KServiceAction mode; + bool initialized : 1; + bool needsConfig : 1; +}; + +} // namespace Plasma +#endif + diff --git a/private/packages.cpp b/private/packages.cpp index 43c62b544..74157e9ba 100644 --- a/private/packages.cpp +++ b/private/packages.cpp @@ -305,6 +305,12 @@ void WallpaperPackage::paperDestroyed() m_paper = 0; } +ContextActionPackage::ContextActionPackage(QObject *parent) + : Plasma::PackageStructure(parent, QString("ContextAction")) +{ + //FIXME how do I do the mimetypes stuff? +} + } // namespace Plasma #include "packages_p.moc" diff --git a/private/packages_p.h b/private/packages_p.h index a1f8280b3..342e29fbd 100644 --- a/private/packages_p.h +++ b/private/packages_p.h @@ -32,8 +32,6 @@ namespace KNS namespace Plasma { -class Wallpaper; - class PlasmoidPackage : public PackageStructure { Q_OBJECT @@ -84,6 +82,14 @@ private: Wallpaper *m_paper; }; +class ContextActionPackage : public PackageStructure +{ + Q_OBJECT + +public: + explicit ContextActionPackage(QObject *parent = 0); +}; + PackageStructure::Ptr defaultPackageStructure(ComponentType type); } // namespace Plasma diff --git a/servicetypes/plasma-contextaction.desktop b/servicetypes/plasma-contextaction.desktop new file mode 100644 index 000000000..73b954255 --- /dev/null +++ b/servicetypes/plasma-contextaction.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Plasma/ContextAction + +Comment=Plasma ContextAction +