/* Copyright 2007 Robert Knight Copyright 2007 Kevin Ottens This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // Own #include "ui/contextmenufactory.h" // Qt #include #include #include #include #include // KDE #include #include #include #include #include #include #include #include #include #include #include #include // Plasma #include #include // Local #include "core/favoritesmodel.h" #include "core/models.h" Q_DECLARE_METATYPE(QPersistentModelIndex) using namespace Kickoff; class ContextMenuFactory::Private { public: Private() : applet(0) { } QMap > viewActions; Plasma::Applet *applet; }; ContextMenuFactory::ContextMenuFactory(QObject *parent) : QObject(parent) , d(new Private) { } ContextMenuFactory::~ContextMenuFactory() { delete d; } void ContextMenuFactory::showContextMenu(QAbstractItemView *view, const QPersistentModelIndex& index, const QPoint& pos) { Q_UNUSED(pos); if (!index.isValid()) { return; } QString url = index.data(UrlRole).value(); qDebug() << "ContextMenuFactory::showContextMenu: " << url; if (url.isEmpty()) { return; } // ivan: The url handling is dirty - instead of handling it in // the source data models (that define them), we are handling // them here. So, we need to make urls from KRunner model // to behave properly if (url.startsWith(QLatin1String("krunner://"))) { url = url.remove("krunner://"); qDebug() << "ContextMenuFactory::showContextMenu: 1 " << url; if (url.startsWith(QLatin1String("services/services_"))) { url = url.remove("services/services_"); } else { return; } KService::Ptr service = KService::serviceByStorageId(url); if(!service) { return; } url = service->entryPath(); qDebug() << "ContextMenuFactory::showContextMenu: " << "KRunner service runner: " << url; } const bool isFavorite = FavoritesModel::isFavorite(url); QList actions; QAction *favoriteAction = 0; if (url.endsWith(QLatin1String(".desktop"))) { // add to / remove from favorites favoriteAction = new QAction(this); if (isFavorite) { favoriteAction->setText(i18n("Remove From Favorites")); favoriteAction->setIcon(KIcon("list-remove")); actions << favoriteAction; //exclude stuff in the leave tab } else if (KUrl(url).protocol() != "leave") { favoriteAction->setText(i18n("Add to Favorites")); favoriteAction->setIcon(KIcon("bookmark-new")); actions << favoriteAction; } } // add to desktop QAction *addToDesktopAction = new QAction(this); // add to main panel QAction *addToPanelAction = new QAction(this); //### FIXME : icons in leave-view are not properly based on a .desktop file //so you cant put them in desktop or panel //### TODO : do not forget to remove (kurl.scheme() != "leave") and kurl declaration //when proper action for such case will be provided KUrl kurl(url); if ((d->applet) && (kurl.scheme() != "leave")) { Plasma::Containment *containment = d->applet->containment(); // There might be relative paths for .desktop installed in // /usr/shar/applnk, we need to locate them bool urlFound = true; if (kurl.isRelative() && kurl.url().endsWith(QLatin1String(".desktop"))) { kurl = KStandardDirs::locate("apps", url); urlFound = !kurl.isEmpty(); } if (urlFound && containment && containment->corona()) { Plasma::Containment *desktop = containment->corona()->containmentForScreen(containment->screen()); if (desktop && desktop->immutability() == Plasma::Mutable) { addToDesktopAction->setText(i18n("Add to Desktop")); actions << addToDesktopAction; } } if (urlFound && containment && containment->immutability() == Plasma::Mutable && (containment->containmentType() == Plasma::Containment::PanelContainment || containment->containmentType() == Plasma::Containment::CustomPanelContainment)) { addToPanelAction->setText(i18n("Add to Panel")); actions << addToPanelAction; } } QAction *advancedSeparator = new QAction(this); if (actions.count() > 0) { // advanced item actions advancedSeparator->setSeparator(true); actions << advancedSeparator; } // device actions const QString udi = index.data(DeviceUdiRole).toString(); Solid::Device device(udi); Solid::StorageAccess *access = device.as(); QAction *ejectAction = 0; if (device.isValid() && access) { ejectAction = new QAction(this); if (device.is()) { ejectAction->setText(i18n("Eject")); } else { ejectAction->setText(i18n("Safely Remove")); } actions << ejectAction; } // add view specific actions QAction *viewSeparator = new QAction(this); if (view) { if (actions.count() > 0) { viewSeparator->setSeparator(true); actions << viewSeparator; } actions << viewActions(view); } //return if we added just a separator so far if (actions.count() < 2) { return; } // display menu KMenu menu; menu.addTitle(index.data(Qt::DisplayRole).value()); foreach(QAction* action, actions) { menu.addAction(action); } QAction *result = menu.exec(QCursor::pos()); if (favoriteAction && result == favoriteAction) { if (isFavorite) { FavoritesModel::remove(url); } else { FavoritesModel::add(url); } } else if (ejectAction && result == ejectAction) { if (device.is()) { Solid::OpticalDrive *drive = device.as(); drive->eject(); } else { access->teardown(); } } else if (addToDesktopAction && result == addToDesktopAction) { if (d->applet) { Plasma::Containment *containment = d->applet->containment(); if (containment) { Plasma::Corona *corona = containment->corona(); if (corona) { int vdesk = KWindowSystem::currentDesktop() - 1; Plasma::Containment *desktop = corona->containmentForScreen(containment->screen(), vdesk); //PVDA disabled? if (!desktop) { desktop = corona->containmentForScreen(containment->screen(), -1); } if (desktop) { QVariantList args; args << kurl.url() << index.data(Kickoff::IconNameRole); if (kurl.scheme() == "applications") { // it's a service group desktop->addApplet("simplelauncher", args); } else if (desktop->metaObject()->indexOfSlot("addUrls(KUrl::List)") != -1) { QMetaObject::invokeMethod(desktop, "addUrls", Qt::DirectConnection, Q_ARG(KUrl::List, KUrl::List(kurl))); } else { desktop->addApplet("icon", args); } } } } } }else if (addToPanelAction && result == addToPanelAction) { if (d->applet) { // we assume that the panel is the same containment where the kickoff is located Plasma::Containment *panel = d->applet->containment(); if (panel) { QVariantList args; args << kurl.url() << index.data(Kickoff::IconNameRole); // move it to the middle of the panel QRectF rect(panel->geometry().width() / 2, 0, 150, panel->boundingRect().height()); if (kurl.scheme() == "applications") { // it's a service group panel->addApplet("simplelauncher", args); } else { panel->addApplet("icon", args, rect); } } } } delete favoriteAction; delete addToDesktopAction; delete addToPanelAction; delete advancedSeparator; delete viewSeparator; delete ejectAction; } void ContextMenuFactory::setViewActions(QAbstractItemView *view, const QList& actions) { if (actions.isEmpty()) { d->viewActions.remove(view); } else { d->viewActions.insert(view, actions); } } QList ContextMenuFactory::viewActions(QAbstractItemView *view) const { return d->viewActions[view]; } void ContextMenuFactory::setApplet(Plasma::Applet *applet) { d->applet = applet; } #include "moc_contextmenufactory.cpp"