Middle Clicking on Bookmarks - KAction integration

Daniel Teske teske at squorn.de
Thu Dec 16 16:11:36 GMT 2004


Hi

this is the second version of the middle click patch. It adds KAction
integration and the KToolbarButton change is a better fit for the
existing interface.

kdeui-wkaction-patch
KToolbarButton:
Adds a signal: middleClicked() to the existing clicked() and
doubleClicked(). This is implemented in the same way doubleClicked() is,
in KToolbarButton::eventFilter().

KPopupMenu:
Unchanged from the last version.

KAction:
I added two additional bits to KAction::ActivationReason, namely:
MiddleClick and DoubleClick.

For KToolbarButton
connects to the middleClicked() (and doubleClicked()) signals to
slotMiddleClicked and slotDoubleClicked. 
The slots set ActivationReason to the apporiate value and emit
activated().

There are two problems with this code:
a) slotActivated is virtual, due to BC constraints slotMiddleClick and
slotDoubleClick aren't. That means, derived classes can't change the
behauviour of middle clicks on toolbar buttons.

b) emitting activated() for DoubleClicking might break apps, who think
KAction ignores those.

For KPopupMenu:
To check wheter the middle button was used, we need to ask the
KPopupMenu for its state(). Due to the way KPopupMenu sends its signals,
sender() returns a QSignal, with no parent. The QSignal stores the Id of
the KPopupMenu inside value(). So I take that id and search inside
containers for the corresponding KPopupMenu. The ids of MenuItems
KAction inserted are guaranteed to be unique. 
However this is crude.
So I added slotPopupActivated, to which the activated() signals of the
KPopupMenus are connected. This ensures that only QSignals of
KPopupMenus, into which we plugged() us in are handled this way.

There is a small problem: slotActivated is virtual, as such derived
classes could expect to get the activated signals of KPopupMenus there.
slotPopupActivated isn't virtual.

kio-bookmarks-wkaction:
This is now a little easier, because KAction knows whether the middle
button was used. 

konqueror-patch:
Unchanged from the last version.

daniel
-------------- next part --------------
? kdeui-patch
Index: kaction.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kaction.cpp,v
retrieving revision 1.321
diff -u -3 -p -r1.321 kaction.cpp
--- kaction.cpp	17 Nov 2004 14:03:48 -0000	1.321
+++ kaction.cpp	16 Dec 2004 14:40:09 -0000
@@ -652,12 +652,12 @@ int KAction::plug( QWidget *w, int index
         else
           instance = KGlobal::instance();
         id = menu->insertItem( d->iconSet( KIcon::Small, 0, instance ), d->text(), this,//dsweet
-                                 SLOT( slotActivated() ), keyQt,
+                                 SLOT( slotPopupActivated() ), keyQt,
                                  -1, index );
     }
     else
         id = menu->insertItem( d->text(), this,
-                               SLOT( slotActivated() ),  //dsweet
+                               SLOT( slotPopupActivated() ),  //dsweet
                                keyQt, -1, index );
 
     // If the shortcut is already in a KAccel object, then
@@ -707,7 +707,11 @@ int KAction::plug( QWidget *w, int index
                            SLOT( slotActivated() ),
                            d->isEnabled(), d->plainText(), index, instance );
     }
-    bar->getButton( id_ )->setName( QCString("toolbutton_")+name() );
+
+    KToolBarButton* ktb = bar->getButton(id_);
+    connect(ktb, SIGNAL( middleClicked(int) ), this, SLOT( slotMiddleClicked(int) ));
+    connect(ktb, SIGNAL( doubleClicked(int) ), this, SLOT( slotDoubleClicked(int) ));
+    ktb->setName( QCString("toolbutton_")+name() );
 
     if ( !d->whatsThis().isEmpty() )
         QWhatsThis::add( bar->getButton(id_), whatsThisWithIcon() );
@@ -1102,6 +1106,53 @@ void KAction::slotActivated()
   emit activated();
 }
 
