1 /* This file is part of the KDE project
2 Copyright (C) 1998-2008 David Faure <faure@kde.org>
3 Copyright (C) 2001 Holger Freyther <freyther@yahoo.com>
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.
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.
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.
21 #include "konq_popupmenu.h"
22 #include "konq_popupmenuplugin.h"
23 #include "konq_popupmenuinformation.h"
24 #include "konq_copytomenu.h"
25 #include "konq_menuactions.h"
26 #include "kpropertiesdialog.h"
28 #include "konq_operations.h"
31 #include <kbookmarkmanager.h>
32 #include <kbookmarkdialog.h>
35 #include <kprotocolmanager.h>
37 #include <kiconloader.h>
38 #include <kinputdialog.h>
39 #include <kglobalsettings.h>
40 #include <kmimetypetrader.h>
41 #include <kstandarddirs.h>
42 #include <kconfiggroup.h>
43 #include <kdesktopfile.h>
44 #include <kfileshare.h>
45 #include <kauthorized.h>
47 #include <kacceleratormanager.h>
53 iconview file: background
54 iconview file: file (with and without servicemenus)
55 iconview file: directory
56 iconview remote protocol (e.g. ftp: or fish:)
58 sidebar directory tree
59 sidebar Devices / Hard Disc
62 khtml image (www.kde.org RMB on K logo)
63 khtmlimage (same as above, then choose View image, then RMB)
64 selected text in khtml
67 trash link on the desktop
68 trashed file or directory
69 application .desktop file
70 Then the same after uninstalling kdeaddons/konq-plugins (arkplugin in particular)
73 class KonqPopupMenuPrivate
76 KonqPopupMenuPrivate(KonqPopupMenu
* qq
, KActionCollection
& actions
)
78 m_itemFlags(KParts::BrowserExtension::DefaultPopupItems
),
80 m_ownActions(static_cast<QWidget
*>(0))
83 void addNamedAction(const QString
& name
);
84 void addGroup(const QString
& name
);
86 void init(KonqPopupMenu::Flags kpf
, KParts::BrowserExtension::PopupFlags itemFlags
);
88 void slotPopupNewDir();
89 void slotPopupNewView();
90 void slotPopupEmptyTrashBin();
91 void slotPopupRestoreTrashedItems();
92 void slotPopupAddToBookmark();
93 void slotPopupMimeType();
94 void slotPopupProperties();
95 void slotOpenShareFileDialog();
99 KParts::BrowserExtension::PopupFlags m_itemFlags
;
100 KNewMenu
*m_pMenuNew
;
102 KonqPopupMenuInformation m_popupMenuInfo
;
103 KonqMenuActions m_menuActions
;
104 KonqCopyToMenu m_copyToMenu
;
105 KBookmarkManager
* m_bookmarkManager
;
106 KActionCollection
&m_actions
;
107 KActionCollection m_ownActions
; // TODO connect to statusbar for help on actions
108 KParts::BrowserExtension::ActionGroupMap m_actionGroups
;
113 KonqPopupMenu::KonqPopupMenu(const KFileItemList
&items
,
115 KActionCollection
& actions
,
118 KParts::BrowserExtension::PopupFlags flags
,
119 QWidget
* parentWidget
,
120 KBookmarkManager
*mgr
,
121 const KParts::BrowserExtension::ActionGroupMap
& actionGroups
)
122 : QMenu(parentWidget
),
123 d(new KonqPopupMenuPrivate(this, actions
))
125 d
->m_actionGroups
= actionGroups
;
126 d
->m_pMenuNew
= newMenu
;
127 d
->m_sViewURL
= viewURL
;
128 d
->m_bookmarkManager
= mgr
;
129 d
->m_popupMenuInfo
.setItems(items
);
130 d
->m_popupMenuInfo
.setParentWidget(parentWidget
);
133 KAcceleratorManager::manage(this);
136 void KonqPopupMenuPrivate::addNamedAction(const QString
& name
)
138 QAction
* act
= m_actions
.action(name
);
143 void KonqPopupMenuPrivate::init(KonqPopupMenu::Flags kpf
, KParts::BrowserExtension::PopupFlags flags
)
145 m_ownActions
.setObjectName("KonqPopupMenu::m_ownActions");
147 q
->setFont(KGlobalSettings::menuFont());
149 Q_ASSERT(m_popupMenuInfo
.items().count() >= 1);
151 bool bTrashIncluded
= false;
153 const KFileItemList lstItems
= m_popupMenuInfo
.items();
154 KFileItemList::const_iterator it
= lstItems
.constBegin();
155 const KFileItemList::const_iterator kend
= lstItems
.constEnd();
156 for ( ; it
!= kend
; ++it
)
158 const KUrl url
= (*it
).url();
159 if ( !bTrashIncluded
&& (
160 ( url
.protocol() == "trash" && url
.path().length() <= 1 ) ) ) {
161 bTrashIncluded
= true;
165 const bool isDirectory
= m_popupMenuInfo
.isDirectory();
166 const bool sReading
= m_popupMenuInfo
.capabilities().supportsReading();
167 bool sDeleting
= (m_itemFlags
& KParts::BrowserExtension::NoDeletion
) == 0
168 && m_popupMenuInfo
.capabilities().supportsDeleting();
169 const bool sWriting
= m_popupMenuInfo
.capabilities().supportsWriting();
170 const bool sMoving
= sDeleting
&& m_popupMenuInfo
.capabilities().supportsMoving();
171 const bool isLocal
= m_popupMenuInfo
.capabilities().isLocal();
173 KUrl url
= m_sViewURL
;
176 bool isTrashLink
= false;
177 bool isCurrentTrash
= false;
178 bool currentDir
= false;
180 //check if url is current directory
181 if ( lstItems
.count() == 1 )
183 KFileItem
firstPopupItem( lstItems
.first() );
184 KUrl
firstPopupURL( firstPopupItem
.url() );
185 firstPopupURL
.cleanPath();
186 //kDebug(1203) << "View path is " << url.url();
187 //kDebug(1203) << "First popup path is " << firstPopupURL.url();
188 currentDir
= firstPopupURL
.equals( url
, KUrl::CompareWithoutTrailingSlash
);
189 if ( firstPopupItem
.isDesktopFile() ) {
190 KDesktopFile
desktopFile( firstPopupItem
.localPath() );
191 const KConfigGroup cfg
= desktopFile
.desktopGroup();
192 isTrashLink
= ( cfg
.readEntry("Type") == "Link" && cfg
.readEntry("URL") == "trash:/" );
199 // isCurrentTrash: popup on trash:/ itself, or on the trash.desktop link
200 isCurrentTrash
= (firstPopupURL
.protocol() == "trash" && firstPopupURL
.path().length() <= 1)
204 const bool isIntoTrash
= (url
.protocol() == "trash") && !isCurrentTrash
; // trashed file, not trash:/ itself
206 const bool bIsLink
= (m_itemFlags
& KParts::BrowserExtension::IsLink
);
208 //kDebug() << "isLocal=" << isLocal << " url=" << url << " isCurrentTrash=" << isCurrentTrash << " isIntoTrash=" << isIntoTrash << " bTrashIncluded=" << bTrashIncluded;
210 //////////////////////////////////////////////////////////////////////////
212 addGroup( "topactions" ); // used e.g. for ShowMenuBar. includes a separator at the end
216 QAction
*actNewWindow
= 0;
218 #if 0 // TODO in the desktop code itself.
219 if (( flags
& KParts::BrowserExtension::ShowProperties
) && isOnDesktop
&&
220 !KAuthorized::authorizeKAction("editable_desktop_icons"))
222 flags
&= ~KParts::BrowserExtension::ShowProperties
; // remove flag
226 // Either 'newview' is in the actions we're given (probably in the tabhandling group)
227 // or we need to insert it ourselves (e.g. for the desktop).
228 // In the first case, actNewWindow must remain 0.
229 if ( ((kpf
& KonqPopupMenu::ShowNewWindow
) != 0) && sReading
)
231 const QString openStr
= i18n("&Open");
232 actNewWindow
= m_ownActions
.addAction( "newview" );
233 actNewWindow
->setIcon( KIcon("window-new") );
234 actNewWindow
->setText( openStr
);
235 QObject::connect(actNewWindow
, SIGNAL(triggered()), q
, SLOT(slotPopupNewView()));
238 if ( isDirectory
&& sWriting
&& !isCurrentTrash
) // A dir, and we can create things into it
240 const bool mkdirRequested
= m_itemFlags
& KParts::BrowserExtension::ShowCreateDirectory
;
241 if ( (currentDir
|| mkdirRequested
) && m_pMenuNew
) // Current dir -> add the "new" menu
243 // As requested by KNewMenu :
244 m_pMenuNew
->slotCheckUpToDate();
245 m_pMenuNew
->setPopupFiles(m_popupMenuInfo
.urlList());
247 q
->addAction( m_pMenuNew
);
250 else if (mkdirRequested
)
252 KAction
*actNewDir
= m_ownActions
.addAction( "newdir" );
253 actNewDir
->setIcon( KIcon("folder-new") );
254 actNewDir
->setText( i18n( "Create &Folder..." ) );
255 QObject::connect(actNewDir
, SIGNAL(triggered()), q
, SLOT(slotPopupNewDir()));
256 q
->addAction( actNewDir
);
259 } else if ( isIntoTrash
) {
260 // Trashed item, offer restoring
261 act
= m_ownActions
.addAction( "restore" );
262 act
->setText( i18n( "&Restore" ) );
263 QObject::connect(act
, SIGNAL(triggered()), q
, SLOT(slotPopupRestoreTrashedItems()));
267 if (m_itemFlags
& KParts::BrowserExtension::ShowNavigationItems
)
269 if (m_itemFlags
& KParts::BrowserExtension::ShowUp
)
270 addNamedAction( "go_up" );
271 addNamedAction( "go_back" );
272 addNamedAction( "go_forward" );
273 if (m_itemFlags
& KParts::BrowserExtension::ShowReload
)
274 addNamedAction( "reload" );
278 // "open in new window" is either provided by us, or by the tabhandling group
280 q
->addAction(actNewWindow
);
283 addGroup( "tabhandling" ); // includes a separator at the end
285 if (m_itemFlags
& KParts::BrowserExtension::ShowUrlOperations
) {
286 if ( !currentDir
&& sReading
) {
288 addNamedAction( "cut" );
290 addNamedAction( "copy" );
293 if ( isDirectory
&& sWriting
) {
295 addNamedAction( "paste" );
297 addNamedAction( "pasteto" );
300 if ( isCurrentTrash
)
302 act
= m_ownActions
.addAction( "emptytrash" );
303 act
->setIcon( KIcon("trash-empty") );
304 act
->setText( i18n( "&Empty Trash Bin" ) );
305 KConfig
trashConfig( "trashrc", KConfig::SimpleConfig
);
306 act
->setEnabled( !trashConfig
.group("Status").readEntry( "Empty", true ) );
307 QObject::connect(act
, SIGNAL(triggered()), q
, SLOT(slotPopupEmptyTrashBin()));
311 // This is used by KHTML, see khtml_popupmenu.rc (copy, selectAll, searchProvider etc.)
312 // and by DolphinPart (rename, trash, delete)
313 addGroup( "editactions" );
315 if (m_itemFlags
& KParts::BrowserExtension::ShowTextSelectionItems
) {
316 // OK, we have to stop here.
318 // Anything else that is provided by the part
319 addGroup( "partactions" );
323 if ( !isCurrentTrash
&& !isIntoTrash
&& (m_itemFlags
& KParts::BrowserExtension::ShowBookmark
))
328 const bool httpPage
= m_sViewURL
.protocol().startsWith("http", Qt::CaseInsensitive
);
330 caption
= i18n("&Bookmark This Page");
332 caption
= i18n("&Bookmark This Location");
334 else if (isDirectory
)
335 caption
= i18n("&Bookmark This Folder");
337 caption
= i18n("&Bookmark This Link");
339 caption
= i18n("&Bookmark This File");
341 act
= m_ownActions
.addAction( "bookmark_add" );
342 act
->setIcon( KIcon("bookmark-new") );
343 act
->setText( caption
);
344 QObject::connect(act
, SIGNAL(triggered()), q
, SLOT(slotPopupAddToBookmark()));
345 if (lstItems
.count() > 1)
346 act
->setEnabled(false);
347 if (KAuthorized::authorizeKAction("bookmarks"))
350 addGroup( "linkactions" ); // see khtml
353 // "Open With" actions
355 m_menuActions
.setPopupMenuInfo(m_popupMenuInfo
);
358 m_menuActions
.addOpenWithActionsTo(q
, "DesktopEntryName != 'kfmclient' and DesktopEntryName != 'kfmclient_dir' and DesktopEntryName != 'kfmclient_html'");
360 QList
<QAction
*> previewActions
= m_actionGroups
.value("preview");
361 if (!previewActions
.isEmpty()) {
362 if (previewActions
.count() == 1) {
363 q
->addAction(previewActions
.first());
365 QMenu
* subMenu
= new QMenu(i18n("Preview In"), q
);
366 subMenu
->menuAction()->setObjectName("preview_submenu"); // for the unittest
368 subMenu
->addActions(previewActions
);
373 // Second block, builtin + user
374 m_menuActions
.addActionsTo(q
);
378 // CopyTo/MoveTo menus
379 if (m_itemFlags
& KParts::BrowserExtension::ShowUrlOperations
) {
380 m_copyToMenu
.setItems(lstItems
);
381 m_copyToMenu
.setReadOnly(sMoving
== false);
382 m_copyToMenu
.addActionsTo(q
);
386 if ( !isCurrentTrash
&& !isIntoTrash
&& sReading
)
387 addPlugins(); // now it's time to add plugins
389 if ( (m_itemFlags
& KParts::BrowserExtension::ShowProperties
) && KPropertiesDialog::canDisplay( lstItems
) ) {
390 act
= m_ownActions
.addAction( "properties" );
391 act
->setText( i18n( "&Properties" ) );
392 QObject::connect(act
, SIGNAL(triggered()), q
, SLOT(slotPopupProperties()));
396 while ( !q
->actions().isEmpty() &&
397 q
->actions().last()->isSeparator() )
398 delete q
->actions().last();
400 if ( isDirectory
&& isLocal
) {
401 if ( KFileShare::authorization() == KFileShare::Authorized
) {
403 act
= m_ownActions
.addAction( "sharefile" );
404 act
->setText( i18n("Share") );
405 QObject::connect(act
, SIGNAL(triggered()), q
, SLOT(slotOpenShareFileDialog()));
410 // Anything else that is provided by the part
411 addGroup( "partactions" );
414 void KonqPopupMenuPrivate::slotOpenShareFileDialog()
416 KPropertiesDialog
* dlg
= new KPropertiesDialog( m_popupMenuInfo
.items(), m_popupMenuInfo
.parentWidget() );
417 dlg
->showFileSharingPage();
421 KonqPopupMenu::~KonqPopupMenu()
424 //kDebug(1203) << "~KonqPopupMenu leave";
427 void KonqPopupMenu::setURLTitle( const QString
& urlTitle
)
429 d
->m_urlTitle
= urlTitle
;
432 void KonqPopupMenuPrivate::slotPopupNewView()
434 Q_FOREACH(const KUrl
& url
, m_popupMenuInfo
.urlList()) {
435 (void) new KRun(url
, m_popupMenuInfo
.parentWidget());
439 void KonqPopupMenuPrivate::slotPopupNewDir()
441 if (m_popupMenuInfo
.urlList().empty())
444 KonqOperations::newDir(m_popupMenuInfo
.parentWidget(), m_popupMenuInfo
.urlList().first());
447 void KonqPopupMenuPrivate::slotPopupEmptyTrashBin()
449 KonqOperations::emptyTrash(m_popupMenuInfo
.parentWidget());
452 void KonqPopupMenuPrivate::slotPopupRestoreTrashedItems()
454 KonqOperations::restoreTrashedItems(m_popupMenuInfo
.urlList(), m_popupMenuInfo
.parentWidget());
457 void KonqPopupMenuPrivate::slotPopupAddToBookmark()
460 if (m_popupMenuInfo
.urlList().count() == 1) {
461 const KUrl url
= m_popupMenuInfo
.urlList().first();
462 const QString title
= m_urlTitle
.isEmpty() ? url
.prettyUrl() : m_urlTitle
;
463 KBookmarkDialog
dlg(m_bookmarkManager
, m_popupMenuInfo
.parentWidget());
464 dlg
.addBookmark(title
, url
.url());
468 root
= m_bookmarkManager
->root();
469 Q_FOREACH(const KUrl
& url
, m_popupMenuInfo
.urlList()) {
470 root
.addBookmark(url
.prettyUrl(), url
);
472 m_bookmarkManager
->emitChanged(root
);
476 void KonqPopupMenuPrivate::slotPopupMimeType()
478 KonqOperations::editMimeType(m_popupMenuInfo
.mimeType(), m_popupMenuInfo
.parentWidget());
481 void KonqPopupMenuPrivate::slotPopupProperties()
483 KPropertiesDialog::showDialog(m_popupMenuInfo
.items(), m_popupMenuInfo
.parentWidget(), false);
486 void KonqPopupMenuPrivate::addGroup(const QString
& name
)
488 QList
<QAction
*> actions
= m_actionGroups
.value(name
);
489 q
->addActions(actions
);
492 void KonqPopupMenuPrivate::addPlugins()
494 const QString commonMimeType
= m_popupMenuInfo
.mimeType();
495 const KService::List plugin_offers
= KMimeTypeTrader::self()->query(commonMimeType
.isEmpty() ? QLatin1String("application/octet-stream") : commonMimeType
, "KonqPopupMenu/Plugin", "exist Library");
497 KService::List::ConstIterator iterator
= plugin_offers
.begin();
498 const KService::List::ConstIterator end
= plugin_offers
.end();
499 for(; iterator
!= end
; ++iterator
) {
500 //kDebug() << (*iterator)->name() << (*iterator)->library();
501 KonqPopupMenuPlugin
*plugin
= (*iterator
)->createInstance
<KonqPopupMenuPlugin
>(q
);
504 plugin
->setup(&m_ownActions
, m_popupMenuInfo
, q
);
508 #include "konq_popupmenu.moc"