make rightclick plugins possible

this makes rightclicks use the plugin configured for rightclick
and adds a new method to the plugin for when an applet is rightclicked
(we need a list of actions then that we can insert into the menu)
this also adds a signal for immutability and improves handling of
needs-configuring plugins

svn path=/trunk/KDE/kdelibs/; revision=1012639
This commit is contained in:
Chani Armitage 2009-08-17 22:30:46 +00:00
parent a848e4fdcf
commit f0a68d537c
5 changed files with 102 additions and 37 deletions

View File

@ -1101,6 +1101,7 @@ void Applet::flushPendingConstraintsEvents()
action->setVisible(canConfig); action->setVisible(canConfig);
action->setEnabled(canConfig); action->setEnabled(canConfig);
} }
emit immutabilityChanged(immutability());
} }
if (c & Plasma::SizeConstraint) { if (c & Plasma::SizeConstraint) {

View File

@ -698,6 +698,12 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
*/ */
void extenderItemRestored(Plasma::ExtenderItem *item); void extenderItemRestored(Plasma::ExtenderItem *item);
/**
* Emitted when the immutability changes
* @since 4.4
*/
void immutabilityChanged(const ImmutabilityType immutable);
public Q_SLOTS: public Q_SLOTS:
/** /**
* Sets the immutability type for this applet (not immutable, * Sets the immutability type for this applet (not immutable,

View File

@ -234,25 +234,35 @@ void Containment::init()
setContextAction(key, cfg.readEntry(key, QString())); setContextAction(key, cfg.readEntry(key, QString()));
} }
} else { } else {
if (d->type == DesktopContainment) { //we need to be very careful here to not write anything
//we need to be very careful here to not write anything //because we have a group, and so the defaults will get merged instead of overwritten
//because we have a group, and so the defaults will get merged instead of overwritten //when copyTo is used (which happens right before restore() is called)
//when copyTo is used (which happens right before restore() is called) //FIXME maybe PlasmaApp should handle the defaults?
QHash<QString,QString> defaults; QHash<QString,QString> defaults;
switch (d->type) {
case DesktopContainment:
defaults.insert("wheel:Vertical;NoModifier", "switchdesktop"); defaults.insert("wheel:Vertical;NoModifier", "switchdesktop");
defaults.insert("wheel:Horizontal;ControlModifier", "test"); defaults.insert("wheel:Horizontal;ControlModifier", "test");
defaults.insert("LeftButton;NoModifier", "switchdesktop"); defaults.insert("LeftButton;NoModifier", "switchdesktop");
defaults.insert("RightButton;NoModifier", "test"); defaults.insert("RightButton;NoModifier", "contextmenu");
foreach (const QString &trigger, defaults.keys()) { break;
ContextAction *action = ContextAction::load(defaults.value(trigger)); case PanelContainment:
if (action) { case CustomPanelContainment:
d->contextActions.insert(trigger, action); defaults.insert("RightButton;NoModifier", "contextmenu");
connect(action, SIGNAL(configureRequested()), this, SLOT(requestConfiguration())); break;
connect(action, SIGNAL(configNeedsSaving()), this, SIGNAL(configNeedsSaving())); default:
} break;
}
foreach (const QString &trigger, defaults.keys()) {
ContextAction *action = ContextAction::load(defaults.value(trigger));
if (action) {
d->contextActions.insert(trigger, action);
connect(action, SIGNAL(configureRequested()), this, SLOT(requestConfiguration()));
connect(action, SIGNAL(configNeedsSaving()), this, SIGNAL(configNeedsSaving()));
action->setParent(this);
} }
} }
//TODO defaults for panel etc.
} }
} }
@ -611,28 +621,28 @@ void ContainmentPrivate::containmentActions(KMenu &desktopMenu)
return; return;
} }
QString trigger = "RightButton;NoModifier";
//get base context actions //get base context actions
QList<QAction*> actions = q->contextualActions(); if (ContextAction *cAction = contextActions.value(trigger)) {
if (QAction *a = cAction->configurationAction()) {
//find the separator to insert the activity settings before it //it needs configuring
QAction *separatorAction = 0; desktopMenu.addAction(a);
} else {
//TODO: should a submenu be created if there are too many containment specific QList<QAction*> actions = cAction->contextualActions();
// actions? see folderview containment if (actions.isEmpty()) {
foreach (QAction *action, actions) { //it probably didn't bother implementing the function. give the user a chance to set
if (action) { //a better plugin.
desktopMenu.addAction(action); //note that if the user sets no-plugin this won't happen...
if (action->isSeparator()) { //FIXME maybe the behaviour could be better
separatorAction = action; if (type == Containment::DesktopContainment) {
desktopMenu.addAction(q->action("configure"));
}
} else {
//yay!
desktopMenu.addActions(actions);
} }
} }
} }
desktopMenu.addSeparator();
if (type == Containment::DesktopContainment) {
desktopMenu.addAction(q->action("configure"));
}
} }
void ContainmentPrivate::appletActions(KMenu &desktopMenu, Applet *applet, bool includeApplet) void ContainmentPrivate::appletActions(KMenu &desktopMenu, Applet *applet, bool includeApplet)
@ -717,7 +727,8 @@ bool ContainmentPrivate::showContextMenu(const QPointF &point, const QPoint &scr
if (applet) { if (applet) {
appletActions(desktopMenu, applet, includeApplet); appletActions(desktopMenu, applet, includeApplet);
} else { } else {
containmentActions(desktopMenu); //containmentActions(desktopMenu);
return false;
} }
if (!desktopMenu.isEmpty()) { if (!desktopMenu.isEmpty()) {
@ -2266,11 +2277,9 @@ bool ContainmentPrivate::prepareContextAction(const QString &trigger, const QPoi
action->restore(actionConfig); action->restore(actionConfig);
} }
if (action->configurationRequired()) { if (QAction *a = action->configurationAction()) {
KMenu menu; KMenu menu;
menu.addTitle(i18n("This plugin needs to be configured")); menu.addAction(a);
//TODO show reason
//TODO offer config button
menu.exec(screenPos); menu.exec(screenPos);
return false; return false;
} }

View File

@ -19,6 +19,9 @@
*/ */
#include "contextaction.h" #include "contextaction.h"
#include "containment.h"
#include <QAction>
#include <kdebug.h> #include <kdebug.h>
#include <kglobal.h> #include <kglobal.h>
@ -120,6 +123,11 @@ PackageStructure::Ptr ContextAction::packageStructure()
return ContextActionPrivate::s_packageStructure; return ContextActionPrivate::s_packageStructure;
} }
Containment *ContextAction::containment()
{
return qobject_cast<Plasma::Containment*>(parent());
}
QString ContextAction::name() const QString ContextAction::name() const
{ {
if (!d->contextActionDescription.isValid()) { if (!d->contextActionDescription.isValid()) {
@ -184,6 +192,12 @@ void ContextAction::wheelEvent(QGraphicsSceneWheelEvent *event)
Q_UNUSED(event) Q_UNUSED(event)
} }
QList<QAction*> ContextAction::contextualActions()
{
//empty list
return QList<QAction*>();
}
DataEngine *ContextAction::dataEngine(const QString &name) const DataEngine *ContextAction::dataEngine(const QString &name) const
{ {
return d->dataEngine(name); return d->dataEngine(name);
@ -194,6 +208,18 @@ bool ContextAction::configurationRequired() const
return d->needsConfig; return d->needsConfig;
} }
QAction *ContextAction::configurationAction()
{
if (d->needsConfig) {
//create the "I need configuring" action
QAction *action = new QAction(i18n("This plugin needs to be configured"), this);
//TODO name/reason?
//TODO connect it to something
return action;
}
return NULL;
}
void ContextAction::setConfigurationRequired(bool needsConfig, const QString &reason) void ContextAction::setConfigurationRequired(bool needsConfig, const QString &reason)
{ {
//TODO: implement something for reason. first, we need to decide where/how //TODO: implement something for reason. first, we need to decide where/how

View File

@ -21,16 +21,21 @@
#ifndef PLASMA_CONTEXTACTION_H #ifndef PLASMA_CONTEXTACTION_H
#define PLASMA_CONTEXTACTION_H #define PLASMA_CONTEXTACTION_H
#include <QList>
#include <kplugininfo.h> #include <kplugininfo.h>
#include <plasma/plasma.h> #include <plasma/plasma.h>
#include <plasma/packagestructure.h> #include <plasma/packagestructure.h>
#include <plasma/version.h> #include <plasma/version.h>
class QAction;
namespace Plasma namespace Plasma
{ {
class DataEngine; class DataEngine;
class Containment;
class ContextActionPrivate; class ContextActionPrivate;
/** /**
@ -164,6 +169,13 @@ class PLASMA_EXPORT ContextAction : public QObject
*/ */
virtual void wheelEvent(QGraphicsSceneWheelEvent *event); virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
/**
* Implement this to provide a list of actions that can be added to another menu
* for example, when right-clicking an applet, the "Activity Options" submenu is populated
* with this.
*/
virtual QList<QAction*> contextualActions();
/** /**
* Loads the given DataEngine * Loads the given DataEngine
* *
@ -190,6 +202,12 @@ class PLASMA_EXPORT ContextAction : public QObject
*/ */
bool configurationRequired() const; bool configurationRequired() const;
/**
* @return a config action if the contextaction currently needs to be configured,
* otherwise, null
*/
QAction *configurationAction();
Q_SIGNALS: Q_SIGNALS:
/** /**
* Emitted when the user wants to configure/change the contextaction. * Emitted when the user wants to configure/change the contextaction.
@ -240,6 +258,11 @@ class PLASMA_EXPORT ContextAction : public QObject
*/ */
void setConfigurationRequired(bool needsConfiguring, const QString &reason = QString()); void setConfigurationRequired(bool needsConfiguring, const QString &reason = QString());
/**
* return the containment the plugin is associated with, if any.
*/
Containment *containment();
private: private:
friend class ContextActionPackage; friend class ContextActionPackage;
friend class ContextActionPrivate; friend class ContextActionPrivate;