+// This catches signals emitted by KActions inserted into KPopupMenu
+// We do crude things inside it, because we need to know which
+// KPopopUpMenu emitted the signal. We need to be sure that it is
+// only called by KpopupMenus, we plugged us in.
+void KAction::slotPopupActivated()
+{
+  kdDebug()<<"KAction::slotPopupActivated()"<<endl;
+  if( ::qt_cast<QSignal *>(sender()))
+  {
+    int id = dynamic_cast<const QSignal *>(sender())->value().toInt();
+    int pos = findContainer(id);
+    if(pos != -1)
+    {
+      KPopupMenu* kpm = dynamic_cast<KPopupMenu *>( container(pos));
+      if(kpm)
+      {
+	if(kpm->state() & Qt::MidButton) //FIXME Keyboard
+	  d->m_activationReason = KAction::ActivationReason(KAction::PopupMenuActivation KAction::MiddleClick);
+	else
+	  d->m_activationReason = KAction::PopupMenuActivation;
+	emit activated();
+	return;
+      }
+    }
+
+    kdWarning()<<"Don't connect KAction::slotPopupActivated() to anything, expect into KPopupMenus which are in containers. Use slotActivated istead."<<endl;
+    d->m_activationReason = KAction::ActivationReason(KAction::PopupMenuActivation);
+    emit activated();
+    return;
+  }
+}
+
+void KAction::slotDoubleClicked(int)
+{
+  //FIXME: compatibility? 
+  //d->m_activationReason = ActivationReason( KAction::ToolBarActivation | KAction::DoubleClick );
+  //emit activated();
+}
+
+void KAction::slotMiddleClicked(int)
+{
+  kdDebug(129) << "slotMiddleClicked()";
+  d->m_activationReason = ActivationReason( KAction::ToolBarActivation | KAction::MiddleClick );
+  emit activated();
+}
+
+
 KAction::ActivationReason KAction::activationReason() const
 {
   return d->m_activationReason;
@@ -1162,6 +1213,26 @@ int KAction::findContainer( const QWidge
   return -1;
 }
 
+int KAction::findContainer( const int id ) const
+{
+  int pos = 0;
+
+  const QValueList<KActionPrivate::Container> & containers = d->m_containers;
+
+  QValueList<KActionPrivate::Container>::ConstIterator it = containers.constBegin();
+  const QValueList<KActionPrivate::Container>::ConstIterator itEnd = containers.constEnd();
+
+  while( it != itEnd )
+  {
+    if ( (*it).m_id == id )
+      return pos;
+    ++it;
+    ++pos;
+  }
+
+  return -1;
+}
+
 void KAction::removeContainer( int index )
 {
   int i = 0;
Index: kaction.h
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kaction.h,v
retrieving revision 1.185
diff -u -3 -p -r1.185 kaction.h
--- kaction.h	17 Nov 2004 14:03:49 -0000	1.185
+++ kaction.h	16 Dec 2004 14:40:09 -0000
@@ -487,7 +487,7 @@ public:
     /**
     * @since 3.4
     */
-    enum ActivationReason { UnknownActivation, EmulatedActivation, AccelActivation, PopupMenuActivation, ToolBarActivation };
+    enum ActivationReason { UnknownActivation = 0, EmulatedActivation = 1, AccelActivation = 2, PopupMenuActivation = 3, ToolBarActivation = 4, DoubleClick = 8, MiddleClick = 16};
 
     /**
     * Returns what triggered the last activated() signal.
@@ -555,12 +555,16 @@ protected slots:
     virtual void slotDestroyed();
     virtual void slotKeycodeChanged();
     virtual void slotActivated();
+    void slotPopupActivated();
+    void slotDoubleClicked(int); //FIXME virtual?
+    void slotMiddleClicked(int);
 
 protected:
     KToolBar* toolBar( int index ) const;
     QPopupMenu* popupMenu( int index ) const;
     void removeContainer( int index );
     int findContainer( const QWidget* widget ) const;
+    int findContainer( const int id ) const;
     void plugMainWindowAccel( QWidget *w );
 
     void addContainer( QWidget* parent, int id );
Index: kpopupmenu.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kpopupmenu.cpp,v
retrieving revision 1.42
diff -u -3 -p -r1.42 kpopupmenu.cpp
--- kpopupmenu.cpp	3 Nov 2004 16:15:17 -0000	1.42
+++ kpopupmenu.cpp	16 Dec 2004 14:40:09 -0000
@@ -21,6 +21,7 @@
 #include <qtimer.h>
 #include <qfontmetrics.h>
 #include <qstyle.h>
+#include <qnamespace.h>
 
 #include "kpopupmenu.h"
 
@@ -126,6 +127,7 @@ public:
         , shortcuts(false)
         , autoExec(false)
         , lastHitIndex(-1)
+	, state(Qt::NoButton)
         , m_ctxMenu(0)
     {}
 
@@ -147,6 +149,7 @@ public:
     QString originalText;
 
     int lastHitIndex;
+    Qt::ButtonState state;
 
     // support for RMB menus on menus
     QPopupMenu* m_ctxMenu;
@@ -272,11 +275,25 @@ void KPopupMenu::closeEvent(QCloseEvent*
     QPopupMenu::closeEvent(e);
 }
 
+void KPopupMenu::activateItemAt(int index)
+{
+    d->state = Qt::NoButton;
+    QPopupMenu::activateItemAt(index);
+}
+
+Qt::ButtonState KPopupMenu::state() const
+{
+    return d->state;
+}
+
 void KPopupMenu::keyPressEvent(QKeyEvent* e)
 {
+    d->state = Qt::NoButton;
     if (!d->shortcuts) {
         // continue event processing by Qpopup
         //e->ignore();
+        d->state = e->state();
+	kdDebug() << "Key Press Event State:"<<d->state<<"\n";
         QPopupMenu::keyPressEvent(e);
         return;
     }
@@ -294,6 +311,8 @@ void KPopupMenu::keyPressEvent(QKeyEvent
         resetKeyboardVars();
         // continue event processing by Qpopup
         //e->ignore();
+	d->state = e->state();
+	kdDebug() << "Key Press Event State:"<<d->state<<"\n";
         QPopupMenu::keyPressEvent(e);
         return;
     } else if ( key == Key_Shift || key == Key_Control || key == Key_Alt || key == Key_Meta )
@@ -486,6 +505,14 @@ void KPopupMenu::mousePressEvent(QMouseE
     QPopupMenu::mousePressEvent(e);
 }
 
+void KPopupMenu::mouseReleaseEvent(QMouseEvent* e)
+{
+    // Save the button and any modifiers, but mouse buttons, in state
+    d->state = Qt::ButtonState(e->button() | (e->state() & ~(Qt::LeftButton & Qt::MidButton & Qt::RightButton)));
+    kdDebug() << "Mouse Press Event State:"<<d->state<<" ("<<e->button()<<")\n";
+    QPopupMenu::mouseReleaseEvent(e);
+}
+
 QPopupMenu* KPopupMenu::contextMenu()
 {
     if (!d->m_ctxMenu)
Index: kpopupmenu.h
===================================================================
RCS file: /home/kde/kdelibs/kdeui/kpopupmenu.h,v
retrieving revision 1.34
diff -u -3 -p -r1.34 kpopupmenu.h
--- kpopupmenu.h	2 Nov 2004 12:44:52 -0000	1.34
+++ kpopupmenu.h	16 Dec 2004 14:40:09 -0000
@@ -229,6 +229,9 @@ public:
      */
     static int contextMenuFocusItem();
 
+    virtual void activateItemAt(int index);
+    Qt::ButtonState state() const;
+
 signals:
     /**
      * connect to this signal to be notified when a context menu is about to be shown
@@ -242,6 +245,7 @@ signals:
 protected:
     virtual void closeEvent(QCloseEvent *);
     virtual void keyPressEvent(QKeyEvent* e);
+    virtual void mouseReleaseEvent(QMouseEvent* e);
     virtual void mousePressEvent(QMouseEvent* e);
     virtual bool focusNextPrevChild( bool next );
     virtual void contextMenuEvent(QContextMenuEvent *e);
Index: ktoolbarbutton.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdeui/ktoolbarbutton.cpp,v
retrieving revision 1.81
diff -u -3 -p -r1.81 ktoolbarbutton.cpp
--- ktoolbarbutton.cpp	3 Nov 2004 16:15:17 -0000	1.81
+++ ktoolbarbutton.cpp	16 Dec 2004 14:40:09 -0000
@@ -426,11 +426,23 @@ bool KToolBarButton::eventFilter(QObject
       }
     }
 
-    if ((ev->type() == QEvent::MouseButtonPress ||
+    if (d->m_isRadio &&
+	(ev->type() == QEvent::MouseButtonPress ||
          ev->type() == QEvent::MouseButtonRelease ||
-         ev->type() == QEvent::MouseButtonDblClick) && d->m_isRadio && isOn())
+         ev->type() == QEvent::MouseButtonDblClick) && isOn())
       return true;
 
+    if(ev->type() == QEvent::MouseButtonPress)
+      if(static_cast<QMouseEvent *>(ev)->button() & Qt::MidButton)
+      {
+	emit middleClicked(d->m_id);
+	return true;
+      }
+
+    if(ev->type() == QEvent::MouseButtonRelease)
+      if(static_cast<QMouseEvent *>(ev)->button() & Qt::MidButton)
+	return true;
+
     // From Kai-Uwe Sattler <kus at iti.CS.Uni-Magdeburg.De>
     if (ev->type() == QEvent::MouseButtonDblClick)
     {
Index: ktoolbarbutton.h
===================================================================
RCS file: /home/kde/kdelibs/kdeui/ktoolbarbutton.h,v
retrieving revision 1.37
diff -u -3 -p -r1.37 ktoolbarbutton.h
--- ktoolbarbutton.h	8 Sep 2004 19:30:58 -0000	1.37
+++ ktoolbarbutton.h	16 Dec 2004 14:40:09 -0000
@@ -254,6 +254,7 @@ public:
 
 signals:
   void clicked(int);
+  void middleClicked(int);
   void doubleClicked(int);
   void pressed(int);
   void released(int);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: kio-bookmarks-wkaction-patch
Type: text/x-patch
Size: 6098 bytes
Desc: not available
URL: <https://mail.kde.org/mailman/private/kfm-devel/attachments/20041216/03b8c9b8/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: konqueror-patch
Type: text/x-patch
Size: 3156 bytes
Desc: not available
URL: <https://mail.kde.org/mailman/private/kfm-devel/attachments/20041216/03b8c9b8/attachment-0001.bin>


More information about the kfm-devel mailing list