keyboard shortcuts.
the defaults are kinda lame right now, but I'm planning to do a lot more with this. applet focus and the shorcut hooks work properly, however. svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=808610
This commit is contained in:
parent
3bce3a18b8
commit
1d8eb91e89
83
applet.cpp
83
applet.cpp
@ -42,6 +42,7 @@
|
||||
#include <QDesktopWidget>
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QAction>
|
||||
|
||||
#include <KIcon>
|
||||
#include <KColorScheme>
|
||||
@ -53,6 +54,7 @@
|
||||
#include <KService>
|
||||
#include <KServiceTypeTrader>
|
||||
#include <KWindowSystem>
|
||||
#include <KActionCollection>
|
||||
|
||||
#include <Solid/PowerManagement>
|
||||
|
||||
@ -650,6 +652,34 @@ void Applet::flushPendingConstraintsEvents()
|
||||
Plasma::Constraints c = d->pendingConstraints;
|
||||
d->pendingConstraints = NoConstraint;
|
||||
|
||||
if (c & Plasma::StartupCompletedConstraint) {
|
||||
//common actions
|
||||
bool unlocked = immutability() == Mutable;
|
||||
//FIXME make it work for containments
|
||||
//also, don't allow to delete the last desktop containment
|
||||
//heck, can desktop ctmts even handle being deleted yet?
|
||||
//so panel has a remove() that tears it down nicely. what does desktop have?
|
||||
QAction* closeApplet = new QAction(i18n("Remove this %1", name()), this);
|
||||
closeApplet->setIcon(KIcon("edit-delete"));
|
||||
closeApplet->setEnabled(unlocked);
|
||||
closeApplet->setVisible(unlocked);
|
||||
closeApplet->setShortcutContext(Qt::WidgetWithChildrenShortcut); //don't clash with other views
|
||||
if (! isContainment()) {
|
||||
closeApplet->setShortcut(QKeySequence("ctrl+r"));
|
||||
connect(closeApplet, SIGNAL(triggered(bool)), this, SLOT(destroy()));
|
||||
}
|
||||
d->actions.addAction("remove", closeApplet);
|
||||
}
|
||||
|
||||
if (c & Plasma::ImmutableConstraint) {
|
||||
bool unlocked = immutability() == Mutable;
|
||||
QAction *action = d->actions.action("remove");
|
||||
if (action) {
|
||||
action->setVisible(unlocked);
|
||||
action->setEnabled(unlocked);
|
||||
}
|
||||
}
|
||||
|
||||
if (c & Plasma::SizeConstraint && d->needsConfigOverlay) {
|
||||
d->needsConfigOverlay->setGeometry(QRectF(QPointF(0, 0), boundingRect().size()));
|
||||
// FIXME:: rather horrible hack to work around the fact we don't have spacers
|
||||
@ -703,6 +733,16 @@ QList<QAction*> Applet::contextualActions()
|
||||
return d->script ? d->script->contextualActions() : QList<QAction*>();
|
||||
}
|
||||
|
||||
QAction* Applet::action(QString name) const
|
||||
{
|
||||
return d->actions.action(name);
|
||||
}
|
||||
|
||||
void Applet::addAction(QString name, QAction *action)
|
||||
{
|
||||
d->actions.addAction(name, action);
|
||||
}
|
||||
|
||||
void Applet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
QPainter *p;
|
||||
@ -821,6 +861,16 @@ Containment* Applet::containment() const
|
||||
return c;
|
||||
}
|
||||
|
||||
void Applet::addAssociatedWidget(QWidget *widget)
|
||||
{
|
||||
d->actions.addAssociatedWidget(widget);
|
||||
}
|
||||
|
||||
void Applet::removeAssociatedWidget(QWidget *widget)
|
||||
{
|
||||
d->actions.removeAssociatedWidget(widget);
|
||||
}
|
||||
|
||||
Location Applet::location() const
|
||||
{
|
||||
Containment* c = containment();
|
||||
@ -886,7 +936,32 @@ bool Applet::hasConfigurationInterface() const
|
||||
|
||||
void Applet::setHasConfigurationInterface(bool hasInterface)
|
||||
{
|
||||
if (d->hasConfigurationInterface == hasInterface) {
|
||||
return;
|
||||
}
|
||||
d->hasConfigurationInterface = hasInterface;
|
||||
//config action
|
||||
//TODO respect security when it's implemented (4.2)
|
||||
QAction *configAction = d->actions.action("configure");
|
||||
if (hasInterface) {
|
||||
if (! configAction) { //should be always true
|
||||
configAction = new QAction(i18n("%1 Settings", name()), this);
|
||||
configAction->setIcon(KIcon("configure"));
|
||||
configAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); //don't clash with other views
|
||||
if (isContainment()) {
|
||||
//kDebug() << "I am a containment";
|
||||
configAction->setShortcut(QKeySequence("ctrl+shift+s"));
|
||||
} else {
|
||||
configAction->setShortcut(QKeySequence("ctrl+s"));
|
||||
}
|
||||
//TODO how can we handle configuration of the shortcut in a way that spans all applets?
|
||||
connect(configAction, SIGNAL(triggered(bool)),
|
||||
this, SLOT(showConfigurationInterface()));
|
||||
d->actions.addAction("configure", configAction);
|
||||
}
|
||||
} else {
|
||||
d->actions.removeAction(configAction);
|
||||
}
|
||||
}
|
||||
|
||||
bool Applet::eventFilter( QObject *o, QEvent * e )
|
||||
@ -946,6 +1021,12 @@ void Applet::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
||||
void Applet::focusInEvent(QFocusEvent * event)
|
||||
{
|
||||
if (containment()) {
|
||||
containment()->d->focusApplet(this);
|
||||
//XXX if we are a containment we'll attempt to focus ourself
|
||||
//which should be harmless
|
||||
//focusing an applet may trigger this event again, but we won't be here more than twice
|
||||
}
|
||||
QGraphicsWidget::focusInEvent(event);
|
||||
}
|
||||
|
||||
@ -1145,6 +1226,7 @@ Applet* Applet::load(const KPluginInfo& info, uint appletId, const QVariantList&
|
||||
|
||||
QVariant Applet::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
//kDebug() << change;
|
||||
switch (change) {
|
||||
case ItemPositionChange:
|
||||
if (d->shadow) {
|
||||
@ -1287,6 +1369,7 @@ Applet::Private::Private(KService::Ptr service, int uniqueID, Applet *applet)
|
||||
pendingConstraints(NoConstraint),
|
||||
aspectRatioMode(Plasma::KeepAspectRatio),
|
||||
immutability(Mutable),
|
||||
actions(applet),
|
||||
constraintsTimerId(0),
|
||||
hasConfigurationInterface(false),
|
||||
failed(false),
|
||||
|
23
applet.h
23
applet.h
@ -36,6 +36,7 @@
|
||||
|
||||
class KConfigDialog;
|
||||
class QGraphicsView;
|
||||
class KActionCollection;
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
@ -414,6 +415,16 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
||||
**/
|
||||
virtual QList<QAction*> contextualActions();
|
||||
|
||||
/**
|
||||
* Returns the QAction with the given name from our collection
|
||||
*/
|
||||
QAction* action(QString name) const;
|
||||
|
||||
/**
|
||||
* Adds the action to our collection under the given name
|
||||
*/
|
||||
void addAction(QString name, QAction *action);
|
||||
|
||||
/**
|
||||
* @return BackgroundHints flags combination telling if the standard background is shown
|
||||
* and if it has a drop shadow
|
||||
@ -448,6 +459,18 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
||||
**/
|
||||
Containment* containment() const;
|
||||
|
||||
/**
|
||||
* associate actions with this widget, including ones added after this call.
|
||||
* needed to make keyboard shortcuts work.
|
||||
*/
|
||||
virtual void addAssociatedWidget(QWidget *widget);
|
||||
|
||||
/**
|
||||
* un-associate actions from this widget, including ones added after this call.
|
||||
* needed to make keyboard shortcuts work.
|
||||
*/
|
||||
virtual void removeAssociatedWidget(QWidget *widget);
|
||||
|
||||
/**
|
||||
* @param parent the QGraphicsItem this applet is parented to
|
||||
* @param serviceId the name of the .desktop file containing the
|
||||
|
@ -22,6 +22,8 @@
|
||||
#ifndef PLASMA_APPLET_P_H
|
||||
#define PLASMA_APPLET_P_H
|
||||
|
||||
#include <KActionCollection>
|
||||
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
@ -87,6 +89,7 @@ public:
|
||||
Plasma::AspectRatioMode aspectRatioMode;
|
||||
QGraphicsView* ghostView;
|
||||
ImmutabilityType immutability;
|
||||
KActionCollection actions;
|
||||
int constraintsTimerId;
|
||||
bool hasConfigurationInterface : 1;
|
||||
bool failed : 1;
|
||||
|
171
containment.cpp
171
containment.cpp
@ -116,6 +116,59 @@ void Containment::init()
|
||||
setContainmentType(DesktopContainment);
|
||||
}
|
||||
|
||||
//common actions
|
||||
bool unlocked = immutability() == Mutable;
|
||||
|
||||
QAction *appletBrowserAction = new QAction(i18n("Add Widgets..."), this);
|
||||
appletBrowserAction->setIcon(KIcon("list-add"));
|
||||
appletBrowserAction->setVisible(unlocked);
|
||||
appletBrowserAction->setEnabled(unlocked);
|
||||
connect(appletBrowserAction, SIGNAL(triggered()), this, SLOT(triggerShowAddWidgets()));
|
||||
appletBrowserAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
appletBrowserAction->setShortcut(QKeySequence("ctrl+a"));
|
||||
d->actions().addAction("add widgets", appletBrowserAction);
|
||||
|
||||
QAction *action = new QAction(i18n("Next Applet"), this);
|
||||
//no icon
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(focusNextApplet()));
|
||||
action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
action->setShortcut(QKeySequence("ctrl+n"));
|
||||
d->actions().addAction("next applet", action);
|
||||
|
||||
action = new QAction(i18n("Previous Applet"), this);
|
||||
//no icon
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(focusPreviousApplet()));
|
||||
action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
action->setShortcut(QKeySequence("ctrl+p"));
|
||||
d->actions().addAction("previous applet", action);
|
||||
|
||||
if (immutability() != SystemImmutable) {
|
||||
//FIXME I'm not certain this belongs in Containment
|
||||
//but it sure is nice to have the keyboard shortcut in every containment by default
|
||||
QAction *lockDesktopAction = new QAction(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets"), this);
|
||||
lockDesktopAction->setIcon(KIcon("object-locked"));
|
||||
connect(lockDesktopAction, SIGNAL(triggered(bool)), this, SLOT(toggleDesktopImmutability()));
|
||||
lockDesktopAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
lockDesktopAction->setShortcut(QKeySequence("ctrl+l"));
|
||||
d->actions().addAction("lock widgets", lockDesktopAction);
|
||||
}
|
||||
|
||||
if (d->type == DesktopContainment) { //this means custom containments are left out
|
||||
QAction *zoomAction = new QAction(i18n("Zoom In"), this);
|
||||
zoomAction->setIcon(KIcon("zoom-in"));
|
||||
connect(zoomAction, SIGNAL(triggered(bool)), this, SLOT(zoomIn()));
|
||||
zoomAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
zoomAction->setShortcut(QKeySequence("ctrl+="));
|
||||
d->actions().addAction("zoom in", zoomAction);
|
||||
|
||||
zoomAction = new QAction(i18n("Zoom Out"), this);
|
||||
zoomAction->setIcon(KIcon("zoom-out"));
|
||||
connect(zoomAction, SIGNAL(triggered(bool)), this, SLOT(zoomOut()));
|
||||
zoomAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
zoomAction->setShortcut(QKeySequence("ctrl+-"));
|
||||
d->actions().addAction("zoom out", zoomAction);
|
||||
}
|
||||
|
||||
Applet::init();
|
||||
}
|
||||
|
||||
@ -276,12 +329,11 @@ void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
|
||||
}
|
||||
|
||||
if (applet->hasConfigurationInterface()) {
|
||||
QAction* configureApplet = new QAction(i18n("%1 Settings", applet->name()), &desktopMenu);
|
||||
configureApplet->setIcon(KIcon("configure"));
|
||||
connect(configureApplet, SIGNAL(triggered(bool)),
|
||||
applet, SLOT(showConfigurationInterface()));
|
||||
desktopMenu.addAction(configureApplet);
|
||||
hasEntries = true;
|
||||
QAction* configureApplet = applet->d->actions.action("configure");
|
||||
if (configureApplet) {
|
||||
desktopMenu.addAction(configureApplet);
|
||||
hasEntries = true;
|
||||
}
|
||||
}
|
||||
|
||||
QList<QAction*> containmentActions = contextualActions();
|
||||
@ -302,14 +354,18 @@ void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
if (scene() && !static_cast<Corona*>(scene())->immutability() != Mutable) {
|
||||
if (scene() && static_cast<Corona*>(scene())->immutability() == Mutable) {
|
||||
if (hasEntries) {
|
||||
desktopMenu.addSeparator();
|
||||
}
|
||||
|
||||
QAction* closeApplet = new QAction(i18n("Remove this %1", applet->name()), &desktopMenu);
|
||||
closeApplet->setIcon(KIcon("edit-delete"));
|
||||
connect(closeApplet, SIGNAL(triggered(bool)), applet, SLOT(destroy()));
|
||||
QAction* closeApplet = applet->d->actions.action("remove");
|
||||
if (! closeApplet) { //unlikely but not impossible
|
||||
kDebug() << "wtf!! no remove action!!!!!!!!";
|
||||
closeApplet = new QAction(i18n("Remove this %1", applet->name()), &desktopMenu);
|
||||
closeApplet->setIcon(KIcon("edit-delete"));
|
||||
connect(closeApplet, SIGNAL(triggered(bool)), applet, SLOT(destroy()));
|
||||
}
|
||||
desktopMenu.addAction(closeApplet);
|
||||
hasEntries = true;
|
||||
}
|
||||
@ -716,6 +772,7 @@ bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
|
||||
QVariant Containment::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
Q_UNUSED(value)
|
||||
//FIXME if the applet is moved to another containment we need to unfocus it
|
||||
|
||||
if (isContainment() &&
|
||||
(change == QGraphicsItem::ItemSceneHasChanged || change == QGraphicsItem::ItemPositionHasChanged) &&
|
||||
@ -789,6 +846,84 @@ void Containment::closeToolBox()
|
||||
}
|
||||
}
|
||||
|
||||
void Containment::addAssociatedWidget(QWidget *widget)
|
||||
{
|
||||
Applet::addAssociatedWidget(widget);
|
||||
if (d->focusedApplet) {
|
||||
d->focusedApplet->addAssociatedWidget(widget);
|
||||
}
|
||||
}
|
||||
|
||||
void Containment::removeAssociatedWidget(QWidget *widget)
|
||||
{
|
||||
Applet::removeAssociatedWidget(widget);
|
||||
if (d->focusedApplet) {
|
||||
d->focusedApplet->removeAssociatedWidget(widget);
|
||||
}
|
||||
}
|
||||
|
||||
KActionCollection& Containment::Private::actions()
|
||||
{
|
||||
return static_cast<Applet*>(q)->d->actions;
|
||||
}
|
||||
|
||||
void Containment::Private::focusApplet(Plasma::Applet *applet)
|
||||
{
|
||||
kDebug();
|
||||
if (focusedApplet == applet) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QWidget *> widgets = actions().associatedWidgets();
|
||||
if (focusedApplet) {
|
||||
foreach (QWidget *w, widgets) {
|
||||
focusedApplet->removeAssociatedWidget(w);
|
||||
}
|
||||
}
|
||||
//but what if applet isn't really one of our applets?
|
||||
//FIXME should we really unfocus the old applet?
|
||||
if (applets.contains(applet)) {
|
||||
kDebug() << "switching to" << applet->name();
|
||||
focusedApplet = applet;
|
||||
if (focusedApplet) {
|
||||
foreach (QWidget *w, widgets) {
|
||||
focusedApplet->addAssociatedWidget(w);
|
||||
}
|
||||
}
|
||||
applet->setFocus(Qt::ShortcutFocusReason);
|
||||
} else {
|
||||
focusedApplet = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Containment::focusNextApplet()
|
||||
{
|
||||
kDebug();
|
||||
if (d->applets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) + 1 : 0;
|
||||
if (index >= d->applets.size()) {
|
||||
index = 0;
|
||||
}
|
||||
kDebug() << "index" << index;
|
||||
d->focusApplet(d->applets.at(index));
|
||||
}
|
||||
|
||||
void Containment::focusPreviousApplet()
|
||||
{
|
||||
kDebug();
|
||||
if (d->applets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int index = d->focusedApplet ? d->applets.indexOf(d->focusedApplet) - 1 : -1;
|
||||
if (index < 0) {
|
||||
index = d->applets.size() - 1;
|
||||
}
|
||||
kDebug() << "index" << index;
|
||||
d->focusApplet(d->applets.at(index));
|
||||
}
|
||||
|
||||
|
||||
// Private class implementation
|
||||
|
||||
@ -808,7 +943,7 @@ void Containment::Private::toggleDesktopImmutability()
|
||||
}
|
||||
}
|
||||
|
||||
setLockToolText();
|
||||
//setLockToolText();
|
||||
}
|
||||
|
||||
void Containment::Private::zoomIn()
|
||||
@ -896,6 +1031,17 @@ void Containment::Private::containmentConstraintsEvent(Plasma::Constraints const
|
||||
//kDebug() << "got containmentConstraintsEvent" << constraints << (QObject*)toolBox;
|
||||
if (constraints & Plasma::ImmutableConstraint) {
|
||||
setLockToolText();
|
||||
//update actions
|
||||
bool unlocked = q->immutability() == Mutable;
|
||||
QAction *action = actions().action("add widgets");
|
||||
if (action) {
|
||||
action->setVisible(unlocked);
|
||||
action->setEnabled(unlocked);
|
||||
}
|
||||
action = actions().action("lock widgets");
|
||||
if (action) {
|
||||
action->setText(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets"));
|
||||
}
|
||||
|
||||
// tell the applets too
|
||||
foreach (Applet *a, applets) {
|
||||
@ -1001,6 +1147,9 @@ void Containment::Private::appletDestroyed(QObject* object)
|
||||
// so this unsafe looking code is actually just fine.
|
||||
Applet* applet = static_cast<Plasma::Applet*>(object);
|
||||
applets.removeAll(applet);
|
||||
if (focusedApplet == applet) {
|
||||
focusedApplet = 0;
|
||||
}
|
||||
emit q->appletRemoved(applet);
|
||||
emit q->configNeedsSaving();
|
||||
}
|
||||
|
@ -260,6 +260,18 @@ class PLASMA_EXPORT Containment : public Applet
|
||||
*/
|
||||
void closeToolBox();
|
||||
|
||||
/**
|
||||
* associate actions with this widget, including ones added after this call.
|
||||
* needed to make keyboard shortcuts work.
|
||||
*/
|
||||
void addAssociatedWidget(QWidget *widget);
|
||||
|
||||
/**
|
||||
* un-associate actions from this widget, including ones added after this call.
|
||||
* needed to make keyboard shortcuts work.
|
||||
*/
|
||||
void removeAssociatedWidget(QWidget *widget);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted when a new applet is created by the containment
|
||||
@ -328,6 +340,16 @@ class PLASMA_EXPORT Containment : public Applet
|
||||
*/
|
||||
void addSiblingContainment();
|
||||
|
||||
/**
|
||||
* switch keyboard focus to the next of our applets
|
||||
*/
|
||||
void focusNextApplet();
|
||||
|
||||
/**
|
||||
* switch keyboard focus to the previous one of our applets
|
||||
*/
|
||||
void focusPreviousApplet();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Sets the type of this containment.
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
: q(c),
|
||||
formFactor(Planar),
|
||||
location(Floating),
|
||||
focusedApplet(0),
|
||||
screen(-1), // no screen
|
||||
toolBox(0),
|
||||
type(Containment::NoContainmentType),
|
||||
@ -82,10 +83,18 @@ public:
|
||||
const QRectF &geometry = QRectF(-1, -1, -1, -1), uint id = 0,
|
||||
bool delayedInit = false);
|
||||
|
||||
KActionCollection& actions();
|
||||
|
||||
/**
|
||||
* give keyboard focus to applet within this containment
|
||||
*/
|
||||
void focusApplet(Plasma::Applet *applet);
|
||||
|
||||
Containment *q;
|
||||
FormFactor formFactor;
|
||||
Location location;
|
||||
Applet::List applets;
|
||||
Applet *focusedApplet;
|
||||
QMap<Applet*, AppletHandle*> handles;
|
||||
int screen;
|
||||
Toolbox *toolBox;
|
||||
|
6
view.cpp
6
view.cpp
@ -21,6 +21,7 @@
|
||||
|
||||
#include <KGlobal>
|
||||
#include <KWindowSystem>
|
||||
#include <KActionCollection>
|
||||
|
||||
#include "corona.h"
|
||||
#include "containment.h"
|
||||
@ -175,6 +176,8 @@ void View::setContainment(Containment *containment)
|
||||
if (d->containment) {
|
||||
disconnect(d->containment, SIGNAL(geometryChanged()), this, SLOT(updateSceneRect()));
|
||||
screen = d->containment->screen();
|
||||
//remove all the old containment's actions
|
||||
d->containment->removeAssociatedWidget(this);
|
||||
}
|
||||
|
||||
d->containment = containment;
|
||||
@ -182,6 +185,9 @@ void View::setContainment(Containment *containment)
|
||||
return;
|
||||
}
|
||||
|
||||
//add keyboard-shortcut actions
|
||||
d->containment->addAssociatedWidget(this);
|
||||
|
||||
if (screen > -1) {
|
||||
containment->setScreen(screen);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user