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