[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-core-devel
Subject: Re: KActionCollection setAssociatedWidget problems
From: Hamish Rodda <rodda () kde ! org>
Date: 2007-10-22 11:04:34
Message-ID: 200710222104.37398.rodda () kde ! org
[Download RAW message or body]
[Attachment #2 (multipart/mixed)]
On Mon, 22 Oct 2007 06:59:06 pm David Faure wrote:
> On Sunday 21 October 2007, Andreas Hartmetz wrote:
> > Am Sonntag, 21. Oktober 2007 17:31:43 schrieb Hamish Rodda:
> > > On Mon, 22 Oct 2007 12:39:00 am Andreas Hartmetz wrote:
> > > > Am Sonntag, 21. Oktober 2007 16:01:02 schrieb Hamish Rodda:
> > > > > Hi,
> > > > >
> > > > > A while back there was a cleanup of KActionCollection which subtly
> > > > > changed the behaviour of setAssociatedWidget(QWidget*). This
> > > > > function is intended to make the actions specific to that widget,
> > > > > and accomplishes this by adding all actions to the widget and
> > > > > setting their shortcut context to Qt::WidgetShortcut. (It replaces
> > > > > KAccel's widget binding functionality)
> > > > >
> > > > > The problem is that in the cleanup, the mechanism to ensure any
> > > > > further actions were added to the widget was kept, but the
> > > > > mechanism to ensure the shortcut context got changed to
> > > > > Qt::WidgetShortcut was deleted. Now, the only shortcuts which have
> > > > > their context changed are those which are already a part of the
> > > > > action collection when
> > > > > setAssociatedWidget is called.
> > > >
> > > > See below...
> > > >
> > > > > This has created a set of serious bugs: when parts are merged
> > > > > together, actions' shortcuts step on each other's toes if the
> > > > > setAssociatedWidget call was prior to their addition to the action
> > > > > collection. For instance, KDirOperator's delete shortcut (a
> > > > > WindowShortcut) competes with katepart's delete shortcut, thus
> > > > > delete doesn't work when you're typing in kate.
> > > > >
> > > > > While I agree that the magic of changing the shortcut context is
> > > > > not ideal, it is the intention (or at least I hope it is) of every
> > > > > use of setAssociatedWidget to conveniently have this effect.
> > > >
> > > > There was actually a complaint from an application programmer about
> > > > the "magic" behavior. So that's why I removed it, but apparently not
> > > > in all places.
> > > >
> > > > > I believe the best course of action is to reintroduce this
> > > > > behaviour (one line patch attached). The alternative really is to
> > > > > remove setAssociatedShortcut and let the apps do it themselves, but
> > > > > I think this would lead to more errors.
> > > >
> > > > IMHO collections that change their contents are a dangerous concept.
> > > > There may be cases where it works, but generally it'll just give you
> > > > problems. Imagine you are debugging an application and objects change
> > > > but you have no idea why - because it's implicit and you can't know
> > > > without reading the documentation of all classes involved. Even a
> > > > breakpoint at the setter won't necessarily work because not
> > > > everything goes through the setter - example: destroying and
> > > > recreating an object changes its properties without calling any
> > > > setters.
> > >
> > > Ok. Should we remove *AssociatedWidget from the api and do:
> > >
> > > for (KAction* action, yourActionCollection) {
> > > action->setShortcutContext(Qt::WidgetShortcut);
> > > widget->addAction(action);
> > > }
> > >
> > > for every use of it? Perhaps replace it with
> > > KActionCollection::associateActionsWithWidget(QWidget*), which
> > > basically does the above on a once-off only...
> >
> > I'd agree with both but I also don't feel like deciding about something I
> > have never used as an application programmer...
> > Any further opinions? Sorry, I know we've had this topic several times
> > already :/
>
> I know that I fixed a bug in konqpopupmenu where a call to
> setAssociatedWidget made all actions be plugged twice into the menu. [and
> this was really not obvious from the code]
>
> Somehow, the automatic setting of the shortcut context would be good to
> have, but the automatic addAction seems very confusing; especially since
> for popup menus you usually add actions yourself, and for the rest we use
> XMLGUI -- or what do I miss here?
This functionality is usually used when you've got a custom widget which wants
to respond to shortcuts when it has focus, eg. katepart, kdiroperator. These
situations don't use XMLGUI for action adding.
I have thought about this more, and come up with an alternative which should
make everyone happy. We remove {set|add|remove|clear}AssociatedWidget(s) and
associatedWidgets(), so no more magic. Then we add void
associateWidget(QWidget*), which is a simple convenience function which
iterates the actions, sets the shortcut context and adds the actions to the
widget. This means you have to be more careful when you call it (need to
have all of your actions set up, or any extras have to be dealt with
manually).
It turned out to be a fairly simple patch; of course, removing those methods
would be BIC. The patch adding this new solution is attached (but not
removing the old methods, yet).
Comments? If ok, would it be possible to remove the old methods, and if so,
when?
Cheers,
Hamish
["kdelibs-associatewidget.patch" (text/x-diff)]
Index: kate/view/kateview.cpp
===================================================================
--- kate/view/kateview.cpp (revision 728024)
+++ kate/view/kateview.cpp (working copy)
@@ -259,7 +259,6 @@
void KateView::setupActions()
{
KActionCollection *ac = this->actionCollection ();
- ac->setAssociatedWidget(m_viewInternal);
QAction *a;
m_toggleWriteLock = 0;
@@ -561,6 +560,8 @@
slotSelectionChanged ();
+ ac->associateWidget(m_viewInternal);
+
connect (this, SIGNAL(selectionChanged(KTextEditor::View*)), this, SLOT(slotSelectionChanged()));
}
@@ -573,7 +574,6 @@
{
m_editActions = new KActionCollection( static_cast<QObject*>(this) );
m_editActions->setObjectName( "edit_actions" );
- m_editActions->setAssociatedWidget(m_viewInternal);
KActionCollection* ac = m_editActions;
QAction* a = ac->addAction("word_left");
@@ -803,6 +803,8 @@
slotGotFocus();
else
slotLostFocus();
+
+ m_editActions->associateWidget(m_viewInternal);
}
void KateView::setupCodeFolding()
Index: kfile/kdiroperator.cpp
===================================================================
--- kfile/kdiroperator.cpp (revision 728024)
+++ kfile/kdiroperator.cpp (working copy)
@@ -1456,7 +1456,6 @@
{
d->actionCollection = new KActionCollection(this);
d->actionCollection->setObjectName("KDirOperator::actionCollection");
- d->actionCollection->setAssociatedWidget(topLevelWidget());
d->actionMenu = new KActionMenu(i18n("Menu"), this);
d->actionCollection->addAction("popupMenu", d->actionMenu);
@@ -1558,6 +1557,8 @@
viewMenu->addAction(detailedAction);
// TODO: QAbstractItemView does not offer an action collection. Provide
// an interface to add a custom action collection.
+
+ d->actionCollection->associateWidget(topLevelWidget());
}
void KDirOperator::setupMenu()
Index: kdeui/dialogs/kedittoolbar.cpp
===================================================================
--- kdeui/dialogs/kedittoolbar.cpp (revision 728024)
+++ kdeui/dialogs/kedittoolbar.cpp (working copy)
@@ -671,7 +671,6 @@
QDomElement elem;
m_widget->setFactory( factory );
- m_widget->actionCollection()->setAssociatedWidget( m_widget );
// add all of the client data
bool first = true;
@@ -705,6 +704,8 @@
loadToolBarCombo( defaultToolBar );
m_widget->adjustSize();
m_widget->setMinimumSize( m_widget->sizeHint() );
+
+ m_widget->actionCollection()->associateWidget( m_widget );
}
bool KEditToolBarWidget::save()
Index: kdeui/actions/kactioncollection.h
===================================================================
--- kdeui/actions/kactioncollection.h (revision 728024)
+++ kdeui/actions/kactioncollection.h (working copy)
@@ -125,6 +125,18 @@
QList<QWidget*> associatedWidgets() const;
/**
+ * Associate all actions in this collection to the given \a widget, and set all
+ * shortcutContexts to Qt::WidgetShortcut. This has the effect of making the actions
+ * only trigger when:
+ * 1) the widget (or its children, it Qt 4.4 and above) has focus
+ * 2) the shortcut is pressed.
+ *
+ * This is important particularly when actions only apply to a specific widget, and
+ * when the application is a kpart and needs to respect other parts' shortcuts.
+ */
+ void associateWidget(QWidget* widget) const;
+
+ /**
* Returns the KConfig group with which settings will be loaded and saved.
*/
QString configGroup() const;
Index: kdeui/actions/kactioncollection.cpp
===================================================================
--- kdeui/actions/kactioncollection.cpp (revision 728024)
+++ kdeui/actions/kactioncollection.cpp (working copy)
@@ -338,6 +338,14 @@
return d->associatedWidgets;
}
+void KActionCollection::associateWidget(QWidget* widget) const
+{
+ foreach (QAction* action, actions()) {
+ action->setShortcutContext(Qt::WidgetShortcut);
+ widget->addAction(action);
+ }
+}
+
QString KActionCollection::configGroup( ) const
{
return d->configGroup;
Index: kdeui/tests/ktoolbartest.cpp
===================================================================
--- kdeui/tests/ktoolbartest.cpp (revision 728024)
+++ kdeui/tests/ktoolbartest.cpp (working copy)
@@ -37,7 +37,7 @@
action3->setSeparator(true);
action7->setSeparator(true);
- coll.setAssociatedWidget(tb);
+ coll.associateWidget(tb);
mw->show();
Index: kdeui/widgets/kdatetable.cpp
===================================================================
--- kdeui/widgets/kdatetable.cpp (revision 728024)
+++ kdeui/widgets/kdatetable.cpp (working copy)
@@ -231,7 +231,6 @@
void KDateTable::initAccels()
{
KActionCollection * localCollection = new KActionCollection( this );
- localCollection->setAssociatedWidget( this );
QAction* next = localCollection->addAction( QLatin1String( "next" ) );
next->setShortcuts( KStandardShortcut::next() );
@@ -258,6 +257,7 @@
connect( endWeek, SIGNAL( triggered( bool ) ), SLOT( endOfWeek() ) );
localCollection->readSettings();
+ localCollection->associateWidget( this );
}
int KDateTable::posFromDate( const QDate &date_ )
["kdebase-associatewidget.patch" (text/x-diff)]
Index: apps/konsole/src/Part.cpp
===================================================================
--- apps/konsole/src/Part.cpp (revision 728025)
+++ apps/konsole/src/Part.cpp (working copy)
@@ -84,7 +84,7 @@
_viewManager->widget()->setParent(parentWidget);
setWidget(_viewManager->widget());
- actionCollection()->setAssociatedWidget(_viewManager->widget());
+ actionCollection()->associateWidget(_viewManager->widget());
// create basic session
createSession(QString());
Index: apps/konsole/src/SessionController.cpp
===================================================================
--- apps/konsole/src/SessionController.cpp (revision 728025)
+++ apps/konsole/src/SessionController.cpp (working copy)
@@ -87,8 +87,8 @@
// handle user interface related to session (menus etc.)
setXMLFile("konsole/sessionui.rc");
- actionCollection()->setAssociatedWidget(view);
setupActions();
+ actionCollection()->associateWidget(view);
setIdentifier(_session->sessionId());
sessionTitleChanged();
Index: apps/konsole/src/MainWindow.cpp
===================================================================
--- apps/konsole/src/MainWindow.cpp (revision 728025)
+++ apps/konsole/src/MainWindow.cpp (working copy)
@@ -60,8 +60,8 @@
// file can be found when this code is being used in the Konsole part.
setXMLFile("konsole/konsoleui.rc");
- actionCollection()->setAssociatedWidget(this);
setupActions();
+ actionCollection()->associateWidget(this);
// create view manager
_viewManager = new ViewManager(this,actionCollection());
["signature.asc" (application/pgp-signature)]
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic