• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • libkonq
 

libkonq

  • libkonq
konq_popupmenu.cc
1 /* This file is part of the KDE project
2  Copyright (C) 1998, 1999 David Faure <faure@kde.org>
3  Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include <tqdir.h>
22 
23 #include <klocale.h>
24 #include <kapplication.h>
25 #include <kbookmarkmanager.h>
26 #include <kdebug.h>
27 #include <krun.h>
28 #include <kprotocolinfo.h>
29 #include <kiconloader.h>
30 #include <kinputdialog.h>
31 #include <kglobalsettings.h>
32 #include <kstandarddirs.h>
33 #include <kxmlguifactory.h>
34 #include <kxmlguibuilder.h>
35 #include <kparts/componentfactory.h>
36 
37 #include <assert.h>
38 
39 #include <kfileshare.h>
40 #include <kprocess.h>
41 
42 #include "kpropertiesdialog.h"
43 #include "knewmenu.h"
44 #include "konq_popupmenu.h"
45 #include "konq_operations.h"
46 #include "konq_xmlguiclient.h"
47 #include <dcopclient.h>
48 
49 /*
50  Test cases:
51  iconview file: background
52  iconview file: file (with and without servicemenus)
53  iconview file: directory
54  iconview remote protocol (e.g. ftp: or fish:)
55  iconview trash:/
56  sidebar directory tree
57  sidebar Devices / Hard Disc
58  khtml background
59  khtml link
60  khtml image (www.kde.org RMB on K logo)
61  khtmlimage (same as above, then choose View image, then RMB)
62  selected text in khtml
63  embedded katepart
64  kdesktop folder
65  trash link on desktop
66  trashed file or directory
67  application .desktop file
68  Then the same after uninstalling kdeaddons/konq-plugins (kuick and arkplugin in particular)
69 */
70 
71 class KonqPopupMenuGUIBuilder : public KXMLGUIBuilder
72 {
73 public:
74  KonqPopupMenuGUIBuilder( TQPopupMenu *menu )
75  : KXMLGUIBuilder( 0 )
76  {
77  m_menu = menu;
78  }
79  virtual ~KonqPopupMenuGUIBuilder()
80  {
81  }
82 
83  virtual TQWidget *createContainer( TQWidget *parent, int index,
84  const TQDomElement &element,
85  int &id )
86  {
87  if ( !parent && element.attribute( "name" ) == "popupmenu" )
88  return m_menu;
89 
90  return KXMLGUIBuilder::createContainer( parent, index, element, id );
91  }
92 
93  TQPopupMenu *m_menu;
94 };
95 
96 class KonqPopupMenu::KonqPopupMenuPrivate
97 {
98 public:
99  KonqPopupMenuPrivate() : m_parentWidget( 0 ),
100  m_itemFlags( KParts::BrowserExtension::DefaultPopupItems )
101  {
102  }
103  TQString m_urlTitle;
104  TQWidget *m_parentWidget;
105  KParts::BrowserExtension::PopupFlags m_itemFlags;
106 };
107 
108 KonqPopupMenu::ProtocolInfo::ProtocolInfo()
109 {
110  m_Reading = false;
111  m_Writing = false;
112  m_Deleting = false;
113  m_Moving = false;
114  m_TrashIncluded = false;
115 }
116 
117 bool KonqPopupMenu::ProtocolInfo::supportsReading() const
118 {
119  return m_Reading;
120 }
121 
122 bool KonqPopupMenu::ProtocolInfo::supportsWriting() const
123 {
124  return m_Writing;
125 }
126 
127 bool KonqPopupMenu::ProtocolInfo::supportsDeleting() const
128 {
129  return m_Deleting;
130 }
131 
132 bool KonqPopupMenu::ProtocolInfo::supportsMoving() const
133 {
134  return m_Moving;
135 }
136 
137 bool KonqPopupMenu::ProtocolInfo::trashIncluded() const
138 {
139  return m_TrashIncluded;
140 }
141 
142 // This helper class stores the .desktop-file actions and the servicemenus
143 // in order to support X-KDE-Priority and X-KDE-Submenu.
144 class PopupServices
145 {
146 public:
147  ServiceList* selectList( const TQString& priority, const TQString& submenuName );
148 
149  ServiceList builtin;
150  ServiceList user, userToplevel, userPriority;
151  TQMap<TQString, ServiceList> userSubmenus, userToplevelSubmenus, userPrioritySubmenus;
152 };
153 
154 ServiceList* PopupServices::selectList( const TQString& priority, const TQString& submenuName )
155 {
156  // we use the categories .desktop entry to define submenus
157  // if none is defined, we just pop it in the main menu
158  if (submenuName.isEmpty())
159  {
160  if (priority == "TopLevel")
161  {
162  return &userToplevel;
163  }
164  else if (priority == "Important")
165  {
166  return &userPriority;
167  }
168  }
169  else if (priority == "TopLevel")
170  {
171  return &(userToplevelSubmenus[submenuName]);
172  }
173  else if (priority == "Important")
174  {
175  return &(userPrioritySubmenus[submenuName]);
176  }
177  else
178  {
179  return &(userSubmenus[submenuName]);
180  }
181  return &user;
182 }
183 
185 
186 KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
187  KURL viewURL,
188  KActionCollection & actions,
189  KNewMenu * newMenu,
190  bool showProperties )
191  : TQPopupMenu( 0L, "konq_popupmenu" ),
192  m_actions( actions ), m_ownActions( static_cast<TQWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ),
193  m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
194 {
195  KonqPopupFlags kpf = ( showProperties ? ShowProperties : IsLink ) | ShowNewWindow;
196  init(0, kpf, KParts::BrowserExtension::DefaultPopupItems);
197 }
198 
199 KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
200  KURL viewURL,
201  KActionCollection & actions,
202  KNewMenu * newMenu,
203  TQWidget * parentWidget,
204  bool showProperties )
205  : TQPopupMenu( parentWidget, "konq_popupmenu" ), m_actions( actions ), m_ownActions( static_cast<TQWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ), m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
206 {
207  KonqPopupFlags kpf = ( showProperties ? ShowProperties : IsLink ) | ShowNewWindow;
208  init(parentWidget, kpf, KParts::BrowserExtension::DefaultPopupItems);
209 }
210 
211 KonqPopupMenu::KonqPopupMenu( KBookmarkManager *mgr, const KFileItemList &items,
212  const KURL& viewURL,
213  KActionCollection & actions,
214  KNewMenu * newMenu,
215  TQWidget * parentWidget,
216  KonqPopupFlags kpf,
217  KParts::BrowserExtension::PopupFlags flags)
218  : TQPopupMenu( parentWidget, "konq_popupmenu" ), m_actions( actions ), m_ownActions( static_cast<TQWidget *>( 0 ), "KonqPopupMenu::m_ownActions" ), m_pMenuNew( newMenu ), m_sViewURL(viewURL), m_lstItems(items), m_pManager(mgr)
219 {
220  init(parentWidget, kpf, flags);
221 }
222 
223 void KonqPopupMenu::init (TQWidget * parentWidget, KonqPopupFlags kpf, KParts::BrowserExtension::PopupFlags flags)
224 {
225  d = new KonqPopupMenuPrivate;
226  d->m_parentWidget = parentWidget;
227  d->m_itemFlags = flags;
228  setup(kpf);
229 }
230 
231 int KonqPopupMenu::insertServicesSubmenus(const TQMap<TQString, ServiceList>& submenus,
232  TQDomElement& menu,
233  bool isBuiltin)
234 {
235  int count = 0;
236  TQMap<TQString, ServiceList>::ConstIterator it;
237 
238  for (it = submenus.begin(); it != submenus.end(); ++it)
239  {
240  if (it.data().isEmpty())
241  {
242  //avoid empty sub-menus
243  continue;
244  }
245 
246  TQDomElement actionSubmenu = m_doc.createElement( "menu" );
247  actionSubmenu.setAttribute( "name", "actions " + it.key() );
248  menu.appendChild( actionSubmenu );
249  TQDomElement subtext = m_doc.createElement( "text" );
250  actionSubmenu.appendChild( subtext );
251  subtext.appendChild( m_doc.createTextNode( it.key() ) );
252  count += insertServices(it.data(), actionSubmenu, isBuiltin);
253  }
254 
255  return count;
256 }
257 
258 int KonqPopupMenu::insertServices(const ServiceList& list,
259  TQDomElement& menu,
260  bool isBuiltin)
261 {
262  static int id = 1000;
263  int count = 0;
264 
265  ServiceList::const_iterator it = list.begin();
266  for( ; it != list.end(); ++it )
267  {
268  if ((*it).isEmpty())
269  {
270  if (!menu.firstChild().isNull() &&
271  menu.lastChild().toElement().tagName().lower() != "separator")
272  {
273  TQDomElement separator = m_doc.createElement( "separator" );
274  menu.appendChild(separator);
275  }
276  continue;
277  }
278 
279  if (isBuiltin || (*it).m_display == true)
280  {
281  TQCString name;
282  name.setNum( id );
283  name.prepend( isBuiltin ? "builtinservice_" : "userservice_" );
284  KAction * act = new KAction( TQString((*it).m_strName).replace('&',"&&"), 0,
285  TQT_TQOBJECT(this), TQT_SLOT( slotRunService() ),
286  &m_ownActions, name );
287 
288  if ( !(*it).m_strIcon.isEmpty() )
289  {
290  TQPixmap pix = SmallIcon( (*it).m_strIcon );
291  act->setIconSet( pix );
292  }
293 
294  addAction( act, menu ); // Add to toplevel menu
295 
296  m_mapPopupServices[ id++ ] = *it;
297  ++count;
298  }
299  }
300 
301  return count;
302 }
303 
304 bool KonqPopupMenu::KIOSKAuthorizedAction(KConfig& cfg)
305 {
306  if ( !cfg.hasKey( "X-KDE-AuthorizeAction") )
307  {
308  return true;
309  }
310 
311  TQStringList list = cfg.readListEntry("X-KDE-AuthorizeAction");
312  if (kapp && !list.isEmpty())
313  {
314  for(TQStringList::ConstIterator it = list.begin();
315  it != list.end();
316  ++it)
317  {
318  if (!kapp->authorize((*it).stripWhiteSpace()))
319  {
320  return false;
321  }
322  }
323  }
324 
325  return true;
326 }
327 
328 
329 void KonqPopupMenu::setup(KonqPopupFlags kpf)
330 {
331  assert( m_lstItems.count() >= 1 );
332 
333  m_ownActions.setWidget( this );
334 
335  const bool bIsLink = (kpf & IsLink);
336  bool currentDir = false;
337  bool sReading = true;
338  bool sDeleting = ( d->m_itemFlags & KParts::BrowserExtension::NoDeletion ) == 0;
339  bool sMoving = sDeleting;
340  bool sWriting = sDeleting && m_lstItems.first()->isWritable();
341  m_sMimeType = m_lstItems.first()->mimetype();
342  TQString mimeGroup = m_sMimeType.left(m_sMimeType.find('/'));
343  mode_t mode = m_lstItems.first()->mode();
344  bool isDirectory = S_ISDIR(mode);
345  bool bTrashIncluded = false;
346  bool mediaFiles = false;
347  bool isReallyLocal = m_lstItems.first()->isLocalFile();
348  bool isLocal = isReallyLocal
349  || m_lstItems.first()->url().protocol()=="media"
350  || m_lstItems.first()->url().protocol()=="system";
351  bool isTrashLink = false;
352  m_lstPopupURLs.clear();
353  int id = 0;
354  setFont(KGlobalSettings::menuFont());
355  m_pluginList.setAutoDelete( true );
356  m_ownActions.setHighlightingEnabled( true );
357 
358  attrName = TQString::fromLatin1( "name" );
359 
360  prepareXMLGUIStuff();
361  m_builder = new KonqPopupMenuGUIBuilder( this );
362  m_factory = new KXMLGUIFactory( m_builder );
363 
364  KURL url;
365  KFileItemListIterator it ( m_lstItems );
366  TQStringList mimeTypeList;
367  // Check whether all URLs are correct
368  for ( ; it.current(); ++it )
369  {
370  url = (*it)->url();
371 
372  // Build the list of URLs
373  m_lstPopupURLs.append( url );
374 
375  // Determine if common mode among all URLs
376  if ( mode != (*it)->mode() )
377  mode = 0; // modes are different => reset to 0
378 
379  // Determine if common mimetype among all URLs
380  if ( m_sMimeType != (*it)->mimetype() )
381  {
382  m_sMimeType = TQString::null; // mimetypes are different => null
383 
384  if ( mimeGroup != (*it)->mimetype().left((*it)->mimetype().find('/')))
385  mimeGroup = TQString::null; // mimetype groups are different as well!
386  }
387 
388  if ( mimeTypeList.findIndex( (*it)->mimetype() ) == -1 )
389  mimeTypeList << (*it)->mimetype();
390 
391  if ( isReallyLocal && !url.isLocalFile() )
392  isReallyLocal = false;
393  if ( isLocal && !url.isLocalFile() && url.protocol() != "media" && url.protocol() != "system" )
394  isLocal = false;
395 
396  if ( !bTrashIncluded && (
397  ( url.protocol() == "trash" && url.path().length() <= 1 )
398  || url.url() == "system:/trash" || url.url() == "system:/trash/" ) ) {
399  bTrashIncluded = true;
400  isLocal = false;
401  }
402 
403  if ( sReading )
404  sReading = KProtocolInfo::supportsReading( url );
405 
406  if ( sWriting )
407  sWriting = KProtocolInfo::supportsWriting( url ) && (*it)->isWritable();
408 
409  if ( sDeleting )
410  sDeleting = KProtocolInfo::supportsDeleting( url );
411 
412  if ( sMoving )
413  sMoving = KProtocolInfo::supportsMoving( url );
414  if ( (*it)->mimetype().startsWith("media/") )
415  mediaFiles = true;
416  }
417  url = m_sViewURL;
418  url.cleanPath();
419 
420  //check if url is current directory
421  if ( m_lstItems.count() == 1 )
422  {
423  KURL firstPopupURL( m_lstItems.first()->url() );
424  firstPopupURL.cleanPath();
425  //kdDebug(1203) << "View path is " << url.url() << endl;
426  //kdDebug(1203) << "First popup path is " << firstPopupURL.url() << endl;
427  currentDir = firstPopupURL.equals( url, true /* ignore_trailing */ );
428  if ( isLocal && ((m_sMimeType == "application/x-desktop")
429  || (m_sMimeType == "media/builtin-mydocuments")
430  || (m_sMimeType == "media/builtin-mycomputer")
431  || (m_sMimeType == "media/builtin-mynetworkplaces")
432  || (m_sMimeType == "media/builtin-printers")
433  || (m_sMimeType == "media/builtin-trash")
434  || (m_sMimeType == "media/builtin-webbrowser")) ) {
435  KSimpleConfig cfg( firstPopupURL.path(), true );
436  cfg.setDesktopGroup();
437  isTrashLink = ( cfg.readEntry("Type") == "Link" && cfg.readEntry("URL") == "trash:/" );
438  }
439 
440  if ( isTrashLink ) {
441  sDeleting = false;
442  }
443  }
444 
445  m_info.m_Reading = sReading;
446  m_info.m_Writing = sWriting;
447  m_info.m_Deleting = sDeleting;
448  m_info.m_Moving = sMoving;
449  m_info.m_TrashIncluded = bTrashIncluded;
450 
451  // isCurrentTrash: popup on trash:/ itself, or on the trash.desktop link
452  bool isCurrentTrash = ( m_lstItems.count() == 1 && bTrashIncluded ) || isTrashLink;
453  bool isIntoTrash = ( url.protocol() == "trash" || url.url().startsWith( "system:/trash" ) ) && !isCurrentTrash; // trashed file, not trash:/ itself
454  //kdDebug() << "isLocal=" << isLocal << " url=" << url << " isCurrentTrash=" << isCurrentTrash << " isIntoTrash=" << isIntoTrash << " bTrashIncluded=" << bTrashIncluded << endl;
455  bool isSingleMedium = m_lstItems.count() == 1 && mediaFiles;
456  clear();
457 
459 
460  KAction * act;
461 
462  if (!isCurrentTrash)
463  addMerge( "konqueror" );
464 
465  bool isKDesktop = TQCString( kapp->name() ) == "kdesktop";
466  KAction *actNewWindow = 0;
467 
468  if (( kpf & ShowProperties ) && isKDesktop &&
469  !kapp->authorize("editable_desktop_icons"))
470  {
471  kpf &= ~ShowProperties; // remove flag
472  }
473 
474  // Either 'newview' is in the actions we're given (probably in the tabhandling group)
475  // or we need to insert it ourselves (e.g. for kdesktop). In the first case, actNewWindow must remain 0.
476  if ( ((kpf & ShowNewWindow) != 0) && sReading )
477  {
478  TQString openStr = isKDesktop ? i18n( "&Open" ) : i18n( "Open in New &Window" );
479  actNewWindow = new KAction( openStr, "window_new", 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupNewView() ), &m_ownActions, "newview" );
480  }
481 
482  if ( actNewWindow && !isKDesktop )
483  {
484  if (isCurrentTrash)
485  actNewWindow->setToolTip( i18n( "Open the trash in a new window" ) );
486  else if (isSingleMedium)
487  actNewWindow->setToolTip( i18n( "Open the medium in a new window") );
488  else
489  actNewWindow->setToolTip( i18n( "Open the document in a new window" ) );
490  }
491 
492  if ( S_ISDIR(mode) && sWriting && !isCurrentTrash ) // A dir, and we can create things into it
493  {
494  if ( currentDir && m_pMenuNew ) // Current dir -> add the "new" menu
495  {
496  // As requested by KNewMenu :
497  m_pMenuNew->slotCheckUpToDate();
498  m_pMenuNew->setPopupFiles( m_lstPopupURLs );
499 
500  addAction( m_pMenuNew );
501 
502  addSeparator();
503  }
504  else
505  {
506  if (d->m_itemFlags & KParts::BrowserExtension::ShowCreateDirectory)
507  {
508  KAction *actNewDir = new KAction( i18n( "Create &Folder..." ), "folder_new", 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupNewDir() ), &m_ownActions, "newdir" );
509  addAction( actNewDir );
510  addSeparator();
511  }
512  }
513  } else if ( isIntoTrash ) {
514  // Trashed item, offer restoring
515  act = new KAction( i18n( "&Restore" ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupRestoreTrashedItems() ), &m_ownActions, "restore" );
516  addAction( act );
517  }
518 
519  if (d->m_itemFlags & KParts::BrowserExtension::ShowNavigationItems)
520  {
521  if (d->m_itemFlags & KParts::BrowserExtension::ShowUp)
522  addAction( "up" );
523  addAction( "back" );
524  addAction( "forward" );
525  if (d->m_itemFlags & KParts::BrowserExtension::ShowReload)
526  addAction( "reload" );
527  addSeparator();
528  }
529 
530  // "open in new window" is either provided by us, or by the tabhandling group
531  if (actNewWindow)
532  {
533  addAction( actNewWindow );
534  addSeparator();
535  }
536  addGroup( "tabhandling" ); // includes a separator
537 
538  if ( !bIsLink )
539  {
540  if ( !currentDir && sReading ) {
541  if ( sDeleting ) {
542  addAction( "cut" );
543  }
544  addAction( "copy" );
545  }
546 
547  if ( S_ISDIR(mode) && sWriting ) {
548  if ( currentDir )
549  addAction( "paste" );
550  else
551  addAction( "pasteto" );
552  }
553  if ( !currentDir )
554  {
555  if ( m_lstItems.count() == 1 && sMoving )
556  addAction( "rename" );
557 
558  bool addTrash = false;
559  bool addDel = false;
560 
561  if ( sMoving && !isIntoTrash && !isTrashLink )
562  addTrash = true;
563 
564  if ( sDeleting ) {
565  if ( !isLocal )
566  addDel = true;
567  else if (KApplication::keyboardMouseState() & TQt::ShiftButton) {
568  addTrash = false;
569  addDel = true;
570  }
571  else {
572  KConfigGroup configGroup( kapp->config(), "KDE" );
573  if ( configGroup.readBoolEntry( "ShowDeleteCommand", false ) )
574  addDel = true;
575  }
576  }
577 
578  if ( addTrash )
579  addAction( "trash" );
580  if ( addDel )
581  addAction( "del" );
582  }
583  }
584  if ( isCurrentTrash )
585  {
586  act = new KAction( i18n( "&Empty Trash Bin" ), "emptytrash", 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupEmptyTrashBin() ), &m_ownActions, "empytrash" );
587  KSimpleConfig trashConfig( "trashrc", true );
588  trashConfig.setGroup( "Status" );
589  act->setEnabled( !trashConfig.readBoolEntry( "Empty", true ) );
590  addAction( act );
591  }
592  addGroup( "editactions" );
593 
594  if (d->m_itemFlags & KParts::BrowserExtension::ShowTextSelectionItems) {
595  addMerge( 0 );
596  m_factory->addClient( this );
597  return;
598  }
599 
600  if ( !isCurrentTrash && !isIntoTrash && (d->m_itemFlags & KParts::BrowserExtension::ShowBookmark))
601  {
602  addSeparator();
603  TQString caption;
604  if (currentDir)
605  {
606  bool httpPage = (m_sViewURL.protocol().find("http", 0, false) == 0);
607  if (httpPage)
608  caption = i18n("&Bookmark This Page");
609  else
610  caption = i18n("&Bookmark This Location");
611  }
612  else if (S_ISDIR(mode))
613  caption = i18n("&Bookmark This Folder");
614  else if (bIsLink)
615  caption = i18n("&Bookmark This Link");
616  else
617  caption = i18n("&Bookmark This File");
618 
619  act = new KAction( caption, "bookmark_add", 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupAddToBookmark() ), &m_ownActions, "bookmark_add" );
620  if (m_lstItems.count() > 1)
621  act->setEnabled(false);
622  if (kapp->authorizeKAction("bookmarks"))
623  addAction( act );
624  if (bIsLink)
625  addGroup( "linkactions" );
626  }
627 
629 
630  const bool isSingleLocal = m_lstItems.count() == 1 && isLocal;
631  PopupServices s;
632  KURL urlForServiceMenu( m_lstItems.first()->url() );
633  if (isLocal && !isReallyLocal) { // media or system
634  bool dummy;
635  urlForServiceMenu = m_lstItems.first()->mostLocalURL(dummy);
636  }
637 
638  // 1 - Look for builtin and user-defined services
639  if ( ((m_sMimeType == "application/x-desktop")
640  || (m_sMimeType == "media/builtin-mydocuments")
641  || (m_sMimeType == "media/builtin-mycomputer")
642  || (m_sMimeType == "media/builtin-mynetworkplaces")
643  || (m_sMimeType == "media/builtin-printers")
644  || (m_sMimeType == "media/builtin-trash")
645  || (m_sMimeType == "media/builtin-webbrowser")) && isSingleLocal ) // .desktop file
646  {
647  // get builtin services, like mount/unmount
648  s.builtin = KDEDesktopMimeType::builtinServices( urlForServiceMenu );
649  const TQString path = urlForServiceMenu.path();
650  KSimpleConfig cfg( path, true );
651  cfg.setDesktopGroup();
652  const TQString priority = cfg.readEntry("X-KDE-Priority");
653  const TQString submenuName = cfg.readEntry( "X-KDE-Submenu" );
654  if ( cfg.readEntry("Type") == "Link" ) {
655  urlForServiceMenu = cfg.readEntry("URL");
656  // TODO: Do we want to make all the actions apply on the target
657  // of the .desktop file instead of the .desktop file itself?
658  }
659  ServiceList* list = s.selectList( priority, submenuName );
660  (*list) = KDEDesktopMimeType::userDefinedServices( path, cfg, urlForServiceMenu.isLocalFile() );
661  }
662 
663  if ( sReading )
664  {
665 
666  // 2 - Look for "servicesmenus" bindings (konqueror-specific user-defined services)
667 
668  // first check the .directory if this is a directory
669  if (isDirectory && isSingleLocal)
670  {
671  TQString dotDirectoryFile = urlForServiceMenu.path(1).append(".directory");
672  KSimpleConfig cfg( dotDirectoryFile, true );
673  cfg.setDesktopGroup();
674 
675  if (KIOSKAuthorizedAction(cfg))
676  {
677  const TQString priority = cfg.readEntry("X-KDE-Priority");
678  const TQString submenuName = cfg.readEntry( "X-KDE-Submenu" );
679  ServiceList* list = s.selectList( priority, submenuName );
680  (*list) += KDEDesktopMimeType::userDefinedServices( dotDirectoryFile, cfg, true );
681  }
682  }
683 
684  // findAllResources() also removes duplicates
685  const TQStringList entries = KGlobal::dirs()->findAllResources("data",
686  "konqueror/servicemenus/*.desktop",
687  false /* recursive */,
688  true /* unique */);
689  TQStringList::ConstIterator eIt = entries.begin();
690  const TQStringList::ConstIterator eEnd = entries.end();
691  for (; eIt != eEnd; ++eIt )
692  {
693  KSimpleConfig cfg( *eIt, true );
694  cfg.setDesktopGroup();
695 
696  if (!KIOSKAuthorizedAction(cfg))
697  {
698  continue;
699  }
700 
701  if ( cfg.hasKey( "X-KDE-ShowIfRunning" ) )
702  {
703  const TQString app = cfg.readEntry( "X-KDE-ShowIfRunning" );
704  if ( !kapp->dcopClient()->isApplicationRegistered( app.utf8() ) )
705  continue;
706  }
707  if ( cfg.hasKey( "X-KDE-ShowIfDcopCall" ) )
708  {
709  TQString dcopcall = cfg.readEntry( "X-KDE-ShowIfDcopCall" );
710  const TQCString app = TQString(dcopcall.section(' ', 0,0)).utf8();
711 
712  //if( !kapp->dcopClient()->isApplicationRegistered( app ))
713  // continue; //app does not exist so cannot send call
714 
715  TQByteArray dataToSend;
716  TQDataStream dataStream(dataToSend, IO_WriteOnly);
717  dataStream << m_lstPopupURLs;
718 
719  TQCString replyType;
720  TQByteArray replyData;
721  TQCString object = TQString(dcopcall.section(' ', 1,-2)).utf8();
722  TQString function = TQString(dcopcall.section(' ', -1));
723  if(!function.endsWith("(KURL::List)")) {
724  kdWarning() << "Desktop file " << *eIt << " contains an invalid X-KDE-ShowIfDcopCall - the function must take the exact parameter (KURL::List) and must be specified." << endl;
725  continue; //Be safe.
726  }
727 
728  if(!kapp->dcopClient()->call( app, object,
729  function.utf8(),
730  dataToSend, replyType, replyData, true, 1000))
731  continue;
732  if(replyType != "bool" || !replyData[0])
733  continue;
734 
735  }
736  if ( cfg.hasKey( "X-KDE-Protocol" ) )
737  {
738  const TQString protocol = cfg.readEntry( "X-KDE-Protocol" );
739  if ( protocol != urlForServiceMenu.protocol() )
740  continue;
741  }
742  else if ( cfg.hasKey( "X-KDE-Protocols" ) )
743  {
744  TQStringList protocols = TQStringList::split( "," , cfg.readEntry( "X-KDE-Protocols" ) );
745  if ( !protocols.contains( urlForServiceMenu.protocol() ) )
746  continue;
747  }
748  else if ( urlForServiceMenu.protocol() == "trash" || urlForServiceMenu.url().startsWith( "system:/trash" ) )
749  {
750  // Require servicemenus for the trash to ask for protocol=trash explicitely.
751  // Trashed files aren't supposed to be available for actions.
752  // One might want a servicemenu for trash.desktop itself though.
753  continue;
754  }
755 
756  if ( cfg.hasKey( "X-KDE-Require" ) )
757  {
758  const TQStringList capabilities = cfg.readListEntry( "X-KDE-Require" );
759  if ( capabilities.contains( "Write" ) && !sWriting )
760  continue;
761  }
762  if ( (cfg.hasKey( "Actions" ) || cfg.hasKey( "X-KDE-GetActionMenu") ) && cfg.hasKey( "ServiceTypes" ) )
763  {
764  const TQStringList types = cfg.readListEntry( "ServiceTypes" );
765  const TQStringList excludeTypes = cfg.readListEntry( "ExcludeServiceTypes" );
766  bool ok = false;
767 
768  // check for exact matches or a typeglob'd mimetype if we have a mimetype
769  for (TQStringList::ConstIterator it = types.begin();
770  it != types.end() && !ok;
771  ++it)
772  {
773  // first check if we have an all mimetype
774  bool checkTheMimetypes = false;
775  if (*it == "all/all" ||
776  *it == "allfiles" /*compat with KDE up to 3.0.3*/)
777  {
778  checkTheMimetypes = true;
779  }
780 
781  // next, do we match all files?
782  if (!ok &&
783  !isDirectory &&
784  *it == "all/allfiles")
785  {
786  checkTheMimetypes = true;
787  }
788 
789  // if we have a mimetype, see if we have an exact or a type globbed match
790  if (!ok &&
791  (!m_sMimeType.isEmpty() &&
792  *it == m_sMimeType) ||
793  (!mimeGroup.isEmpty() &&
794  ((*it).right(1) == "*" &&
795  (*it).left((*it).find('/')) == mimeGroup)))
796  {
797  checkTheMimetypes = true;
798  }
799 
800  if (checkTheMimetypes)
801  {
802  ok = true;
803  for (TQStringList::ConstIterator itex = excludeTypes.begin(); itex != excludeTypes.end(); ++itex)
804  {
805  if( ((*itex).right(1) == "*" && (*itex).left((*itex).find('/')) == mimeGroup) ||
806  ((*itex) == m_sMimeType) )
807  {
808  ok = false;
809  break;
810  }
811  }
812  }
813  }
814 
815  if ( ok )
816  {
817  const TQString priority = cfg.readEntry("X-KDE-Priority");
818  const TQString submenuName = cfg.readEntry( "X-KDE-Submenu" );
819 
820  ServiceList* list = s.selectList( priority, submenuName );
821  (*list) += KDEDesktopMimeType::userDefinedServices( *eIt, cfg, url.isLocalFile(), m_lstPopupURLs );
822  }
823  }
824  }
825 
826  KTrader::OfferList offers;
827 
828  if (kapp->authorizeKAction("openwith"))
829  {
830  TQString constraint = "Type == 'Application' and DesktopEntryName != 'kfmclient' and DesktopEntryName != 'kfmclient_dir' and DesktopEntryName != 'kfmclient_html'";
831  TQString subConstraint = " and '%1' in ServiceTypes";
832 
833  TQStringList::ConstIterator it = mimeTypeList.begin();
834  TQStringList::ConstIterator end = mimeTypeList.end();
835  Q_ASSERT( it != end );
836  TQString first = *it;
837  ++it;
838  while ( it != end ) {
839  constraint += subConstraint.arg( *it );
840  ++it;
841  }
842 
843  offers = KTrader::self()->query( first, constraint );
844  }
845 
847 
848  m_mapPopup.clear();
849  m_mapPopupServices.clear();
850  // "Open With..." for folders is really not very useful, especially for remote folders.
851  // (media:/something, or trash:/, or ftp://...)
852  if ( !isDirectory || isLocal )
853  {
854  if ( hasAction() )
855  addSeparator();
856 
857  if ( !offers.isEmpty() )
858  {
859  // First block, app and preview offers
860  id = 1;
861 
862  TQDomElement menu = m_menuElement;
863 
864  if ( offers.count() > 1 ) // submenu 'open with'
865  {
866  menu = m_doc.createElement( "menu" );
867  menu.setAttribute( "name", "openwith submenu" );
868  m_menuElement.appendChild( menu );
869  TQDomElement text = m_doc.createElement( "text" );
870  menu.appendChild( text );
871  text.appendChild( m_doc.createTextNode( i18n("&Open With") ) );
872  }
873 
874  KTrader::OfferList::ConstIterator it = offers.begin();
875  for( ; it != offers.end(); it++ )
876  {
877  KService::Ptr service = (*it);
878 
879  // Skip OnlyShowIn=Foo and NotShowIn=KDE entries,
880  // but still offer NoDisplay=true entries, that's the
881  // whole point of such desktop files. This is why we don't
882  // use service->noDisplay() here.
883  const TQString onlyShowIn = service->property("OnlyShowIn", TQVariant::String).toString();
884  if ( !onlyShowIn.isEmpty() ) {
885  const TQStringList aList = TQStringList::split(';', onlyShowIn);
886  if (!aList.contains("KDE"))
887  continue;
888  }
889  const TQString notShowIn = service->property("NotShowIn", TQVariant::String).toString();
890  if ( !notShowIn.isEmpty() ) {
891  const TQStringList aList = TQStringList::split(';', notShowIn);
892  if (aList.contains("KDE"))
893  continue;
894  }
895 
896  TQCString nam;
897  nam.setNum( id );
898 
899  TQString actionName( (*it)->name().replace("&", "&&") );
900  if ( menu == m_menuElement ) // no submenu -> prefix single offer
901  actionName = i18n( "Open with %1" ).arg( actionName );
902 
903  act = new KAction( actionName, (*it)->pixmap( KIcon::Small ), 0,
904  TQT_TQOBJECT(this), TQT_SLOT( slotRunService() ),
905  &m_ownActions, nam.prepend( "appservice_" ) );
906  addAction( act, menu );
907 
908  m_mapPopup[ id++ ] = *it;
909  }
910 
911  TQString openWithActionName;
912  if ( menu != m_menuElement ) // submenu
913  {
914  addSeparator( menu );
915  openWithActionName = i18n( "&Other..." );
916  }
917  else
918  {
919  openWithActionName = i18n( "&Open With..." );
920  }
921  KAction *openWithAct = new KAction( openWithActionName, 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" );
922  addAction( openWithAct, menu );
923  }
924  else // no app offers -> Open With...
925  {
926  act = new KAction( i18n( "&Open With..." ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupOpenWith() ), &m_ownActions, "openwith" );
927  addAction( act );
928  }
929 
930  }
931  addGroup( "preview" );
932  }
933 
934  // Second block, builtin + user
935  TQDomElement actionMenu = m_menuElement;
936  int userItemCount = 0;
937  if (s.user.count() + s.userSubmenus.count() +
938  s.userPriority.count() + s.userPrioritySubmenus.count() > 1)
939  {
940  // we have more than one item, so let's make a submenu
941  actionMenu = m_doc.createElement( "menu" );
942  actionMenu.setAttribute( "name", "actions submenu" );
943  m_menuElement.appendChild( actionMenu );
944  TQDomElement text = m_doc.createElement( "text" );
945  actionMenu.appendChild( text );
946  text.appendChild( m_doc.createTextNode( i18n("Ac&tions") ) );
947  }
948 
949  userItemCount += insertServicesSubmenus(s.userPrioritySubmenus, actionMenu, false);
950  userItemCount += insertServices(s.userPriority, actionMenu, false);
951 
952  // see if we need to put a separator between our priority items and our regular items
953  if (userItemCount > 0 &&
954  (s.user.count() > 0 ||
955  s.userSubmenus.count() > 0 ||
956  s.builtin.count() > 0) &&
957  actionMenu.lastChild().toElement().tagName().lower() != "separator")
958  {
959  TQDomElement separator = m_doc.createElement( "separator" );
960  actionMenu.appendChild(separator);
961  }
962 
963  userItemCount += insertServicesSubmenus(s.userSubmenus, actionMenu, false);
964  userItemCount += insertServices(s.user, actionMenu, false);
965  userItemCount += insertServices(s.builtin, m_menuElement, true);
966 
967  userItemCount += insertServicesSubmenus(s.userToplevelSubmenus, m_menuElement, false);
968  userItemCount += insertServices(s.userToplevel, m_menuElement, false);
969 
970  if ( userItemCount > 0 )
971  {
972  addPendingSeparator();
973  }
974 
975  if ( !isCurrentTrash && !isIntoTrash && !mediaFiles && sReading )
976  addPlugins(); // now it's time to add plugins
977 
978  if ( KPropertiesDialog::canDisplay( m_lstItems ) && (kpf & ShowProperties) )
979  {
980  act = new KAction( i18n( "&Properties" ), 0, TQT_TQOBJECT(this), TQT_SLOT( slotPopupProperties() ),
981  &m_ownActions, "properties" );
982  addAction( act );
983  }
984 
985  while ( !m_menuElement.lastChild().isNull() &&
986  m_menuElement.lastChild().toElement().tagName().lower() == "separator" )
987  m_menuElement.removeChild( m_menuElement.lastChild() );
988 
989  if ( isDirectory && isLocal )
990  {
991  if ( KFileShare::authorization() == KFileShare::Authorized )
992  {
993  addSeparator();
994  act = new KAction( i18n("Share"), 0, TQT_TQOBJECT(this), TQT_SLOT( slotOpenShareFileDialog() ),
995  &m_ownActions, "sharefile" );
996  addAction( act );
997  }
998  }
999 
1000  addMerge( 0 );
1001  //kdDebug() << k_funcinfo << domDocument().toString() << endl;
1002 
1003  m_factory->addClient( this );
1004 }
1005 
1006 void KonqPopupMenu::slotOpenShareFileDialog()
1007 {
1008  KPropertiesDialog* dlg = showPropertiesDialog();
1009  dlg->showFileSharingPage();
1010 }
1011 
1012 KonqPopupMenu::~KonqPopupMenu()
1013 {
1014  m_pluginList.clear();
1015  delete m_factory;
1016  delete m_builder;
1017  delete d;
1018  //kdDebug(1203) << "~KonqPopupMenu leave" << endl;
1019 }
1020 
1021 void KonqPopupMenu::setURLTitle( const TQString& urlTitle )
1022 {
1023  d->m_urlTitle = urlTitle;
1024 }
1025 
1026 void KonqPopupMenu::slotPopupNewView()
1027 {
1028  KURL::List::ConstIterator it = m_lstPopupURLs.begin();
1029  for ( ; it != m_lstPopupURLs.end(); it++ )
1030  (void) new KRun(*it);
1031 }
1032 
1033 void KonqPopupMenu::slotPopupNewDir()
1034 {
1035  if (m_lstPopupURLs.empty())
1036  return;
1037 
1038  KonqOperations::newDir(d->m_parentWidget, m_lstPopupURLs.first());
1039 }
1040 
1041 void KonqPopupMenu::slotPopupEmptyTrashBin()
1042 {
1043  KonqOperations::emptyTrash();
1044 }
1045 
1046 void KonqPopupMenu::slotPopupRestoreTrashedItems()
1047 {
1048  KonqOperations::restoreTrashedItems( m_lstPopupURLs );
1049 }
1050 
1051 void KonqPopupMenu::slotPopupOpenWith()
1052 {
1053  KRun::displayOpenWithDialog( m_lstPopupURLs );
1054 }
1055 
1056 void KonqPopupMenu::slotPopupAddToBookmark()
1057 {
1058  KBookmarkGroup root;
1059  if ( m_lstPopupURLs.count() == 1 ) {
1060  KURL url = m_lstPopupURLs.first();
1061  TQString title = d->m_urlTitle.isEmpty() ? url.prettyURL() : d->m_urlTitle;
1062  root = m_pManager->addBookmarkDialog( url.prettyURL(), title );
1063  }
1064  else
1065  {
1066  root = m_pManager->root();
1067  KURL::List::ConstIterator it = m_lstPopupURLs.begin();
1068  for ( ; it != m_lstPopupURLs.end(); it++ )
1069  root.addBookmark( m_pManager, (*it).prettyURL(), (*it) );
1070  }
1071  m_pManager->emitChanged( root );
1072 }
1073 
1074 void KonqPopupMenu::slotRunService()
1075 {
1076  TQCString senderName = TQT_TQOBJECT_CONST(sender())->name();
1077  int id = senderName.mid( senderName.find( '_' ) + 1 ).toInt();
1078 
1079  // Is it a usual service (application)
1080  TQMap<int,KService::Ptr>::Iterator it = m_mapPopup.find( id );
1081  if ( it != m_mapPopup.end() )
1082  {
1083  KRun::run( **it, m_lstPopupURLs );
1084  return;
1085  }
1086 
1087  // Is it a service specific to desktop entry files ?
1088  TQMap<int,KDEDesktopMimeType::Service>::Iterator it2 = m_mapPopupServices.find( id );
1089  if ( it2 != m_mapPopupServices.end() )
1090  {
1091  KDEDesktopMimeType::executeService( m_lstPopupURLs, it2.data() );
1092  }
1093 
1094  return;
1095 }
1096 
1097 void KonqPopupMenu::slotPopupMimeType()
1098 {
1099  KonqOperations::editMimeType( m_sMimeType );
1100 }
1101 
1102 void KonqPopupMenu::slotPopupProperties()
1103 {
1104  (void)showPropertiesDialog();
1105 }
1106 
1107 KPropertiesDialog* KonqPopupMenu::showPropertiesDialog()
1108 {
1109  // It may be that the kfileitem was created by hand
1110  // (see KonqKfmIconView::slotMouseButtonPressed)
1111  // In that case, we can get more precise info in the properties
1112  // (like permissions) if we stat the URL.
1113  if ( m_lstItems.count() == 1 )
1114  {
1115  KFileItem * item = m_lstItems.first();
1116  if (item->entry().count() == 0) // this item wasn't listed by a slave
1117  {
1118  // KPropertiesDialog will use stat to get more info on the file
1119  return new KPropertiesDialog( item->url(), d->m_parentWidget );
1120  }
1121  }
1122  return new KPropertiesDialog( m_lstItems, d->m_parentWidget );
1123 }
1124 
1125 KAction *KonqPopupMenu::action( const TQDomElement &element ) const
1126 {
1127  TQCString name = element.attribute( attrName ).ascii();
1128  KAction *res = m_ownActions.action( static_cast<const char *>(name) );
1129 
1130  if ( !res )
1131  res = m_actions.action( static_cast<const char *>(name) );
1132 
1133  if ( !res && m_pMenuNew && strcmp( name, m_pMenuNew->name() ) == 0 )
1134  return m_pMenuNew;
1135 
1136  return res;
1137 }
1138 
1139 KActionCollection *KonqPopupMenu::actionCollection() const
1140 {
1141  return const_cast<KActionCollection *>( &m_ownActions );
1142 }
1143 
1144 TQString KonqPopupMenu::mimeType() const
1145 {
1146  return m_sMimeType;
1147 }
1148 
1149 KonqPopupMenu::ProtocolInfo KonqPopupMenu::protocolInfo() const
1150 {
1151  return m_info;
1152 }
1153 
1154 void KonqPopupMenu::addPlugins()
1155 {
1156  // search for Konq_PopupMenuPlugins inspired by simons kpropsdlg
1157  //search for a plugin with the right protocol
1158  KTrader::OfferList plugin_offers;
1159  unsigned int pluginCount = 0;
1160  plugin_offers = KTrader::self()->query( m_sMimeType.isNull() ? TQString::fromLatin1( "all/all" ) : m_sMimeType, "'KonqPopupMenu/Plugin' in ServiceTypes");
1161  if ( plugin_offers.isEmpty() )
1162  return; // no plugins installed do not bother about it
1163 
1164  KTrader::OfferList::ConstIterator iterator = plugin_offers.begin();
1165  KTrader::OfferList::ConstIterator end = plugin_offers.end();
1166 
1167  addGroup( "plugins" );
1168  // travers the offerlist
1169  for(; iterator != end; ++iterator, ++pluginCount ) {
1170  //kdDebug() << (*iterator)->library() << endl;
1171  KonqPopupMenuPlugin *plugin =
1172  KParts::ComponentFactory::
1173  createInstanceFromLibrary<KonqPopupMenuPlugin>( TQFile::encodeName( (*iterator)->library() ),
1174  TQT_TQOBJECT(this),
1175  (*iterator)->name().latin1() );
1176  if ( !plugin )
1177  continue;
1178  // This make the kuick plugin insert its stuff above "Properties"
1179  TQString pluginClientName = TQString::fromLatin1( "Plugin%1" ).arg( pluginCount );
1180  addMerge( pluginClientName );
1181  plugin->domDocument().documentElement().setAttribute( "name", pluginClientName );
1182  m_pluginList.append( plugin );
1183  insertChildClient( plugin );
1184  }
1185 
1186  // ## Where is this used?
1187  addMerge( "plugins" );
1188 }
1189 
1190 KURL KonqPopupMenu::url() const // ### should be viewURL()
1191 {
1192  return m_sViewURL;
1193 }
1194 
1195 KFileItemList KonqPopupMenu::fileItemList() const
1196 {
1197  return m_lstItems;
1198 }
1199 
1200 KURL::List KonqPopupMenu::popupURLList() const
1201 {
1202  return m_lstPopupURLs;
1203 }
1204 
1209 KonqPopupMenuPlugin::KonqPopupMenuPlugin( KonqPopupMenu *parent, const char *name )
1210  : TQObject( parent, name )
1211 {
1212 }
1213 
1214 KonqPopupMenuPlugin::~KonqPopupMenuPlugin()
1215 {
1216 }
1217 
1218 #include "konq_popupmenu.moc"

libkonq

Skip menu "libkonq"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

libkonq

Skip menu "libkonq"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for libkonq by doxygen 1.8.1.2
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |