diff options
Diffstat (limited to 'src/dolphincontextmenu.cpp')
-rw-r--r-- | src/dolphincontextmenu.cpp | 494 |
1 files changed, 494 insertions, 0 deletions
diff --git a/src/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp new file mode 100644 index 0000000..7ac2a56 --- /dev/null +++ b/src/dolphincontextmenu.cpp @@ -0,0 +1,494 @@ +/*************************************************************************** + * Copyright (C) 2006 by Peter Penz ([email protected]) and * + * Cvetoslav Ludmiloff * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "dolphincontextmenu.h" + +#include <kactioncollection.h> +#include <kbookmarkmanager.h> +#include <kbookmark.h> +#include <ktrader.h> +#include <klocale.h> +#include <krun.h> +#include <qdir.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kaction.h> +#include <kpropertiesdialog.h> +#include <kdesktopfile.h> +#include <assert.h> +#include <ksortablevaluelist.h> +#include <kio/netaccess.h> +#include <konq_operations.h> + +#include "dolphin.h" +#include "dolphinview.h" +#include "editbookmarkdialog.h" +#include "dolphinsettings.h" + + +DolphinContextMenu::DolphinContextMenu(DolphinView* parent, + KFileItem* fileInfo, + const QPoint& pos) : + m_dolphinView(parent), + m_fileInfo(fileInfo), + m_pos(pos) +{ +} + +void DolphinContextMenu::open() +{ + if (m_fileInfo == 0) { + openViewportContextMenu(); + } + else { + openItemContextMenu(); + } +} + +DolphinContextMenu::~DolphinContextMenu() +{ +} + +void DolphinContextMenu::openViewportContextMenu() +{ + // Parts of the following code have been taken + // from the class KonqOperations located in + // libqonq/konq_operations.h of Konqueror. + // (Copyright (C) 2000 David Faure <[email protected]>) + + assert(m_fileInfo == 0); + const int propertiesID = 100; + const int bookmarkID = 101; + + KPopupMenu* popup = new KPopupMenu(m_dolphinView); + Dolphin& dolphin = Dolphin::mainWin(); + + // setup 'Create New' menu + KPopupMenu* createNewMenu = new KPopupMenu(); + + KAction* createFolderAction = dolphin.actionCollection()->action("create_folder"); + if (createFolderAction != 0) { + createFolderAction->plug(createNewMenu); + } + + createNewMenu->insertSeparator(); + + KAction* action = 0; + + QPtrListIterator<KAction> fileGrouptIt(dolphin.fileGroupActions()); + while ((action = fileGrouptIt.current()) != 0) { + action->plug(createNewMenu); + ++fileGrouptIt; + } + + // TODO: not used yet. See documentation of Dolphin::linkGroupActions() + // and Dolphin::linkToDeviceActions() in the header file for details. + // + //createNewMenu->insertSeparator(); + // + //QPtrListIterator<KAction> linkGroupIt(dolphin.linkGroupActions()); + //while ((action = linkGroupIt.current()) != 0) { + // action->plug(createNewMenu); + // ++linkGroupIt; + //} + // + //KPopupMenu* linkToDeviceMenu = new KPopupMenu(); + //QPtrListIterator<KAction> linkToDeviceIt(dolphin.linkToDeviceActions()); + //while ((action = linkToDeviceIt.current()) != 0) { + // action->plug(linkToDeviceMenu); + // ++linkToDeviceIt; + //} + // + //createNewMenu->insertItem(i18n("Link to Device"), linkToDeviceMenu); + + const KURL& url = dolphin.activeView()->url(); + if (url.protocol() == "trash") + { + popup->insertItem(i18n("Empty Deleted Items Folder"), emptyID); + } + else + { + popup->insertItem(SmallIcon("filenew"), i18n("Create New"), createNewMenu); + } + popup->insertSeparator(); + + KAction* pasteAction = dolphin.actionCollection()->action(KStdAction::stdName(KStdAction::Paste)); + pasteAction->plug(popup); + + // setup 'View Mode' menu + KPopupMenu* viewModeMenu = new KPopupMenu(); + + KAction* iconsMode = dolphin.actionCollection()->action("icons"); + iconsMode->plug(viewModeMenu); + + KAction* detailsMode = dolphin.actionCollection()->action("details"); + detailsMode->plug(viewModeMenu); + + KAction* previewsMode = dolphin.actionCollection()->action("previews"); + previewsMode->plug(viewModeMenu); + + popup->insertItem(i18n("View Mode"), viewModeMenu); + popup->insertSeparator(); + + popup->insertItem(i18n("Bookmark this folder"), bookmarkID); + popup->insertSeparator(); + + popup->insertItem(i18n("Properties..."), propertiesID); + + int id = popup->exec(m_pos); + if (id == emptyID) { + KonqOperations::emptyTrash(); + } + else if (id == propertiesID) { + new KPropertiesDialog(dolphin.activeView()->url()); + } + else if (id == bookmarkID) { + const KURL& url = dolphin.activeView()->url(); + KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add folder as bookmark"), + url.filename(), + url, + "bookmark"); + if (!bookmark.isNull()) { + KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager(); + KBookmarkGroup root = manager->root(); + root.addBookmark(manager, bookmark); + manager->emitChanged(root); + } + } + + popup->deleteLater(); +} + +void DolphinContextMenu::openItemContextMenu() +{ + // Parts of the following code have been taken + // from the class KonqOperations located in + // libqonq/konq_operations.h of Konqueror. + // (Copyright (C) 2000 David Faure <[email protected]>) + + assert(m_fileInfo != 0); + + KPopupMenu* popup = new KPopupMenu(m_dolphinView); + Dolphin& dolphin = Dolphin::mainWin(); + const KURL::List urls = m_dolphinView->selectedURLs(); + + const KURL& url = dolphin.activeView()->url(); + if (url.protocol() == "trash") + { + popup->insertItem(i18n("&Restore"), restoreID); + } + + // insert 'Cut', 'Copy' and 'Paste' + const KStdAction::StdAction actionNames[] = { KStdAction::Cut, KStdAction::Copy, KStdAction::Paste }; + const int count = sizeof(actionNames) / sizeof(KStdAction::StdAction); + for (int i = 0; i < count; ++i) { + KAction* action = dolphin.actionCollection()->action(KStdAction::stdName(actionNames[i])); + if (action != 0) { + action->plug(popup); + } + } + popup->insertSeparator(); + + // insert 'Rename' + KAction* renameAction = dolphin.actionCollection()->action("rename"); + renameAction->plug(popup); + + // insert 'Move to Trash' for local URLs, otherwise insert 'Delete' + if (url.isLocalFile()) { + KAction* moveToTrashAction = dolphin.actionCollection()->action("move_to_trash"); + moveToTrashAction->plug(popup); + } + else { + KAction* deleteAction = dolphin.actionCollection()->action("delete"); + deleteAction->plug(popup); + } + + // insert 'Bookmark this folder...' entry + // urls is a list of selected items, so insert boolmark menu if + // urls contains only one item, i.e. no multiple selection made + if (m_fileInfo->isDir() && (urls.count() == 1)) { + popup->insertItem(i18n("Bookmark this folder"), bookmarkID); + } + + popup->insertSeparator(); + + // Insert 'Open With...' sub menu + QValueVector<KService::Ptr> openWithVector; + const int openWithID = insertOpenWithItems(popup, openWithVector); + + // Insert 'Actions' sub menu + QValueVector<KDEDesktopMimeType::Service> actionsVector; + insertActionItems(popup, actionsVector); + + // insert 'Properties...' entry + popup->insertSeparator(); + KAction* propertiesAction = dolphin.actionCollection()->action("properties"); + propertiesAction->plug(popup); + + int id = popup->exec(m_pos); + + if (id == restoreID ) { + KonqOperations::restoreTrashedItems(urls); + } + else if (id == bookmarkID) { + const KURL selectedURL(m_fileInfo->url()); + KBookmark bookmark = EditBookmarkDialog::getBookmark(i18n("Add folder as bookmark"), + selectedURL.filename(), + selectedURL, + "bookmark"); + if (!bookmark.isNull()) { + KBookmarkManager* manager = DolphinSettings::instance().bookmarkManager(); + KBookmarkGroup root = manager->root(); + root.addBookmark(manager, bookmark); + manager->emitChanged(root); + } + } + else if (id >= actionsIDStart) { + // one of the 'Actions' items has been selected + KDEDesktopMimeType::executeService(urls, actionsVector[id - actionsIDStart]); + } + else if (id >= openWithIDStart) { + // one of the 'Open With' items has been selected + if (id == openWithID) { + // the item 'Other...' has been selected + KRun::displayOpenWithDialog(urls); + } + else { + KService::Ptr servicePtr = openWithVector[id - openWithIDStart]; + KRun::run(*servicePtr, urls); + } + } + + openWithVector.clear(); + actionsVector.clear(); + popup->deleteLater(); +} + +int DolphinContextMenu::insertOpenWithItems(KPopupMenu* popup, + QValueVector<KService::Ptr>& openWithVector) +{ + // Prepare 'Open With' sub menu. Usually a sub menu is created, where all applications + // are listed which are registered to open the item. As last entry "Other..." will be + // attached which allows to select a custom application. If no applications are registered + // no sub menu is created at all, only "Open With..." will be offered. + const KFileItemList* list = m_dolphinView->selectedItems(); + assert(list != 0); + + bool insertOpenWithItems = true; + const QString contextMimeType(m_fileInfo->mimetype()); + KFileItemListIterator mimeIt(*list); + KFileItem* item = 0; + while (insertOpenWithItems && ((item = mimeIt.current()) != 0)) { + insertOpenWithItems = (contextMimeType == item->mimetype()); + ++mimeIt; + } + + int openWithID = -1; + + if (insertOpenWithItems) { + // fill the 'Open with' sub menu with application types + const KMimeType::Ptr mimePtr = KMimeType::findByURL(m_fileInfo->url()); + KTrader::OfferList offers = KTrader::self()->query(mimePtr->name(), + "Type == 'Application'"); + int index = openWithIDStart; + if (offers.count() > 0) { + KTrader::OfferList::Iterator it; + KPopupMenu* openWithMenu = new KPopupMenu(); + for(it = offers.begin(); it != offers.end(); ++it) { + // The offer list from the KTrader returns duplicate + // application entries. Although this seems to be a configuration + // problem outside the scope of Dolphin, duplicated entries just + // will be skipped here. + const QString appName((*it)->name()); + if (!containsEntry(openWithMenu, appName)) { + openWithMenu->insertItem((*it)->pixmap(KIcon::Small), + appName, index); + openWithVector.append(*it); + ++index; + } + } + + openWithMenu->insertSeparator(); + openWithMenu->insertItem(i18n("&Other..."), index); + popup->insertItem(i18n("Open With"), openWithMenu); + } + else { + // No applications are registered, hence just offer + // a "Open With..." item instead of a sub menu containing + // only one entry. + popup->insertItem(i18n("Open With..."), openWithIDStart); + } + openWithID = index; + } + else { + // At least one of the selected items has a different MIME type. In this case + // just show a disabled "Open With..." entry. + popup->insertItem(i18n("Open With..."), openWithIDStart); + popup->setItemEnabled(openWithIDStart, false); + } + + popup->setItemEnabled(openWithID, insertOpenWithItems); + + return openWithID; +} + +void DolphinContextMenu::insertActionItems(KPopupMenu* popup, + QValueVector<KDEDesktopMimeType::Service>& actionsVector) +{ + KPopupMenu* actionsMenu = new KPopupMenu(); + + int actionsIndex = 0; + + QStringList dirs = KGlobal::dirs()->findDirs("data", "d3lphin/servicemenus/"); + + KPopupMenu* menu = 0; + for (QStringList::ConstIterator dirIt = dirs.begin(); dirIt != dirs.end(); ++dirIt) { + QDir dir(*dirIt); + QStringList entries = dir.entryList("*.desktop", QDir::Files); + + for (QStringList::ConstIterator entryIt = entries.begin(); entryIt != entries.end(); ++entryIt) { + KSimpleConfig cfg(*dirIt + *entryIt, true); + cfg.setDesktopGroup(); + if ((cfg.hasKey("Actions") || cfg.hasKey("X-KDE-GetActionMenu")) && cfg.hasKey("ServiceTypes")) { + const QStringList types = cfg.readListEntry("ServiceTypes"); + for (QStringList::ConstIterator it = types.begin(); it != types.end(); ++it) { + // check whether the mime type is equal or whether the + // mimegroup (e. g. image/*) is supported + + bool insert = false; + if ((*it) == "all/allfiles") { + // The service type is valid for all files, but not for directories. + // Check whether the selected items only consist of files... + const KFileItemList* list = m_dolphinView->selectedItems(); + assert(list != 0); + + KFileItemListIterator mimeIt(*list); + KFileItem* item = 0; + insert = true; + while (insert && ((item = mimeIt.current()) != 0)) { + insert = !item->isDir(); + ++mimeIt; + } + } + + if (!insert) { + // Check whether the MIME types of all selected files match + // to the mimetype of the service action. As soon as one MIME + // type does not match, no service menu is shown at all. + const KFileItemList* list = m_dolphinView->selectedItems(); + assert(list != 0); + + KFileItemListIterator mimeIt(*list); + KFileItem* item = 0; + insert = true; + while (insert && ((item = mimeIt.current()) != 0)) { + const QString mimeType((*mimeIt)->mimetype()); + const QString mimeGroup(mimeType.left(mimeType.find('/'))); + + insert = (*it == mimeType) || + ((*it).right(1) == "*") && + ((*it).left((*it).find('/')) == mimeGroup); + ++mimeIt; + } + } + + if (insert) { + menu = actionsMenu; + + const QString submenuName = cfg.readEntry( "X-KDE-Submenu" ); + if (!submenuName.isEmpty()) { + menu = new KPopupMenu(); + actionsMenu->insertItem(submenuName, menu, submenuID); + } + + QValueList<KDEDesktopMimeType::Service> userServices = + KDEDesktopMimeType::userDefinedServices(*dirIt + *entryIt, true); + + QValueList<KDEDesktopMimeType::Service>::Iterator serviceIt; + for (serviceIt = userServices.begin(); serviceIt != userServices.end(); ++serviceIt) { + KDEDesktopMimeType::Service service = (*serviceIt); + if (!service.m_strIcon.isEmpty()) { + menu->insertItem(SmallIcon(service.m_strIcon), + service.m_strName, + actionsIDStart + actionsIndex); + } + else { + menu->insertItem(service.m_strName, + actionsIDStart + actionsIndex); + } + actionsVector.append(service); + ++actionsIndex; + } + } + } + } + } + } + + const int itemsCount = actionsMenu->count(); + if (itemsCount == 0) { + // no actions are available at all, hence show the "Actions" + // submenu disabled + actionsMenu->setEnabled(false); + } + + if (itemsCount == 1) { + // Exactly one item is available. Instead of showing a sub menu with + // only one item, show the item directly in the root menu. + if (menu == actionsMenu) { + // The item is an action, hence show the action in the root menu. + const int id = actionsMenu->idAt(0); + const QString text(actionsMenu->text(id)); + const QIconSet* iconSet = actionsMenu->iconSet(id); + if (iconSet == 0) { + popup->insertItem(text, id); + } + else { + popup->insertItem(*iconSet, text, id); + } + } + else { + // The item is a sub menu, hence show the sub menu in the root menu. + popup->insertItem(actionsMenu->text(submenuID), menu); + } + actionsMenu->deleteLater(); + actionsMenu = 0; + } + else { + popup->insertItem(i18n("Actions"), actionsMenu); + } +} + +bool DolphinContextMenu::containsEntry(const KPopupMenu* menu, + const QString& entryName) const +{ + assert(menu != 0); + + const uint count = menu->count(); + for (uint i = 0; i < count; ++i) { + const int id = menu->idAt(i); + if (menu->text(id) == entryName) { + return true; + } + } + + return false; +} |