]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphincontextmenu.cpp
Use a KIO Job for applying the view properties recursively to sub directories.
[dolphin.git] / src / dolphincontextmenu.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) and *
3 * Cvetoslav Ludmiloff *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program 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 *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "dolphincontextmenu.h"
22
23 #include <kactioncollection.h>
24 #include <kbookmarkmanager.h>
25 #include <kbookmark.h>
26 #include <kmimetypetrader.h>
27 #include <klocale.h>
28 #include <krun.h>
29 #include <qdir.h>
30 //Added by qt3to4:
31 #include <Q3ValueList>
32 #include <kglobal.h>
33 #include <kstandarddirs.h>
34 #include <kiconloader.h>
35 #include <kaction.h>
36 #include <kpropertiesdialog.h>
37 #include <kdesktopfile.h>
38 #include <assert.h>
39 #include <kio/netaccess.h>
40 #include <kmenu.h>
41 #include <kstdaction.h>
42
43 #include "dolphinmainwindow.h"
44 #include "dolphinview.h"
45 #include "editbookmarkdialog.h"
46 #include "dolphinsettings.h"
47
48
49 DolphinContextMenu::DolphinContextMenu(DolphinView* parent,
50 KFileItem* fileInfo,
51 const QPoint& pos) :
52 m_dolphinView(parent),
53 m_fileInfo(fileInfo),
54 m_pos(pos)
55 {
56 }
57
58 void DolphinContextMenu::open()
59 {
60 if (m_fileInfo == 0) {
61 openViewportContextMenu();
62 }
63 else {
64 openItemContextMenu();
65 }
66 }
67
68 DolphinContextMenu::~DolphinContextMenu()
69 {
70 }
71
72 void DolphinContextMenu::openViewportContextMenu()
73 {
74 // Parts of the following code have been taken
75 // from the class KonqOperations located in
76 // libqonq/konq_operations.h of Konqueror.
77 // (Copyright (C) 2000 David Faure <faure@kde.org>)
78
79 assert(m_fileInfo == 0);
80
81 KMenu* popup = new KMenu(m_dolphinView);
82 DolphinMainWindow *dolphin = m_dolphinView->mainWindow();
83
84 // setup 'Create New' menu
85 KMenu* createNewMenu = new KMenu();
86
87 QAction* createFolderAction = dolphin->actionCollection()->action("create_folder");
88 if (createFolderAction != 0) {
89 createNewMenu->addAction(createFolderAction);
90 }
91
92 createNewMenu->insertSeparator();
93
94 QAction* action = 0;
95
96 Q3PtrListIterator<KAction> fileGrouptIt(dolphin->fileGroupActions());
97 while ((action = fileGrouptIt.current()) != 0) {
98 createNewMenu->addAction(action);
99 ++fileGrouptIt;
100 }
101
102 // TODO: not used yet. See documentation of Dolphin::linkGroupActions()
103 // and Dolphin::linkToDeviceActions() in the header file for details.
104 //
105 //createNewMenu->insertSeparator();
106 //
107 //QPtrListIterator<KAction> linkGroupIt(dolphin->linkGroupActions());
108 //while ((action = linkGroupIt.current()) != 0) {
109 // action->plug(createNewMenu);
110 // ++linkGroupIt;
111 //}
112 //
113 //KMenu* linkToDeviceMenu = new KMenu();
114 //QPtrListIterator<KAction> linkToDeviceIt(dolphin->linkToDeviceActions());
115 //while ((action = linkToDeviceIt.current()) != 0) {
116 // action->plug(linkToDeviceMenu);
117 // ++linkToDeviceIt;
118 //}
119 //
120 //createNewMenu->insertItem(i18n("Link to Device"), linkToDeviceMenu);
121
122 popup->insertItem(SmallIcon("filenew"), i18n("Create New"), createNewMenu);
123 popup->insertSeparator();
124
125 QAction* pasteAction = dolphin->actionCollection()->action(KStdAction::stdName(KStdAction::Paste));
126 popup->addAction(pasteAction);
127
128 // setup 'View Mode' menu
129 KMenu* viewModeMenu = new KMenu();
130
131 QAction* iconsMode = dolphin->actionCollection()->action("icons");
132 viewModeMenu->addAction(iconsMode);
133
134 QAction* detailsMode = dolphin->actionCollection()->action("details");
135 viewModeMenu->addAction(detailsMode);
136
137 QAction* previewsMode = dolphin->actionCollection()->action("previews");
138 viewModeMenu->addAction(previewsMode);
139
140 popup->insertItem(i18n("View Mode"), viewModeMenu);
141 popup->insertSeparator();
142
143 QAction *bookmarkAction = popup->addAction(i18n("Bookmark this folder"));
144 popup->insertSeparator();
145
146 QAction *propertiesAction = popup->addAction(i18n("Properties..."));
147
148 QAction *activatedAction = popup->exec(m_pos);
149 if (activatedAction == propertiesAction) {
150 new KPropertiesDialog(dolphin->activeView()->url());
151 }
152 else if (activatedAction == bookmarkAction) {
153 const KUrl& url = dolphin->activeView()->url();
154 KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add folder as bookmark"),
155 url.fileName(),
156 url,
157 "bookmark");
158 if (!bookmark.isNull()) {
159 KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
160 KBookmarkGroup root = manager->root();
161 root.addBookmark(manager, bookmark);
162 manager->emitChanged(root);
163 }
164 }
165
166 popup->deleteLater();
167 }
168
169 void DolphinContextMenu::openItemContextMenu()
170 {
171 // Parts of the following code have been taken
172 // from the class KonqOperations located in
173 // libqonq/konq_operations.h of Konqueror.
174 // (Copyright (C) 2000 David Faure <faure@kde.org>)
175
176 assert(m_fileInfo != 0);
177
178 KMenu* popup = new KMenu(m_dolphinView);
179 DolphinMainWindow* dolphin = m_dolphinView->mainWindow();
180 const KUrl::List urls = m_dolphinView->selectedUrls();
181
182 // insert 'Cut', 'Copy' and 'Paste'
183 const KStdAction::StdAction actionNames[] = { KStdAction::Cut, KStdAction::Copy, KStdAction::Paste };
184 const int count = sizeof(actionNames) / sizeof(KStdAction::StdAction);
185 for (int i = 0; i < count; ++i) {
186 QAction* action = dolphin->actionCollection()->action(KStdAction::stdName(actionNames[i]));
187 if (action)
188 popup->addAction(action);
189 }
190 popup->insertSeparator();
191
192 // insert 'Rename'
193 QAction* renameAction = dolphin->actionCollection()->action("rename");
194 popup->addAction(renameAction);
195
196 // insert 'Move to Trash' for local Urls, otherwise insert 'Delete'
197 const KUrl& url = dolphin->activeView()->url();
198 if (url.isLocalFile()) {
199 QAction* moveToTrashAction = dolphin->actionCollection()->action("move_to_trash");
200 popup->addAction(moveToTrashAction);
201 }
202 else {
203 QAction* deleteAction = dolphin->actionCollection()->action("delete");
204 popup->addAction(deleteAction);
205 }
206
207 // insert 'Bookmark this folder...' entry
208 // urls is a list of selected items, so insert boolmark menu if
209 // urls contains only one item, i.e. no multiple selection made
210 QAction *bookmarkAction = 0;
211 if (m_fileInfo->isDir() && (urls.count() == 1)) {
212 bookmarkAction = popup->addAction(i18n("Bookmark this folder"));
213 }
214
215 popup->insertSeparator();
216
217 // Insert 'Open With...' sub menu
218 Q3ValueVector<KService::Ptr> openWithVector;
219 const QList<QAction*> openWithActions = insertOpenWithItems(popup, openWithVector);
220
221 // Insert 'Actions' sub menu
222 Q3ValueVector<KDEDesktopMimeType::Service> actionsVector;
223 const QList<QAction*> serviceActions = insertActionItems(popup, actionsVector);
224
225 // insert 'Properties...' entry
226 popup->insertSeparator();
227 QAction* propertiesAction = dolphin->actionCollection()->action("properties");
228 popup->addAction(propertiesAction);
229
230 QAction *activatedAction = popup->exec(m_pos);
231
232 if (bookmarkAction!=0 && activatedAction == bookmarkAction) {
233 const KUrl selectedUrl(m_fileInfo->url());
234 KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add folder as bookmark"),
235 selectedUrl.fileName(),
236 selectedUrl,
237 "bookmark");
238 if (!bookmark.isNull()) {
239 KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager();
240 KBookmarkGroup root = manager->root();
241 root.addBookmark(manager, bookmark);
242 manager->emitChanged(root);
243 }
244 }
245 else if (serviceActions.contains(activatedAction)) {
246 // one of the 'Actions' items has been selected
247 int id = serviceActions.indexOf(activatedAction);
248 KDEDesktopMimeType::executeService(urls, actionsVector[id]);
249 }
250 else if (openWithActions.contains(activatedAction)) {
251 // one of the 'Open With' items has been selected
252 if (openWithActions.last()==activatedAction) {
253 // the item 'Other...' has been selected
254 KRun::displayOpenWithDialog(urls, m_dolphinView);
255 }
256 else {
257 int id = openWithActions.indexOf(activatedAction);
258 KService::Ptr servicePtr = openWithVector[id];
259 KRun::run(*servicePtr, urls, m_dolphinView);
260 }
261 }
262
263 openWithVector.clear();
264 actionsVector.clear();
265 popup->deleteLater();
266 }
267
268 QList<QAction*> DolphinContextMenu::insertOpenWithItems(KMenu* popup,
269 Q3ValueVector<KService::Ptr>& openWithVector)
270 {
271 // Prepare 'Open With' sub menu. Usually a sub menu is created, where all applications
272 // are listed which are registered to open the item. As last entry "Other..." will be
273 // attached which allows to select a custom application. If no applications are registered
274 // no sub menu is created at all, only "Open With..." will be offered.
275 const KFileItemList list = m_dolphinView->selectedItems();
276
277 bool insertOpenWithItems = true;
278 const QString contextMimeType(m_fileInfo->mimetype());
279 QListIterator<KFileItem*> mimeIt(list);
280 while (insertOpenWithItems && mimeIt.hasNext()) {
281 KFileItem* item = mimeIt.next();
282 insertOpenWithItems = (contextMimeType == item->mimetype());
283 }
284
285 QList<QAction*> openWithActions;
286
287 if (insertOpenWithItems) {
288 // fill the 'Open with' sub menu with application types
289 const KMimeType::Ptr mimePtr = KMimeType::findByUrl(m_fileInfo->url());
290 KService::List offers = KMimeTypeTrader::self()->query(mimePtr->name(),
291 "Application",
292 "Type == 'Application'");
293 if (offers.count() > 0) {
294 KService::List::Iterator it;
295 KMenu* openWithMenu = new KMenu();
296 for(it = offers.begin(); it != offers.end(); ++it) {
297 // The offer list from the KTrader returns duplicate
298 // application entries. Although this seems to be a configuration
299 // problem outside the scope of Dolphin, duplicated entries just
300 // will be skipped here.
301 const QString appName((*it)->name());
302 if (!containsEntry(openWithMenu, appName)) {
303 QAction *action = openWithMenu->addAction((*it)->pixmap(K3Icon::Small),
304 appName);
305 openWithVector.append(*it);
306 openWithActions << action;
307 }
308 }
309
310 openWithMenu->insertSeparator();
311 QAction *action = openWithMenu->addAction(i18n("&Other..."));
312 openWithActions << action;
313 popup->insertItem(i18n("Open With"), openWithMenu);
314 }
315 else {
316 // No applications are registered, hence just offer
317 // a "Open With..." item instead of a sub menu containing
318 // only one entry.
319 QAction *action = popup->addAction(i18n("Open With..."));
320 openWithActions << action;
321 }
322 }
323 else {
324 // At least one of the selected items has a different MIME type. In this case
325 // just show a disabled "Open With..." entry.
326 QAction *action = popup->addAction(i18n("Open With..."));
327 action->setEnabled(false);
328 }
329
330 return openWithActions;
331 }
332
333 QList<QAction*> DolphinContextMenu::insertActionItems(KMenu* popup,
334 Q3ValueVector<KDEDesktopMimeType::Service>& actionsVector)
335 {
336 KMenu* actionsMenu = new KMenu();
337
338 QList<QAction*> serviceActions;
339
340 QStringList dirs = KGlobal::dirs()->findDirs("data", "dolphin/servicemenus/");
341
342 KMenu* menu = 0;
343 for (QStringList::ConstIterator dirIt = dirs.begin(); dirIt != dirs.end(); ++dirIt) {
344 QDir dir(*dirIt);
345 QStringList entries = dir.entryList("*.desktop", QDir::Files);
346
347 for (QStringList::ConstIterator entryIt = entries.begin(); entryIt != entries.end(); ++entryIt) {
348 KSimpleConfig cfg(*dirIt + *entryIt, true);
349 cfg.setDesktopGroup();
350 if ((cfg.hasKey("Actions") || cfg.hasKey("X-KDE-GetActionMenu")) && cfg.hasKey("ServiceTypes")) {
351 const QStringList types = cfg.readListEntry("ServiceTypes");
352 for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it) {
353 // check whether the mime type is equal or whether the
354 // mimegroup (e. g. image/*) is supported
355
356 bool insert = false;
357 if ((*it) == "all/allfiles") {
358 // The service type is valid for all files, but not for directories.
359 // Check whether the selected items only consist of files...
360 const KFileItemList list = m_dolphinView->selectedItems();
361
362 QListIterator<KFileItem*> mimeIt(list);
363 insert = true;
364 while (insert && mimeIt.hasNext()) {
365 KFileItem* item = mimeIt.next();
366 insert = !item->isDir();
367 }
368 }
369
370 if (!insert) {
371 // Check whether the MIME types of all selected files match
372 // to the mimetype of the service action. As soon as one MIME
373 // type does not match, no service menu is shown at all.
374 const KFileItemList list = m_dolphinView->selectedItems();
375
376 QListIterator<KFileItem*> mimeIt(list);
377 insert = true;
378 while (insert && mimeIt.hasNext()) {
379 KFileItem* item = mimeIt.next();
380 const QString mimeType(item->mimetype());
381 const QString mimeGroup(mimeType.left(mimeType.indexOf('/')));
382
383 insert = (*it == mimeType) ||
384 ((*it).right(1) == "*") &&
385 ((*it).left((*it).indexOf('/')) == mimeGroup);
386 }
387 }
388
389 if (insert) {
390 menu = actionsMenu;
391
392 const QString submenuName = cfg.readEntry( "X-KDE-Submenu" );
393 if (!submenuName.isEmpty()) {
394 menu = new KMenu();
395 actionsMenu->insertItem(submenuName, menu, submenuID);
396 }
397
398 Q3ValueList<KDEDesktopMimeType::Service> userServices =
399 KDEDesktopMimeType::userDefinedServices(*dirIt + *entryIt, true);
400
401 Q3ValueList<KDEDesktopMimeType::Service>::Iterator serviceIt;
402 for (serviceIt = userServices.begin(); serviceIt != userServices.end(); ++serviceIt) {
403 KDEDesktopMimeType::Service service = (*serviceIt);
404 if (!service.m_strIcon.isEmpty()) {
405 QAction *action = menu->addAction(SmallIcon(service.m_strIcon),
406 service.m_strName);
407 serviceActions << action;
408 }
409 else {
410 QAction *action = menu->addAction(service.m_strName);
411 serviceActions << action;
412 }
413 actionsVector.append(service);
414 }
415 }
416 }
417 }
418 }
419 }
420
421 const int itemsCount = actionsMenu->count();
422 if (itemsCount == 0) {
423 // no actions are available at all, hence show the "Actions"
424 // submenu disabled
425 actionsMenu->setEnabled(false);
426 }
427
428 if (itemsCount == 1) {
429 // Exactly one item is available. Instead of showing a sub menu with
430 // only one item, show the item directly in the root menu.
431 if (menu == actionsMenu) {
432 // The item is an action, hence show the action in the root menu.
433 const int id = actionsMenu->idAt(0);
434 const QString text(actionsMenu->text(id));
435 QIcon iconSet = actionsMenu->iconSet(id);
436 if (iconSet.isNull()) {
437 QAction *action = popup->addAction(text);
438 serviceActions.clear();
439 serviceActions << action;
440 }
441 else {
442 QAction *action = popup->addAction(iconSet, text);
443 serviceActions.clear();
444 serviceActions << action;
445 }
446 }
447 else {
448 // The item is a sub menu, hence show the sub menu in the root menu.
449 popup->insertItem(actionsMenu->text(submenuID), menu);
450 }
451 actionsMenu->deleteLater();
452 actionsMenu = 0;
453 }
454 else {
455 popup->insertItem(i18n("Actions"), actionsMenu);
456 }
457
458 return serviceActions;
459 }
460
461 bool DolphinContextMenu::containsEntry(const KMenu* menu,
462 const QString& entryName) const
463 {
464 assert(menu != 0);
465
466 const uint count = menu->count();
467 for (uint i = 0; i < count; ++i) {
468 const int id = menu->idAt(i);
469 if (menu->text(id) == entryName) {
470 return true;
471 }
472 }
473
474 return false;
475 }