libkonq Library API Documentation

konq_popupmenu.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 David Faure <faure@kde.org>
00003    Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 
00021 #include <qdir.h>
00022 
00023 #include <klocale.h>
00024 #include <kapplication.h>
00025 #include <kbookmarkmanager.h>
00026 #include <kdebug.h>
00027 #include <krun.h>
00028 #include <kprotocolinfo.h>
00029 #include <kiconloader.h>
00030 #include <kinputdialog.h>
00031 #include <kglobalsettings.h>
00032 #include <kstandarddirs.h>
00033 #include <kxmlguifactory.h>
00034 #include <kxmlguibuilder.h>
00035 #include <kparts/componentfactory.h>
00036 
00037 #include <assert.h>
00038 
00039 #include <kfileshare.h>
00040 #include <kprocess.h>
00041 
00042 #include "kpropertiesdialog.h"
00043 #include "knewmenu.h"
00044 #include "konq_popupmenu.h"
00045 #include "konq_operations.h"
00046 #include <dcopclient.h>
00047 
00048 /*
00049  Test cases:
00050   iconview file: background
00051   iconview file: file (with and without servicemenus)
00052   iconview file: directory
00053   iconview remote protocol (e.g. ftp: or fish:)
00054   iconview trash:/
00055   sidebar directory tree
00056   sidebar Devices / Hard Disc
00057   khtml background
00058   khtml link
00059   khtml image (www.kde.org RMB on K logo)
00060   khtmlimage (same as above, then choose View image, then RMB)
00061   selected text in khtml
00062   embedded katepart
00063   kdesktop folder
00064   trash link on desktop
00065   trashed file or directory
00066   application .desktop file
00067  Then the same after uninstalling kdeaddons/konq-plugins (kuick and arkplugin in particular)
00068 */
00069 
00070 class KonqPopupMenuGUIBuilder : public KXMLGUIBuilder
00071 {
00072 public:
00073   KonqPopupMenuGUIBuilder( QPopupMenu *menu )
00074   : KXMLGUIBuilder( 0 )
00075   {
00076     m_menu = menu;
00077   }
00078   virtual ~KonqPopupMenuGUIBuilder()
00079   {
00080   }
00081 
00082   virtual QWidget *createContainer( QWidget *parent, int index,
00083           const QDomElement &element,
00084           int &id )
00085   {
00086     if ( !parent && element.attribute( "name" ) == "popupmenu" )
00087       return m_menu;
00088 
00089     return KXMLGUIBuilder::createContainer( parent, index, element, id );
00090   }
00091 
00092   QPopupMenu *m_menu;
00093 };
00094 
00095 class KonqPopupMenu::KonqPopupMenuPrivate
00096 {
00097 public:
00098   KonqPopupMenuPrivate() : m_parentWidget( 0 ),
00099                            m_itemFlags( KParts::BrowserExtension::DefaultPopupItems )
00100   {
00101   }
00102   QString m_urlTitle;
00103   QWidget *m_parentWidget;
00104   KParts::BrowserExtension::PopupFlags m_itemFlags;
00105 };
00106 
00107 KonqPopupMenu::ProtocolInfo::ProtocolInfo()
00108 {
00109   m_Reading = false;
00110   m_Writing = false;
00111   m_Deleting = false;
00112   m_Moving = false;
00113   m_TrashIncluded = false;
00114 }
00115 
00116 bool KonqPopupMenu::ProtocolInfo::supportsReading() const
00117 {
00118   return m_Reading;
00119 }
00120 
00121 bool KonqPopupMenu::ProtocolInfo::supportsWriting() const
00122 {
00123   return m_Writing;
00124 }
00125 
00126 bool KonqPopupMenu::ProtocolInfo::supportsDeleting() const
00127 {
00128   return m_Deleting;
00129 }
00130 
00131 bool KonqPopupMenu::ProtocolInfo::supportsMoving() const
00132 {
00133   return m_Moving;
00134 }
00135 
00136 bool KonqPopupMenu::ProtocolInfo::trashIncluded() const
00137 {
00138   return m_TrashIncluded;
00139 }
00140 
00141 // This helper class stores the .desktop-file actions and the servicemenus
00142 // in order to support X-KDE-Priority and X-KDE-Submenu.
00143 class PopupServices
00144 {
00145 public:
00146     ServiceList* selectList( const QString& priority, const QString& submenuName );
00147 
00148     ServiceList builtin;
00149     ServiceList user, userToplevel, userPriority;
00150     QMap<QString, ServiceList> userSubmenus, userToplevelSubmenus, userPrioritySubmenus;
00151 };
00152 
00153 ServiceList* PopupServices::selectList( const QString& priority, const QString& submenuName )
00154 {
00155     // we use the categories .desktop entry to define submenus
00156     // if none is defined, we just pop it in the main menu
00157     if (submenuName.isEmpty())
00158     {
00159         if (priority == "TopLevel")
00160         {
00161             return &userToplevel;
00162         }
00163         else if (priority == "Important")
00164         {
00165             return &userPriority;
00166         }
00167     }
00168     else if (priority == "TopLevel")
00169     {
00170         return &(userToplevelSubmenus[submenuName]);
00171     }
00172     else if (priority == "Important")
00173     {
00174         return &(userPrioritySubmenus[submenuName]);
00175     }
00176     else
00177     {
00178         return &(userSubmenus[submenuName]);
00179     }
00180     return &user;
00181 }
00182 
00184 
00185 KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
00186                               KURL viewURL,
00187                               KActionCollection & actions,
00188                               KNewMenu * newMenu,
00189                               bool showProperties )
00190     : QPopupMenu( 0L, "konq_popupmenu" ),
00191       m_actions( actions ), m_ownActions( static_cast<QWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ),
00192           m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
00193 {
00194     KonqPopupFlags kpf = ( showProperties ? ShowProperties : IsLink ) | ShowNewWindow;
00195     init(0, kpf, KParts::BrowserExtension::DefaultPopupItems);
00196 }
00197 
00198 KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
00199                               KURL viewURL,
00200                               KActionCollection & actions,
00201                               KNewMenu * newMenu,
00202                               QWidget * parentWidget,
00203                               bool showProperties )
00204     : QPopupMenu( parentWidget, "konq_popupmenu" ), m_actions( actions ), m_ownActions( static_cast<QWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ), m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
00205 {
00206     KonqPopupFlags kpf = ( showProperties ? ShowProperties : IsLink ) | ShowNewWindow;
00207     init(parentWidget, kpf, KParts::BrowserExtension::DefaultPopupItems);
00208 }
00209 
00210 KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
00211                               const KURL& viewURL,
00212                               KActionCollection & actions,
00213                               KNewMenu * newMenu,
00214                               QWidget * parentWidget,
00215                               KonqPopupFlags kpf,
00216                               KParts::BrowserExtension::PopupFlags flags)
00217   : QPopupMenu( parentWidget, "konq_popupmenu" ), m_actions( actions ), m_ownActions( static_cast<QWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ), m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
00218 {
00219     init(parentWidget, kpf, flags);
00220 }
00221 
00222 void KonqPopupMenu::init (QWidget * parentWidget, KonqPopupFlags kpf, KParts::BrowserExtension::PopupFlags flags)
00223 {
00224     d = new KonqPopupMenuPrivate;
00225     d->m_parentWidget = parentWidget;
00226     d->m_itemFlags = flags;
00227     setup(kpf);
00228 }
00229 
00230 int KonqPopupMenu::insertServicesSubmenus(const QMap<QString, ServiceList>& submenus,
00231                                           QDomElement& menu,
00232                                           bool isBuiltin)
00233 {
00234     int count = 0;
00235     QMap<QString, ServiceList>::ConstIterator it;
00236 
00237     for (it = submenus.begin(); it != submenus.end(); ++it)
00238     {
00239         if (it.data().isEmpty())
00240         {
00241             //avoid empty sub-menus
00242             continue;
00243         }
00244 
00245         QDomElement actionSubmenu = m_doc.createElement( "menu" );
00246         actionSubmenu.setAttribute( "name", "actions " + it.key() );
00247         menu.appendChild( actionSubmenu );
00248         QDomElement subtext = m_doc.createElement( "text" );
00249         actionSubmenu.appendChild( subtext );
00250         subtext.appendChild( m_doc.createTextNode( it.key() ) );
00251         count += insertServices(it.data(), actionSubmenu, isBuiltin);
00252     }
00253 
00254     return count;
00255 }
00256 
00257 int KonqPopupMenu::insertServices(const ServiceList& list,
00258                                   QDomElement& menu,
00259                                   bool isBuiltin)
00260 {
00261     static int id = 1000;
00262     int count = 0;
00263 
00264     ServiceList::const_iterator it = list.begin();
00265     for( ; it != list.end(); ++it )
00266     {
00267         if ((*it).isEmpty())
00268         {
00269             if (!menu.firstChild().isNull() &&
00270                 menu.lastChild().toElement().tagName().lower() != "separator")
00271             {
00272                 QDomElement separator = m_doc.createElement( "separator" );
00273                 menu.appendChild(separator);
00274             }
00275             continue;
00276         }
00277 
00278         if (isBuiltin || (*it).m_display == true)
00279         {
00280             QCString name;
00281             name.setNum( id );
00282             name.prepend( isBuiltin ? "builtinservice_" : "userservice_" );
00283             KAction * act = new KAction( (*it).m_strName, 0,
00284                                          this, SLOT( slotRunService() ),
00285                                          &m_ownActions, name );
00286 
00287             if ( !(*it).m_strIcon.isEmpty() )
00288             {
00289                 QPixmap pix = SmallIcon( (*it).m_strIcon );
00290                 act->setIconSet( pix );
00291             }
00292 
00293             addAction( act, menu ); // Add to toplevel menu
00294 
00295             m_mapPopupServices[ id++ ] = *it;
00296             ++count;
00297         }
00298     }
00299 
00300     return count;
00301 }
00302 
00303 bool KonqPopupMenu::KIOSKAuthorizedAction(KConfig& cfg)
00304 {
00305     if ( !cfg.hasKey( "X-KDE-AuthorizeAction") )
00306     {
00307         return true;
00308     }
00309 
00310     QStringList list = cfg.readListEntry("X-KDE-AuthorizeAction");
00311     if (kapp && !list.isEmpty())
00312     {
00313         for(QStringList::ConstIterator it = list.begin();
00314             it != list.end();
00315             ++it)
00316         {
00317             if (!kapp->authorize((*it).stripWhiteSpace()))
00318             {
00319                 return false;
00320             }
00321         }
00322     }
00323 
00324     return true;
00325 }
00326 
00327 
00328 void KonqPopupMenu::setup(KonqPopupFlags kpf)
00329 {
00330     assert( m_lstItems.count() >= 1 );
00331 
00332     m_ownActions.setWidget( this );
00333 
00334     const bool bIsLink  = (kpf & IsLink);
00335     bool currentDir     = false;
00336     bool sReading       = true;
00337     bool sDeleting      = ( d->m_itemFlags & KParts::BrowserExtension::NoDeletion ) == 0;
00338     bool sMoving        = sDeleting;
00339     bool sWriting       = sDeleting && m_lstItems.first()->isWritable();
00340     m_sMimeType         = m_lstItems.first()->mimetype();
00341     QString mimeGroup   = m_sMimeType.left(m_sMimeType.find('/'));
00342     mode_t mode         = m_lstItems.first()->mode();
00343     bool isDirectory    = S_ISDIR(mode);
00344     bool bTrashIncluded = false;
00345     bool mediaFiles     = false;
00346     bool isLocal        = m_lstItems.first()->isLocalFile();
00347     bool isTrashLink     = false;
00348     m_lstPopupURLs.clear();
00349     int id = 0;
00350     setFont(KGlobalSettings::menuFont());
00351     m_pluginList.setAutoDelete( true );
00352     m_ownActions.setHighlightingEnabled( true );
00353 
00354     attrName = QString::fromLatin1( "name" );
00355 
00356     prepareXMLGUIStuff();
00357     m_builder = new KonqPopupMenuGUIBuilder( this );
00358     m_factory = new KXMLGUIFactory( m_builder );
00359 
00360     KURL url;
00361     KFileItemListIterator it ( m_lstItems );
00362     QStringList mimeTypeList;
00363     // Check whether all URLs are correct
00364     for ( ; it.current(); ++it )
00365     {
00366         url = (*it)->mostLocalURL(isLocal);
00367 
00368         // Build the list of URLs
00369         m_lstPopupURLs.append( url );
00370 
00371         // Determine if common mode among all URLs
00372         if ( mode != (*it)->mode() )
00373             mode = 0; // modes are different => reset to 0
00374 
00375         // Determine if common mimetype among all URLs
00376         if ( m_sMimeType != (*it)->mimetype() )
00377         {
00378             m_sMimeType = QString::null; // mimetypes are different => null
00379 
00380             if ( mimeGroup != (*it)->mimetype().left((*it)->mimetype().find('/')))
00381                 mimeGroup = QString::null; // mimetype groups are different as well!
00382         }
00383 
00384         if ( mimeTypeList.findIndex( (*it)->mimetype() ) == -1 )
00385             mimeTypeList << (*it)->mimetype();
00386 
00387         if ( isLocal && !url.isLocalFile() )
00388             isLocal = false;
00389 
00390         if ( !bTrashIncluded &&
00391              (*it)->url().protocol() == "trash" &&
00392              (*it)->url().path().length() <= 1 )
00393             bTrashIncluded = true;
00394 
00395         if ( sReading )
00396             sReading = KProtocolInfo::supportsReading( url );
00397 
00398         if ( sWriting )
00399             sWriting = KProtocolInfo::supportsWriting( url ) && (*it)->isWritable();
00400 
00401         if ( sDeleting )
00402             sDeleting = KProtocolInfo::supportsDeleting( url );
00403 
00404         if ( sMoving )
00405             sMoving = KProtocolInfo::supportsMoving( url );
00406         if ( (*it)->mimetype().startsWith("media/") )
00407             mediaFiles = true;
00408     }
00409     url = m_sViewURL;
00410     url.cleanPath();
00411 
00412     //check if url is current directory
00413     if ( m_lstItems.count() == 1 )
00414     {
00415         KURL firstPopupURL( m_lstItems.first()->url() );
00416         firstPopupURL.cleanPath();
00417         //kdDebug(1203) << "View path is " << url.url() << endl;
00418         //kdDebug(1203) << "First popup path is " << firstPopupURL.url() << endl;
00419         currentDir = firstPopupURL.equals( url, true /* ignore_trailing */ );
00420         if ( isLocal && m_sMimeType == "application/x-desktop" ) {
00421             KSimpleConfig cfg( firstPopupURL.path(), true );
00422             cfg.setDesktopGroup();
00423             isTrashLink = ( cfg.readEntry("Type") == "Link" && cfg.readEntry("URL") == "trash:/" );
00424             if ( isTrashLink ) {
00425                 sDeleting = false;
00426             }
00427         }
00428     }
00429     const bool isSingleLocal = m_lstItems.count() == 1 && isLocal;
00430 
00431     m_info.m_Reading = sReading;
00432     m_info.m_Writing = sWriting;
00433     m_info.m_Deleting = sDeleting;
00434     m_info.m_Moving = sMoving;
00435     m_info.m_TrashIncluded = bTrashIncluded;
00436 
00437     // isCurrentTrash: popup on trash:/ itself, or on the trash.desktop link
00438     bool isCurrentTrash = ( m_lstItems.count() == 1 && bTrashIncluded ) || isTrashLink;
00439     bool isIntoTrash = url.protocol() == "trash" && !isCurrentTrash; // trashed file, not trash:/ itself
00440     bool isSingleMedium = m_lstItems.count() == 1 && mediaFiles;
00441     clear();
00442 
00444 
00445     KAction * act;
00446 
00447     if (!isCurrentTrash)
00448         addMerge( "konqueror" );
00449 
00450     bool isKDesktop = QCString( kapp->name() ) == "kdesktop";
00451     KAction *actNewWindow = 0;
00452 
00453     if (( kpf & ShowProperties ) && isKDesktop &&
00454         !kapp->authorize("editable_desktop_icons"))
00455     {
00456         kpf &= ~ShowProperties; // remove flag
00457     }
00458 
00459     // Either 'newview' is in the actions we're given (probably in the tabhandling group)
00460     // or we need to insert it ourselves (e.g. for kdesktop). In the first case, actNewWindow must remain 0.
00461     if ( ((kpf & ShowNewWindow) != 0) && sReading )
00462     {
00463         QString openStr = isKDesktop ? i18n( "&Open" ) : i18n( "Open in New &Window" );
00464         actNewWindow = new KAction( openStr, "window_new", 0, this, SLOT( slotPopupNewView() ), &m_ownActions, "newview" );
00465     }
00466 
00467     if ( actNewWindow && !isKDesktop )
00468     {
00469         if (isCurrentTrash)
00470             actNewWindow->setToolTip( i18n( "Open the trash in a new window" ) );
00471         else if (isSingleMedium)
00472             actNewWindow->setToolTip( i18n( "Open the medium in a new window") );
00473         else
00474             actNewWindow->setToolTip( i18n( "Open the document in a new window" ) );
00475     }
00476 
00477     if ( S_ISDIR(mode) && sWriting && !isCurrentTrash ) // A dir, and we can create things into it
00478     {
00479         if ( currentDir && m_pMenuNew ) // Current dir -> add the "new" menu
00480         {
00481             // As requested by KNewMenu :
00482             m_pMenuNew->slotCheckUpToDate();
00483             m_pMenuNew->setPopupFiles( m_lstPopupURLs );
00484 
00485             addAction( m_pMenuNew );
00486 
00487             addSeparator();
00488         }
00489         else
00490         {
00491             if (d->m_itemFlags & KParts::BrowserExtension::ShowCreateDirectory)
00492             {
00493                 KAction *actNewDir = new KAction( i18n( "Create &Folder..." ), "folder_new", 0, this, SLOT( slotPopupNewDir() ), &m_ownActions, "newdir" );
00494                 addAction( actNewDir );
00495                 addSeparator();
00496             }
00497         }
00498     } else if ( isIntoTrash ) {
00499         // Trashed item, offer restoring
00500         act = new KAction( i18n( "&Restore" ), 0, this, SLOT( slotPopupRestoreTrashedItems() ), &m_ownActions, "restore" );
00501         addAction( act );
00502     }
00503 
00504     if (d->m_itemFlags & KParts::BrowserExtension::ShowNavigationItems)
00505     {
00506         addAction( "back" );
00507         addAction( "forward" );
00508         if (d->m_itemFlags & KParts::BrowserExtension::ShowUp)
00509             addAction( "up" );
00510         if (d->m_itemFlags & KParts::BrowserExtension::ShowReload)
00511             addAction( "reload" );
00512         addSeparator();
00513     }
00514 
00515     // "open in new window" is either provided by us, or by the tabhandling group
00516     if (actNewWindow)
00517     {
00518         addAction( actNewWindow );
00519         addSeparator();
00520     }
00521     addGroup( "tabhandling" ); // includes a separator
00522 
00523     if ( !bIsLink )
00524     {
00525         if ( !currentDir && sReading ) {
00526             if ( sDeleting ) {
00527                 addAction( "cut" );
00528             }
00529             addAction( "copy" );
00530         }
00531 
00532         if ( S_ISDIR(mode) && sWriting ) {
00533             if ( currentDir )
00534                 addAction( "paste" );
00535             else
00536                 addAction( "pasteto" );
00537         }
00538         if ( !currentDir )
00539         {
00540             if ( m_lstItems.count() == 1 && sMoving )
00541                 addAction( "rename" );
00542 
00543             bool addTrash = false;
00544             bool addDel = false;
00545 
00546             if ( sMoving && !isIntoTrash && !isTrashLink )
00547                 addTrash = true;
00548 
00549             if ( sDeleting ) {
00550                 if ( !isLocal )
00551                     addDel = true;
00552                 else if (KApplication::keyboardMouseState() & Qt::ShiftButton) {
00553                     addTrash = false;
00554                     addDel = true;
00555                 }
00556                 else {
00557                     KConfigGroup configGroup( kapp->config(), "KDE" );
00558                     if ( configGroup.readBoolEntry( "ShowDeleteCommand", false ) )
00559                         addDel = true;
00560                 }
00561             }
00562 
00563             if ( addTrash )
00564                 addAction( "trash" );
00565             if ( addDel )
00566                 addAction( "del" );
00567         }
00568     }
00569     if ( isCurrentTrash )
00570     {
00571         act = new KAction( i18n( "&Empty Trash Bin" ), "emptytrash", 0, this, SLOT( slotPopupEmptyTrashBin() ), &m_ownActions, "empytrash" );
00572         addAction( act );
00573     }
00574     addGroup( "editactions" );
00575 
00576     if (d->m_itemFlags & KParts::BrowserExtension::ShowTextSelectionItems) {
00577       addMerge( 0 );
00578       m_factory->addClient( this );
00579       return;
00580     }
00581 
00582     if ( !isCurrentTrash && !isIntoTrash && (d->m_itemFlags & KParts::BrowserExtension::ShowBookmark))
00583     {
00584         addSeparator();
00585         QString caption;
00586         if (currentDir)
00587         {
00588            bool httpPage = (m_sViewURL.protocol().find("http", 0, false) == 0);
00589            if (httpPage)
00590               caption = i18n("&Bookmark This Page");
00591            else
00592               caption = i18n("&Bookmark This Location");
00593         }
00594         else if (S_ISDIR(mode))
00595            caption = i18n("&Bookmark This Folder");
00596         else if (bIsLink)
00597            caption = i18n("&Bookmark This Link");
00598         else
00599            caption = i18n("&Bookmark This File");
00600 
00601         act = new KAction( caption, "bookmark_add", 0, this, SLOT( slotPopupAddToBookmark() ), &m_ownActions, "bookmark_add" );
00602         if (m_lstItems.count() > 1)
00603             act->setEnabled(false);
00604         if (kapp->authorizeKAction("bookmarks"))
00605             addAction( act );
00606         if (bIsLink)
00607             addGroup( "linkactions" );
00608     }
00609 
00611 
00612     PopupServices s;
00613     KURL urlForServiceMenu( m_lstItems.first()->url() );
00614 
00615     // 1 - Look for builtin and user-defined services
00616     if ( m_sMimeType == "application/x-desktop" && isSingleLocal ) // .desktop file
00617     {
00618         // get builtin services, like mount/unmount
00619         s.builtin = KDEDesktopMimeType::builtinServices( m_lstItems.first()->url() );
00620         const QString path = m_lstItems.first()->url().path();
00621         KSimpleConfig cfg( path, true );
00622         cfg.setDesktopGroup();
00623         const QString priority = cfg.readEntry("X-KDE-Priority");
00624         const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
00625         if ( cfg.readEntry("Type") == "Link" ) {
00626            urlForServiceMenu = cfg.readEntry("URL");
00627            // TODO: Do we want to make all the actions apply on the target
00628            // of the .desktop file instead of the .desktop file itself?
00629         }
00630         ServiceList* list = s.selectList( priority, submenuName );
00631         (*list) = KDEDesktopMimeType::userDefinedServices( path, cfg, url.isLocalFile() );
00632     }
00633 
00634     if ( sReading )
00635     {
00636 
00637         // 2 - Look for "servicesmenus" bindings (konqueror-specific user-defined services)
00638 
00639         // first check the .directory if this is a directory
00640         if (isDirectory && isSingleLocal)
00641         {
00642             QString dotDirectoryFile = m_lstItems.first()->url().path(1).append(".directory");
00643             KSimpleConfig cfg( dotDirectoryFile, true );
00644             cfg.setDesktopGroup();
00645 
00646             if (KIOSKAuthorizedAction(cfg))
00647             {
00648                 const QString priority = cfg.readEntry("X-KDE-Priority");
00649                 const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
00650                 ServiceList* list = s.selectList( priority, submenuName );
00651                 (*list) += KDEDesktopMimeType::userDefinedServices( dotDirectoryFile, cfg, true );
00652             }
00653         }
00654 
00655         QStringList dirs = KGlobal::dirs()->findDirs( "data", "konqueror/servicemenus/" );
00656         QStringList::ConstIterator dIt = dirs.begin();
00657         QStringList::ConstIterator dEnd = dirs.end();
00658 
00659         for (; dIt != dEnd; ++dIt )
00660         {
00661             QDir dir( *dIt );
00662 
00663             QStringList entries = dir.entryList( "*.desktop", QDir::Files );
00664             QStringList::ConstIterator eIt = entries.begin();
00665             QStringList::ConstIterator eEnd = entries.end();
00666 
00667             for (; eIt != eEnd; ++eIt )
00668             {
00669                 KSimpleConfig cfg( *dIt + *eIt, true );
00670                 cfg.setDesktopGroup();
00671 
00672                 if (!KIOSKAuthorizedAction(cfg))
00673                 {
00674                     continue;
00675                 }
00676 
00677                 if ( cfg.hasKey( "X-KDE-ShowIfRunning" ) )
00678                 {
00679                     const QString app = cfg.readEntry( "X-KDE-ShowIfRunning" );
00680                     if ( !kapp->dcopClient()->isApplicationRegistered( app.utf8() ) )
00681                         continue;
00682                 }
00683 
00684                 if ( cfg.hasKey( "X-KDE-Protocol" ) )
00685                 {
00686                     const QString protocol = cfg.readEntry( "X-KDE-Protocol" );
00687                     if ( protocol != urlForServiceMenu.protocol() )
00688                         continue;
00689                 }
00690                 else if ( urlForServiceMenu.protocol() == "trash" )
00691                 {
00692                     // Require servicemenus for the trash to ask for protocol=trash explicitely.
00693                     // Trashed files aren't supposed to be available for actions.
00694                     // One might want a servicemenu for trash.desktop itself though.
00695                     continue;
00696                 }
00697 
00698                 if ( cfg.hasKey( "X-KDE-Require" ) )
00699                 {
00700                     const QStringList capabilities = cfg.readListEntry( "X-KDE-Require" );
00701                     if ( capabilities.contains( "Write" ) && !sWriting )
00702                         continue;
00703                 }
00704 
00705                 if ( cfg.hasKey( "Actions" ) && cfg.hasKey( "ServiceTypes" ) )
00706                 {
00707                     const QStringList types = cfg.readListEntry( "ServiceTypes" );
00708                     const QStringList excludeTypes = cfg.readListEntry( "ExcludeServiceTypes" );
00709                     bool ok = false;
00710 
00711                     // check for exact matches or a typeglob'd mimetype if we have a mimetype
00712                     for (QStringList::ConstIterator it = types.begin();
00713                          it != types.end() && !ok;
00714                          ++it)
00715                     {
00716                         // first check if we have an all mimetype
00717                         bool checkTheMimetypes = false;
00718                         if (*it == "all/all" ||
00719                             *it == "allfiles" /*compat with KDE up to 3.0.3*/)
00720                         {
00721                             checkTheMimetypes = true;
00722                         }
00723 
00724                         // next, do we match all files?
00725                         if (!ok &&
00726                             !isDirectory &&
00727                             *it == "all/allfiles")
00728                         {
00729                             checkTheMimetypes = true;
00730                         }
00731 
00732                         // if we have a mimetype, see if we have an exact or a type globbed match
00733                         if (!ok &&
00734                             (!m_sMimeType.isEmpty() &&
00735                               *it == m_sMimeType) ||
00736                             (!mimeGroup.isEmpty() &&
00737                              ((*it).right(1) == "*" &&
00738                               (*it).left((*it).find('/')) == mimeGroup)))
00739                         {
00740                             checkTheMimetypes = true;
00741                         }
00742 
00743                         if (checkTheMimetypes)
00744                         {
00745                             ok = true;
00746                             for (QStringList::ConstIterator itex = excludeTypes.begin(); itex != excludeTypes.end(); ++itex)
00747                             {
00748                                 if( ((*itex).right(1) == "*" && (*itex).left((*itex).find('/')) == mimeGroup) ||
00749                                     ((*itex) == m_sMimeType) )
00750                                 {
00751                                     ok = false;
00752                                     break;
00753                                 }
00754                             }
00755                         }
00756                     }
00757 
00758                     if ( ok )
00759                     {
00760                         const QString priority = cfg.readEntry("X-KDE-Priority");
00761                         const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
00762                         ServiceList* list = s.selectList( priority, submenuName );
00763                         (*list) += KDEDesktopMimeType::userDefinedServices( *dIt + *eIt, cfg, url.isLocalFile() );
00764                     }
00765                 }
00766             }
00767         }
00768 
00769         KTrader::OfferList offers;
00770 
00771         if (kapp->authorizeKAction("openwith"))
00772         {
00773             QString constraint = "Type == 'Application' and DesktopEntryName != 'kfmclient' and DesktopEntryName != 'kfmclient_dir' and DesktopEntryName != 'kfmclient_html'";
00774             QString subConstraint = " and '%1' in ServiceTypes";
00775 
00776             QStringList::ConstIterator it = mimeTypeList.begin();
00777             QStringList::ConstIterator end = mimeTypeList.end();
00778             Q_ASSERT( it != end );
00779             QString first = *it;
00780             ++it;
00781             while ( it != end ) {
00782                 constraint += subConstraint.arg( *it );
00783                 ++it;
00784             }
00785 
00786             offers = KTrader::self()->query( first, constraint );
00787         }
00788 
00790 
00791         m_mapPopup.clear();
00792         m_mapPopupServices.clear();
00793         // "Open With..." for folders is really not very useful, especially for remote folders.
00794         // (media:/something, or trash:/, or ftp://...)
00795         if ( !isDirectory || isLocal )
00796         {
00797             if ( hasAction() )
00798                 addSeparator();
00799 
00800             if ( !offers.isEmpty() )
00801             {
00802                 // First block, app and preview offers
00803                 id = 1;
00804 
00805                 QDomElement menu = m_menuElement;
00806 
00807                 if ( offers.count() > 1 ) // submenu 'open with'
00808                 {
00809                     menu = m_doc.createElement( "menu" );
00810                     menu.setAttribute( "name", "openwith submenu" );
00811                     m_menuElement.appendChild( menu );
00812                     QDomElement text = m_doc.createElement( "text" );
00813                     menu.appendChild( text );
00814                     text.appendChild( m_doc.createTextNode( i18n("&Open With") ) );
00815                 }
00816 
00817                 if ( menu == m_menuElement ) // no submenu -> open with... above the single offer
00818                 {
00819                     KAction *openWithAct = new KAction( i18n( "&Open With..." ), 0, this, SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" );
00820                     addAction( openWithAct, menu );
00821                 }
00822 
00823                 KTrader::OfferList::ConstIterator it = offers.begin();
00824                 for( ; it != offers.end(); it++ )
00825                 {
00826                     QCString nam;
00827                     nam.setNum( id );
00828 
00829                     act = new KAction( (*it)->name(), (*it)->pixmap( KIcon::Small ), 0,
00830                                        this, SLOT( slotRunService() ),
00831                                        &m_ownActions, nam.prepend( "appservice_" ) );
00832                     addAction( act, menu );
00833 
00834                     m_mapPopup[ id++ ] = *it;
00835                 }
00836 
00837                 if ( menu != m_menuElement ) // submenu
00838                 {
00839                     addSeparator( menu );
00840                     KAction *openWithAct = new KAction( i18n( "&Other..." ), 0, this, SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" );
00841                     addAction( openWithAct, menu ); // Other...
00842                 }
00843             }
00844             else // no app offers -> Open With...
00845             {
00846                 act = new KAction( i18n( "&Open With..." ), 0, this, SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" );
00847                 addAction( act );
00848             }
00849 
00850         }
00851         addGroup( "preview" );
00852     }
00853 
00854     // Second block, builtin + user
00855     QDomElement actionMenu = m_menuElement;
00856     int userItemCount = 0;
00857     if (s.user.count() + s.userSubmenus.count() +
00858         s.userPriority.count() + s.userPrioritySubmenus.count() > 1)
00859     {
00860         // we have more than one item, so let's make a submenu
00861         actionMenu = m_doc.createElement( "menu" );
00862         actionMenu.setAttribute( "name", "actions submenu" );
00863         m_menuElement.appendChild( actionMenu );
00864         QDomElement text = m_doc.createElement( "text" );
00865         actionMenu.appendChild( text );
00866         text.appendChild( m_doc.createTextNode( i18n("Ac&tions") ) );
00867     }
00868 
00869     userItemCount += insertServicesSubmenus(s.userPrioritySubmenus, actionMenu, false);
00870     userItemCount += insertServices(s.userPriority, actionMenu, false);
00871 
00872     // see if we need to put a separator between our priority items and our regular items
00873     if (userItemCount > 0 &&
00874         (s.user.count() > 0 ||
00875          s.userSubmenus.count() > 0 ||
00876          s.builtin.count() > 0) &&
00877          actionMenu.lastChild().toElement().tagName().lower() != "separator")
00878     {
00879         QDomElement separator = m_doc.createElement( "separator" );
00880         actionMenu.appendChild(separator);
00881     }
00882 
00883     userItemCount += insertServicesSubmenus(s.userSubmenus, actionMenu, false);
00884     userItemCount += insertServices(s.user, actionMenu, false);
00885     userItemCount += insertServices(s.builtin, m_menuElement, true);
00886 
00887     userItemCount += insertServicesSubmenus(s.userToplevelSubmenus, m_menuElement, false);
00888     userItemCount += insertServices(s.userToplevel, m_menuElement, false);
00889 
00890     if ( userItemCount > 0 )
00891     {
00892         addPendingSeparator();
00893     }
00894 
00895     if ( !isCurrentTrash && !isIntoTrash && !mediaFiles && sReading )
00896         addPlugins(); // now it's time to add plugins
00897 
00898     if ( KPropertiesDialog::canDisplay( m_lstItems ) && (kpf & ShowProperties) )
00899     {
00900         act = new KAction( i18n( "&Properties" ), 0, this, SLOT( slotPopupProperties() ),
00901                            &m_ownActions, "properties" );
00902         addAction( act );
00903     }
00904 
00905     while ( !m_menuElement.lastChild().isNull() &&
00906             m_menuElement.lastChild().toElement().tagName().lower() == "separator" )
00907         m_menuElement.removeChild( m_menuElement.lastChild() );
00908 
00909     if ( isDirectory && isLocal )
00910     {
00911         if ( KFileShare::authorization() == KFileShare::Authorized )
00912         {
00913             addSeparator();
00914             act = new KAction( i18n("Share"), 0, this, SLOT( slotOpenShareFileDialog() ),
00915                                &m_ownActions, "sharefile" );
00916             addAction( act );
00917         }
00918     }
00919 
00920     addMerge( 0 );
00921     //kdDebug() << k_funcinfo << domDocument().toString() << endl;
00922 
00923     m_factory->addClient( this );
00924 }
00925 
00926 void KonqPopupMenu::slotOpenShareFileDialog()
00927 {
00928     KPropertiesDialog* dlg = showPropertiesDialog();
00929     dlg->showFileSharingPage();
00930 }
00931 
00932 KonqPopupMenu::~KonqPopupMenu()
00933 {
00934   m_pluginList.clear();
00935   delete m_factory;
00936   delete m_builder;
00937   delete d;
00938   //kdDebug(1203) << "~KonqPopupMenu leave" << endl;
00939 }
00940 
00941 void KonqPopupMenu::setURLTitle( const QString& urlTitle )
00942 {
00943     d->m_urlTitle = urlTitle;
00944 }
00945 
00946 void KonqPopupMenu::slotPopupNewView()
00947 {
00948   KURL::List::ConstIterator it = m_lstPopupURLs.begin();
00949   for ( ; it != m_lstPopupURLs.end(); it++ )
00950     (void) new KRun(*it);
00951 }
00952 
00953 void KonqPopupMenu::slotPopupNewDir()
00954 {
00955   if (m_lstPopupURLs.empty())
00956     return;
00957 
00958   KonqOperations::newDir(d->m_parentWidget, m_lstPopupURLs.first());
00959 }
00960 
00961 void KonqPopupMenu::slotPopupEmptyTrashBin()
00962 {
00963   KonqOperations::emptyTrash();
00964 }
00965 
00966 void KonqPopupMenu::slotPopupRestoreTrashedItems()
00967 {
00968   KonqOperations::restoreTrashedItems( m_lstPopupURLs );
00969 }
00970 
00971 void KonqPopupMenu::slotPopupOpenWith()
00972 {
00973   KRun::displayOpenWithDialog( m_lstPopupURLs );
00974 }
00975 
00976 void KonqPopupMenu::slotPopupAddToBookmark()
00977 {
00978   KBookmarkGroup root;
00979   if ( m_lstPopupURLs.count() == 1 ) {
00980     KURL url = m_lstPopupURLs.first();
00981     QString title = d->m_urlTitle.isEmpty() ? url.prettyURL() : d->m_urlTitle;
00982     root = m_pManager->addBookmarkDialog( url.prettyURL(), title );
00983   }
00984   else
00985   {
00986     root = m_pManager->root();
00987     KURL::List::ConstIterator it = m_lstPopupURLs.begin();
00988     for ( ; it != m_lstPopupURLs.end(); it++ )
00989       root.addBookmark( m_pManager, (*it).prettyURL(), (*it) );
00990   }
00991   m_pManager->emitChanged( root );
00992 }
00993 
00994 void KonqPopupMenu::slotRunService()
00995 {
00996   QCString senderName = sender()->name();
00997   int id = senderName.mid( senderName.find( '_' ) + 1 ).toInt();
00998 
00999   // Is it a usual service (application)
01000   QMap<int,KService::Ptr>::Iterator it = m_mapPopup.find( id );
01001   if ( it != m_mapPopup.end() )
01002   {
01003     KRun::run( **it, m_lstPopupURLs );
01004     return;
01005   }
01006 
01007   // Is it a service specific to desktop entry files ?
01008   QMap<int,KDEDesktopMimeType::Service>::Iterator it2 = m_mapPopupServices.find( id );
01009   if ( it2 != m_mapPopupServices.end() )
01010   {
01011       KDEDesktopMimeType::executeService( m_lstPopupURLs, it2.data() );
01012   }
01013 
01014   return;
01015 }
01016 
01017 void KonqPopupMenu::slotPopupMimeType()
01018 {
01019     KonqOperations::editMimeType( m_sMimeType );
01020 }
01021 
01022 void KonqPopupMenu::slotPopupProperties()
01023 {
01024     (void)showPropertiesDialog();
01025 }
01026 
01027 KPropertiesDialog* KonqPopupMenu::showPropertiesDialog()
01028 {
01029     // It may be that the kfileitem was created by hand
01030     // (see KonqKfmIconView::slotMouseButtonPressed)
01031     // In that case, we can get more precise info in the properties
01032     // (like permissions) if we stat the URL.
01033     if ( m_lstItems.count() == 1 )
01034     {
01035         KFileItem * item = m_lstItems.first();
01036         if (item->entry().count() == 0) // this item wasn't listed by a slave
01037         {
01038             // KPropertiesDialog will use stat to get more info on the file
01039             return new KPropertiesDialog( item->url(), d->m_parentWidget );
01040         }
01041     }
01042     return new KPropertiesDialog( m_lstItems, d->m_parentWidget );
01043 }
01044 
01045 KAction *KonqPopupMenu::action( const QDomElement &element ) const
01046 {
01047   QCString name = element.attribute( attrName ).ascii();
01048   KAction *res = m_ownActions.action( name );
01049 
01050   if ( !res )
01051     res = m_actions.action( name );
01052 
01053   if ( !res && m_pMenuNew && strcmp( name, m_pMenuNew->name() ) == 0 )
01054     return m_pMenuNew;
01055 
01056   return res;
01057 }
01058 
01059 KActionCollection *KonqPopupMenu::actionCollection() const
01060 {
01061     return const_cast<KActionCollection *>( &m_ownActions );
01062 }
01063 
01064 QString KonqPopupMenu::mimeType() const
01065 {
01066     return m_sMimeType;
01067 }
01068 
01069 KonqPopupMenu::ProtocolInfo KonqPopupMenu::protocolInfo() const
01070 {
01071     return m_info;
01072 }
01073 
01074 void KonqPopupMenu::addPlugins()
01075 {
01076     // search for Konq_PopupMenuPlugins inspired by simons kpropsdlg
01077     //search for a plugin with the right protocol
01078     KTrader::OfferList plugin_offers;
01079     unsigned int pluginCount = 0;
01080     plugin_offers = KTrader::self()->query( m_sMimeType.isNull() ? QString::fromLatin1( "all/all" ) : m_sMimeType, "'KonqPopupMenu/Plugin' in ServiceTypes");
01081     if ( plugin_offers.isEmpty() )
01082         return; // no plugins installed do not bother about it
01083 
01084     KTrader::OfferList::ConstIterator iterator = plugin_offers.begin();
01085     KTrader::OfferList::ConstIterator end = plugin_offers.end();
01086 
01087     addGroup( "plugins" );
01088     // travers the offerlist
01089     for(; iterator != end; ++iterator, ++pluginCount ) {
01090         //kdDebug() << (*iterator)->library() << endl;
01091         KonqPopupMenuPlugin *plugin =
01092             KParts::ComponentFactory::
01093             createInstanceFromLibrary<KonqPopupMenuPlugin>( QFile::encodeName( (*iterator)->library() ),
01094                                                             this,
01095                                                             (*iterator)->name().latin1() );
01096         if ( !plugin )
01097             continue;
01098         QString pluginClientName = QString::fromLatin1( "Plugin%1" ).arg( pluginCount );
01099         addMerge( pluginClientName );
01100         plugin->domDocument().documentElement().setAttribute( "name", pluginClientName );
01101         m_pluginList.append( plugin );
01102         insertChildClient( plugin );
01103     }
01104 
01105     // ## Where is this used?
01106     addMerge( "plugins" );
01107 }
01108 
01109 KURL KonqPopupMenu::url() const // ### should be viewURL()
01110 {
01111   return m_sViewURL;
01112 }
01113 
01114 KFileItemList KonqPopupMenu::fileItemList() const
01115 {
01116   return m_lstItems;
01117 }
01118 
01119 KURL::List KonqPopupMenu::popupURLList() const
01120 {
01121   return m_lstPopupURLs;
01122 }
01123 
01128 KonqPopupMenuPlugin::KonqPopupMenuPlugin( KonqPopupMenu *parent, const char *name )
01129     : QObject( parent, name )
01130 {
01131 }
01132 
01133 KonqPopupMenuPlugin::~KonqPopupMenuPlugin()
01134 {
01135 }
01136 
01137 #include "konq_popupmenu.moc"
KDE Logo
This file is part of the documentation for libkonq Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 13 19:27:50 2006 by doxygen 1.4.3 written by Dimitri van Heesch, © 1997-2003