[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kfm-devel
Subject:    Service Menus
From:       "Aaron J. Seigo" <aseigo () olympusproject ! org>
Date:       2003-05-19 5:57:08
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

hi...

attached is a patchto improve the handling of servicemenus in konqueror. it 
does three things:

 1) allows mimetype globs in the form of image/*. it's quite possible to add 
support for other forms of globbing (e.g. kdedevice/smb-*, or even full on 
REs) but i thought i'd start with this for now.

 2) puts all the actions (including the builtins) into an Actions submenu to 
help keep the size of the RMB menu down

 3) supports submenus in the Action menu. this is achieved by supporting the 
Categories .desktop field and using the first category (if any) as the 
submenu. an example servicemenu utilizing the submenu support is attached as 
well.

these things were discussed some time ago on the kde-usability list, but i've 
only now gotten around to implementing them. comments?  =)

- -- 
Aaron J. Seigo
GPG Fingerprint: 8B8B 2209 0C6F 7C47 B1EA  EE75 D6B7 2EB1 A7F1 DB43

KDE: The 'K' is for 'kick ass'
http://www.kde.org       http://promo.kde.org/3.1/feature_guide.php
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQE+yHI11rcusafx20MRAj3QAJ0ZFAblISXH/P43B8znR2nQTdGWSACePQLw
FkkzpHrKRKFCjML8HdI0W1A=
=D39x
-----END PGP SIGNATURE-----

["background.desktop" (application/x-desktop)]
["libkonq_servicemenus.diff" (text/x-diff)]

Index: konq_popupmenu.cc
===================================================================
RCS file: /home/kde/kdebase/libkonq/konq_popupmenu.cc,v
retrieving revision 1.143
diff -u -3 -d -p -b -r1.143 konq_popupmenu.cc
--- konq_popupmenu.cc	20 Mar 2003 16:27:45 -0000	1.143
+++ konq_popupmenu.cc	19 May 2003 05:46:53 -0000
@@ -44,6 +44,7 @@
 #include "konq_popupmenu.h"
 #include "konq_operations.h"
 
+
 class KonqPopupMenuGUIBuilder : public KXMLGUIBuilder
 {
 public:
@@ -132,6 +133,38 @@ KonqPopupMenu::KonqPopupMenu( KBookmarkM
   setup(showPropertiesAndFileType);
 }
 
+
+void KonqPopupMenu::insertServices(const ServiceList& list,
+                                   QDomElement& menu,
+                                   bool isBuiltin)
+{
+    static int id = 1000;
+
+    ServiceList::const_iterator it = list.begin();
+    for( ; it != list.end(); ++it )
+    {
+        if (isBuiltin || (*it).m_display == true)
+        {
+            QCString name;
+            name.setNum( id );
+            name.prepend( isBuiltin ? "builtinservice_" : "userservice_" );
+            KAction * act = new KAction( (*it).m_strName, 0,
+                                         this, SLOT( slotRunService() ),
+                                         &m_ownActions, name );
+
+            if ( !(*it).m_strIcon.isEmpty() )
+            {
+                QPixmap pix = SmallIcon( (*it).m_strIcon );
+                act->setIconSet( pix );
+            }
+
+            addAction( act, menu ); // Add to toplevel menu
+
+            m_mapPopupServices[ id++ ] = *it;
+        }
+    }
+}
+
 void KonqPopupMenu::setup(bool showPropertiesAndFileType)
 {
   assert( m_lstItems.count() >= 1 );
@@ -351,8 +384,9 @@ void KonqPopupMenu::setup(bool showPrope
 
   //////////////////////////////////////////////////////
 
-  QValueList<KDEDesktopMimeType::Service> builtin;
-  QValueList<KDEDesktopMimeType::Service> user;
+  ServiceList builtin;
+  ServiceList user;
+  QMap<QString, ServiceList> userSubmenus;
 
   // 1 - Look for builtin and user-defined services
   if ( m_sMimeType == "application/x-desktop" && m_lstItems.count() == 1 && \
m_lstItems.first()->url().isLocalFile() ) // .desktop file @@ -405,19 +439,58 @@ void \
KonqPopupMenu::setup(bool showPrope  if ( cfg.hasKey( "Actions" ) && cfg.hasKey( \
"ServiceTypes" ) )  {
               QStringList types = cfg.readListEntry( "ServiceTypes" );
-              bool ok = !m_sMimeType.isNull() && types.contains( m_sMimeType );
-              if ( !ok ) {
-                  ok = (types[0] == "all/all" ||
-                        types[0] == "allfiles" /*compat with KDE up to 3.0.3*/);
-                  if ( !ok && types[0] == "all/allfiles" )
+              bool ok = false;
+              QString mimeGroup = m_sMimeType.left(m_sMimeType.find('/'));
+
+              // check for exact matches or a typeglob'd mimetype if we have a \
mimetype +              for (QStringList::iterator it = types.begin(); it != \
types.end(); ++it)  {
-                      ok = (m_sMimeType != "inode/directory"); // ## or inherits \
from it +                  // we could cram the following three if statements into
+                  // one gigantic boolean statement but that would be a
+                  // hororr show for readability
+
+                  // first check if we have an all mimetype
+                  if (*it == "all/all" ||
+                      *it == "allfiles" /*compat with KDE up to 3.0.3*/)
+                  {
+                      ok = true;
+                      break;
                   }
+
+                  // next, do we match all files?
+                  if (*it == "all/allfiles" &&
+                      m_sMimeType != "inode/directory") // ## or inherits from it
+                  {
+                      ok = true;
+                      break;
               }
+
+                  // if we have a mimetype, see if we have an exact or type
+                  // globbed match
+                  if (!m_sMimeType.isNull() &&
+                      (*it == m_sMimeType ||
+                      ((*it).right(1) == "*" &&
+                      (*it).left((*it).find('/')) == mimeGroup)))
+                  {
+                      ok = true;
+                      break;
+                  }
+              }
+
               if ( ok )
               {
+                  // we use the categories .desktop entry to define submenus
+                  // if none is defined, we just pop it in the main menu
+                  QStringList categories = cfg.readListEntry( "Categories" );
+                  if (categories.isEmpty())
+                  {
                   user += KDEDesktopMimeType::userDefinedServices( *dIt + *eIt, \
url.isLocalFile() );  }
+                  else
+                  {
+                    userSubmenus[categories[0]] += \
KDEDesktopMimeType::userDefinedServices( *dIt + *eIt, url.isLocalFile() ); +          \
} +              }
           }
       }
   }
@@ -492,58 +565,40 @@ void KonqPopupMenu::setup(bool showPrope
 
   addGroup( "preview" );
 
-  addSeparator();
-
   // Second block, builtin + user
-  if ( !user.isEmpty() || !builtin.isEmpty() )
+  if ( !user.isEmpty() || !userSubmenus.empty() || !builtin.isEmpty() )
   {
-      bool insertedOffer = false;
+      QDomElement actionMenu = m_doc.createElement( "menu" );
+      actionMenu.setAttribute( "name", "actions submenu" );
+      m_menuElement.appendChild( actionMenu );
+      QDomElement text = m_doc.createElement( "text" );
+      actionMenu.appendChild( text );
+      text.appendChild( m_doc.createTextNode( i18n("Ac&tions") ) );
 
-      QValueList<KDEDesktopMimeType::Service>::Iterator it2 = user.begin();
-      for( ; it2 != user.end(); ++it2 )
-      {
-        if ((*it2).m_display == true)
+      QMap<QString, ServiceList>::Iterator it;
+      for (it = userSubmenus.begin(); it != userSubmenus.end(); ++it)
         {
-          QCString nam;
-          nam.setNum( id );
-          act = new KAction( (*it2).m_strName, 0, this, SLOT( slotRunService() ), \
                &m_ownActions, nam.prepend( "userservice_" ) );
-
-          if ( !(*it2).m_strIcon.isEmpty() )
+        if (it.data().isEmpty())
           {
-            QPixmap pix = SmallIcon( (*it2).m_strIcon );
-            act->setIconSet( pix );
-          }
-
-          addAction( act, m_menuElement ); // Add to toplevel menu
-
-          m_mapPopupServices[ id++ ] = *it2;
-          insertedOffer = true;
-        }
+          //avoid empty sub-menus
+          continue;
       }
 
-      it2 = builtin.begin();
-      for( ; it2 != builtin.end(); ++it2 )
-      {
-        QCString nam;
-        nam.setNum( id );
-
-        act = new KAction( (*it2).m_strName, 0, this, SLOT( slotRunService() ), \
                &m_ownActions, nam.prepend( "builtinservice_" ) );
-
-        if ( !(*it2).m_strIcon.isEmpty() )
-        {
-          QPixmap pix = SmallIcon( (*it2).m_strIcon );
-          act->setIconSet( pix );
+        QDomElement actionSubmenu = m_doc.createElement( "menu" );
+        actionSubmenu.setAttribute( "name", "actions " + it.key() );
+        actionMenu.appendChild( actionSubmenu );
+        QDomElement subtext = m_doc.createElement( "text" );
+        actionSubmenu.appendChild( subtext );
+        subtext.appendChild( m_doc.createTextNode( it.key() ) );
+        insertServices(it.data(), actionSubmenu, false);
         }
 
-        addAction( act, m_menuElement );
-
-        m_mapPopupServices[ id++ ] = *it2;
-        insertedOffer = true;
+      insertServices(user, actionMenu, false);
+      insertServices(builtin, actionMenu, true);
       }
 
-      if ( insertedOffer )
         addSeparator();
-  }
+
   if ( !isCurrentTrash )
       addPlugins( ); // now it's time to add plugins
 
Index: konq_popupmenu.h
===================================================================
RCS file: /home/kde/kdebase/libkonq/konq_popupmenu.h,v
retrieving revision 1.41
diff -u -3 -d -p -b -r1.41 konq_popupmenu.h
--- konq_popupmenu.h	20 Nov 2002 11:35:24 -0000	1.41
+++ konq_popupmenu.h	19 May 2003 05:46:54 -0000
@@ -34,6 +34,8 @@
 
 #include "konq_xmlguiclient.h"
 
+typedef QValueList<KDEDesktopMimeType::Service> ServiceList;
+
 class KNewMenu;
 class KService;
 class KonqPopupMenuPlugin;
@@ -134,6 +136,7 @@ protected:
 private:
   void setup(bool showPropertiesAndFileType);
   void addPlugins( );
+  void insertServices(const ServiceList& list, QDomElement& menu, bool isBuiltin);
   class KonqPopupMenuPrivate;
   KonqPopupMenuPrivate *d;
   KNewMenu *m_pMenuNew;



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic