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

libkonq

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