• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KIO

  • sources
  • kde-4.14
  • kdelibs
  • kio
  • kio
kfileitemactions.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE project
2  Copyright (C) 1998-2009 David Faure <faure@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify
5  it under the terms of the GNU Library General Public License as published
6  by the Free Software Foundation; either version 2 of the License or
7  ( at your option ) version 3 or, at the discretion of KDE e.V.
8  ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version.
9 
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.
14 
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.
19 */
20 
21 #include "kfileitemactions.h"
22 #include "kfileitemactions_p.h"
23 #include <kaction.h>
24 #include <krun.h>
25 #include <kmimetypetrader.h>
26 #include <kdebug.h>
27 #include <kdesktopfileactions.h>
28 #include <kmenu.h>
29 #include <klocale.h>
30 #include <kauthorized.h>
31 #include <kconfiggroup.h>
32 #include <kdesktopfile.h>
33 #include <kglobal.h>
34 #include <kicon.h>
35 #include <kstandarddirs.h>
36 #include <kservicetypetrader.h>
37 #include <QFile>
38 #include <QtAlgorithms>
39 
40 #include <QtDBus/QtDBus>
41 
42 static bool KIOSKAuthorizedAction(const KConfigGroup& cfg)
43 {
44  if (!cfg.hasKey("X-KDE-AuthorizeAction")) {
45  return true;
46  }
47  const QStringList list = cfg.readEntry("X-KDE-AuthorizeAction", QStringList());
48  for(QStringList::ConstIterator it = list.constBegin();
49  it != list.constEnd(); ++it) {
50  if (!KAuthorized::authorize((*it).trimmed())) {
51  return false;
52  }
53  }
54  return true;
55 }
56 
57 // This helper class stores the .desktop-file actions and the servicemenus
58 // in order to support X-KDE-Priority and X-KDE-Submenu.
59 namespace KIO {
60 class PopupServices
61 {
62 public:
63  ServiceList& selectList(const QString& priority, const QString& submenuName);
64 
65  ServiceList builtin;
66  ServiceList user, userToplevel, userPriority;
67  QMap<QString, ServiceList> userSubmenus, userToplevelSubmenus, userPrioritySubmenus;
68 };
69 
70 ServiceList& PopupServices::selectList(const QString& priority, const QString& submenuName)
71 {
72  // we use the categories .desktop entry to define submenus
73  // if none is defined, we just pop it in the main menu
74  if (submenuName.isEmpty()) {
75  if (priority == "TopLevel") {
76  return userToplevel;
77  } else if (priority == "Important") {
78  return userPriority;
79  }
80  } else if (priority == "TopLevel") {
81  return userToplevelSubmenus[submenuName];
82  } else if (priority == "Important") {
83  return userPrioritySubmenus[submenuName];
84  } else {
85  return userSubmenus[submenuName];
86  }
87  return user;
88 }
89 } // namespace
90 
92 
93 KFileItemActionsPrivate::KFileItemActionsPrivate(KFileItemActions *qq)
94  : QObject(),
95  q(qq),
96  m_executeServiceActionGroup(static_cast<QWidget *>(0)),
97  m_runApplicationActionGroup(static_cast<QWidget *>(0)),
98  m_parentWidget(0)
99 {
100  QObject::connect(&m_executeServiceActionGroup, SIGNAL(triggered(QAction*)),
101  this, SLOT(slotExecuteService(QAction*)));
102  QObject::connect(&m_runApplicationActionGroup, SIGNAL(triggered(QAction*)),
103  this, SLOT(slotRunApplication(QAction*)));
104 }
105 
106 KFileItemActionsPrivate::~KFileItemActionsPrivate()
107 {
108  qDeleteAll(m_ownActions);
109 }
110 
111 int KFileItemActionsPrivate::insertServicesSubmenus(const QMap<QString, ServiceList>& submenus,
112  QMenu* menu,
113  bool isBuiltin)
114 {
115  int count = 0;
116  QMap<QString, ServiceList>::ConstIterator it;
117  for (it = submenus.begin(); it != submenus.end(); ++it) {
118  if (it.value().isEmpty()) {
119  //avoid empty sub-menus
120  continue;
121  }
122 
123  QMenu* actionSubmenu = new KMenu(menu);
124  actionSubmenu->setTitle(it.key());
125  actionSubmenu->menuAction()->setObjectName("services_submenu"); // for the unittest
126  menu->addMenu(actionSubmenu);
127  count += insertServices(it.value(), actionSubmenu, isBuiltin);
128  }
129 
130  return count;
131 }
132 
133 int KFileItemActionsPrivate::insertServices(const ServiceList& list,
134  QMenu* menu,
135  bool isBuiltin)
136 {
137  int count = 0;
138  ServiceList::const_iterator it = list.begin();
139  for(; it != list.end(); ++it) {
140  if ((*it).isSeparator()) {
141  const QList<QAction*> actions = menu->actions();
142  if (!actions.isEmpty() && !actions.last()->isSeparator()) {
143  menu->addSeparator();
144  }
145  continue;
146  }
147 
148  if (isBuiltin || !(*it).noDisplay()) {
149  KAction *act = new KAction(m_parentWidget);
150  m_ownActions.append(act);
151  act->setObjectName("menuaction"); // for the unittest
152  QString text = (*it).text();
153  text.replace('&',"&&");
154  act->setText(text);
155  if (!(*it).icon().isEmpty()) {
156  act->setIcon(KIcon((*it).icon()));
157  }
158  act->setData(QVariant::fromValue(*it));
159  m_executeServiceActionGroup.addAction(act);
160 
161  menu->addAction(act); // Add to toplevel menu
162  ++count;
163  }
164  }
165 
166  return count;
167 }
168 
169 void KFileItemActionsPrivate::slotExecuteService(QAction* act)
170 {
171  KServiceAction serviceAction = act->data().value<KServiceAction>();
172  if (KAuthorized::authorizeKAction(serviceAction.name())) {
173  KDesktopFileActions::executeService(m_props.urlList(), serviceAction);
174  }
175 }
176 
178 
179 KFileItemActions::KFileItemActions(QObject* parent)
180  : QObject(parent), d(new KFileItemActionsPrivate(this))
181 {
182 }
183 
184 
185 KFileItemActions::~KFileItemActions()
186 {
187  delete d;
188 }
189 
190 void KFileItemActions::setItemListProperties(const KFileItemListProperties& itemListProperties)
191 {
192  d->m_props = itemListProperties;
193 
194  d->m_mimeTypeList.clear();
195  const KFileItemList items = d->m_props.items();
196  KFileItemList::const_iterator kit = items.constBegin();
197  const KFileItemList::const_iterator kend = items.constEnd();
198  for (; kit != kend; ++kit) {
199  if (!d->m_mimeTypeList.contains((*kit).mimetype()))
200  d->m_mimeTypeList << (*kit).mimetype();
201  }
202 }
203 
204 int KFileItemActions::addServiceActionsTo(QMenu* mainMenu)
205 {
206  const KFileItemList items = d->m_props.items();
207  const KFileItem firstItem = items.first();
208  const QString protocol = firstItem.url().protocol(); // assumed to be the same for all items
209  const bool isLocal = !firstItem.localPath().isEmpty();
210  const bool isSingleLocal = items.count() == 1 && isLocal;
211  const KUrl::List urlList = d->m_props.urlList();
212 
213  KIO::PopupServices s;
214 
215  // 1 - Look for builtin and user-defined services
216  if (isSingleLocal && (d->m_props.mimeType() == "application/x-desktop" || // .desktop file
217  d->m_props.mimeType() == "inode/blockdevice")) { // dev file
218  // get builtin services, like mount/unmount
219  const QString path = firstItem.localPath();
220  s.builtin = KDesktopFileActions::builtinServices(path);
221  KDesktopFile desktopFile(path);
222  KConfigGroup cfg = desktopFile.desktopGroup();
223  const QString priority = cfg.readEntry("X-KDE-Priority");
224  const QString submenuName = cfg.readEntry("X-KDE-Submenu");
225 #if 0
226  if (cfg.readEntry("Type") == "Link") {
227  d->m_url = cfg.readEntry("URL");
228  // TODO: Do we want to make all the actions apply on the target
229  // of the .desktop file instead of the .desktop file itself?
230  }
231 #endif
232  ServiceList& list = s.selectList(priority, submenuName);
233  list = KDesktopFileActions::userDefinedServices(path, desktopFile, true /*isLocal*/);
234  }
235 
236  // 2 - Look for "servicemenus" bindings (user-defined services)
237 
238  // first check the .directory if this is a directory
239  if (d->m_props.isDirectory() && isSingleLocal) {
240  QString dotDirectoryFile = KUrl::fromPath(firstItem.localPath()).path(KUrl::AddTrailingSlash).append(".directory");
241  if (QFile::exists(dotDirectoryFile)) {
242  const KDesktopFile desktopFile(dotDirectoryFile);
243  const KConfigGroup cfg = desktopFile.desktopGroup();
244 
245  if (KIOSKAuthorizedAction(cfg)) {
246  const QString priority = cfg.readEntry("X-KDE-Priority");
247  const QString submenuName = cfg.readEntry("X-KDE-Submenu");
248  ServiceList& list = s.selectList(priority, submenuName);
249  list += KDesktopFileActions::userDefinedServices(dotDirectoryFile, desktopFile, true);
250  }
251  }
252  }
253 
254  const KConfig config("kservicemenurc", KConfig::NoGlobals);
255  const KConfigGroup showGroup = config.group("Show");
256 
257  const QString commonMimeType = d->m_props.mimeType();
258  const QString commonMimeGroup = d->m_props.mimeGroup();
259  const KMimeType::Ptr mimeTypePtr = commonMimeType.isEmpty() ? KMimeType::Ptr() : KMimeType::mimeType(commonMimeType);
260  const KService::List entries = KServiceTypeTrader::self()->query("KonqPopupMenu/Plugin");
261  KService::List::const_iterator eEnd = entries.end();
262  for (KService::List::const_iterator it2 = entries.begin(); it2 != eEnd; ++it2) {
263  QString file = KStandardDirs::locate("services", (*it2)->entryPath());
264  KDesktopFile desktopFile(file);
265  const KConfigGroup cfg = desktopFile.desktopGroup();
266 
267  if (!KIOSKAuthorizedAction(cfg)) {
268  continue;
269  }
270 
271  if (cfg.hasKey("X-KDE-ShowIfRunning")) {
272  const QString app = cfg.readEntry("X-KDE-ShowIfRunning");
273  if (QDBusConnection::sessionBus().interface()->isServiceRegistered(app)) {
274  continue;
275  }
276  }
277  if (cfg.hasKey("X-KDE-ShowIfDBusCall")) {
278  QString calldata = cfg.readEntry("X-KDE-ShowIfDBusCall");
279  const QStringList parts = calldata.split(' ');
280  const QString &app = parts.at(0);
281  const QString &obj = parts.at(1);
282  QString interface = parts.at(2);
283  QString method;
284  int pos = interface.lastIndexOf(QLatin1Char('.'));
285  if (pos != -1) {
286  method = interface.mid(pos + 1);
287  interface.truncate(pos);
288  }
289 
290  //if (!QDBus::sessionBus().busService()->nameHasOwner(app))
291  // continue; //app does not exist so cannot send call
292 
293  QDBusMessage reply = QDBusInterface(app, obj, interface).
294  call(method, urlList.toStringList());
295  if (reply.arguments().count() < 1 || reply.arguments().at(0).type() != QVariant::Bool || !reply.arguments().at(0).toBool()) {
296  continue;
297  }
298 
299  }
300  if (cfg.hasKey("X-KDE-Protocol")) {
301  const QString theProtocol = cfg.readEntry("X-KDE-Protocol");
302  if (theProtocol.startsWith('!')) {
303  const QString excludedProtocol = theProtocol.mid(1);
304  if (excludedProtocol == protocol) {
305  continue;
306  }
307  } else if (protocol != theProtocol) {
308  continue;
309  }
310  }
311  else if (cfg.hasKey("X-KDE-Protocols")) {
312  const QStringList protocols = cfg.readEntry("X-KDE-Protocols", QStringList());
313  if (!protocols.contains(protocol)) {
314  continue;
315  }
316  }
317  else if (protocol == "trash") {
318  // Require servicemenus for the trash to ask for protocol=trash explicitly.
319  // Trashed files aren't supposed to be available for actions.
320  // One might want a servicemenu for trash.desktop itself though.
321  continue;
322  }
323 
324  if (cfg.hasKey("X-KDE-Require")) {
325  const QStringList capabilities = cfg.readEntry("X-KDE-Require" , QStringList());
326  if (capabilities.contains("Write") && !d->m_props.supportsWriting()) {
327  continue;
328  }
329  }
330  if (cfg.hasKey("Actions") || cfg.hasKey("X-KDE-GetActionMenu")) {
331  // Like KService, we support ServiceTypes, X-KDE-ServiceTypes, and MimeType.
332  QStringList types = cfg.readEntry("ServiceTypes", QStringList());
333  types += cfg.readEntry("X-KDE-ServiceTypes", QStringList());
334  types += cfg.readXdgListEntry("MimeType");
335  //kDebug() << file << types;
336 
337  if (types.isEmpty()) {
338  continue;
339  }
340  const QStringList excludeTypes = cfg.readEntry("ExcludeServiceTypes" , QStringList());
341  bool ok = false;
342 
343  // check for exact matches or a typeglob'd mimetype if we have a mimetype
344  for (QStringList::ConstIterator it = types.constBegin();
345  it != types.constEnd() && !ok;
346  ++it)
347  {
348  // first check if we have an all mimetype
349  bool checkTheMimetypes = false;
350  if (*it == "all/all" ||
351  *it == "allfiles" /*compat with KDE up to 3.0.3*/) {
352  checkTheMimetypes = true;
353  }
354 
355  // next, do we match all files?
356  if (!ok &&
357  !d->m_props.isDirectory() &&
358  (*it == "all/allfiles" || *it == "application/octet-stream")) {
359  checkTheMimetypes = true;
360  }
361 
362  // if we have a mimetype, see if we have an exact or a type globbed match
363  if (!ok && (
364  (mimeTypePtr && mimeTypePtr->is(*it)) ||
365  (!commonMimeGroup.isEmpty() &&
366  ((*it).right(1) == "*" &&
367  (*it).left((*it).indexOf('/')) == commonMimeGroup)))) {
368  checkTheMimetypes = true;
369  }
370 
371  if (checkTheMimetypes) {
372  ok = true;
373  for (QStringList::ConstIterator itex = excludeTypes.constBegin(); itex != excludeTypes.constEnd(); ++itex) {
374  if(((*itex).endsWith('*') && (*itex).left((*itex).indexOf('/')) == commonMimeGroup) ||
375  ((*itex) == commonMimeType)) {
376  ok = false;
377  break;
378  }
379  }
380  }
381  }
382 
383  if (ok) {
384  const QString priority = cfg.readEntry("X-KDE-Priority");
385  const QString submenuName = cfg.readEntry("X-KDE-Submenu");
386 
387  ServiceList& list = s.selectList(priority, submenuName);
388  const ServiceList userServices = KDesktopFileActions::userDefinedServices(*(*it2), isLocal, urlList);
389  foreach (const KServiceAction& action, userServices) {
390  if (showGroup.readEntry(action.name(), true)) {
391  list += action;
392  }
393  }
394  }
395  }
396  }
397 
398 
399 
400  QMenu* actionMenu = mainMenu;
401  int userItemCount = 0;
402  if (s.user.count() + s.userSubmenus.count() +
403  s.userPriority.count() + s.userPrioritySubmenus.count() > 1) {
404  // we have more than one item, so let's make a submenu
405  actionMenu = new KMenu(i18nc("@title:menu", "&Actions"), mainMenu);
406  actionMenu->menuAction()->setObjectName("actions_submenu"); // for the unittest
407  mainMenu->addMenu(actionMenu);
408  }
409 
410  userItemCount += d->insertServicesSubmenus(s.userPrioritySubmenus, actionMenu, false);
411  userItemCount += d->insertServices(s.userPriority, actionMenu, false);
412 
413  // see if we need to put a separator between our priority items and our regular items
414  if (userItemCount > 0 &&
415  (s.user.count() > 0 ||
416  s.userSubmenus.count() > 0 ||
417  s.builtin.count() > 0) &&
418  !actionMenu->actions().last()->isSeparator()) {
419  actionMenu->addSeparator();
420  }
421  userItemCount += d->insertServicesSubmenus(s.userSubmenus, actionMenu, false);
422  userItemCount += d->insertServices(s.user, actionMenu, false);
423  userItemCount += d->insertServices(s.builtin, mainMenu, true);
424  userItemCount += d->insertServicesSubmenus(s.userToplevelSubmenus, mainMenu, false);
425  userItemCount += d->insertServices(s.userToplevel, mainMenu, false);
426  return userItemCount;
427 }
428 
429 
430 // static
431 KService::List KFileItemActions::associatedApplications(const QStringList& mimeTypeList, const QString& traderConstraint)
432 {
433  if (!KAuthorized::authorizeKAction("openwith") || mimeTypeList.isEmpty()) {
434  return KService::List();
435  }
436 
437  const KService::List firstOffers = KMimeTypeTrader::self()->query(mimeTypeList.first(), "Application", traderConstraint);
438 
439  QList<KFileItemActionsPrivate::ServiceRank> rankings;
440  QStringList serviceList;
441 
442  // This section does two things. First, it determines which services are common to all the given mimetypes.
443  // Second, it ranks them based on their preference level in the associated applications list.
444  // The more often a service appear near the front of the list, the LOWER its score.
445 
446  for (int i = 0; i < firstOffers.count(); ++i) {
447  KFileItemActionsPrivate::ServiceRank tempRank;
448  tempRank.service = firstOffers[i];
449  tempRank.score = i;
450  rankings << tempRank;
451  serviceList << tempRank.service->storageId();
452  }
453 
454  for (int j = 1; j < mimeTypeList.count(); ++j) {
455  QStringList subservice; // list of services that support this mimetype
456  const KService::List offers = KMimeTypeTrader::self()->query(mimeTypeList[j], "Application", traderConstraint);
457  for (int i = 0; i != offers.count(); ++i) {
458  const QString serviceId = offers[i]->storageId();
459  subservice << serviceId;
460  const int idPos = serviceList.indexOf(serviceId);
461  if (idPos != -1) {
462  rankings[idPos].score += i;
463  } // else: we ignore the services that didn't support the previous mimetypes
464  }
465 
466  // Remove services which supported the previous mimetypes but don't support this one
467  for (int i = 0; i < serviceList.count(); ++i) {
468  if (!subservice.contains(serviceList[i])) {
469  serviceList.removeAt(i);
470  rankings.removeAt(i);
471  --i;
472  }
473  }
474  // Nothing left -> there is no common application for these mimetypes
475  if (rankings.isEmpty()) {
476  return KService::List();
477  }
478  }
479 
480  qSort(rankings.begin(), rankings.end(), KFileItemActionsPrivate::lessRank);
481 
482  KService::List result;
483  Q_FOREACH(const KFileItemActionsPrivate::ServiceRank& tempRank, rankings) {
484  result << tempRank.service;
485  }
486 
487  return result;
488 }
489 
490 // KMimeTypeTrader::preferredService doesn't take a constraint
491 static KService::Ptr preferredService(const QString& mimeType, const QString& constraint)
492 {
493  const KService::List services = KMimeTypeTrader::self()->query(mimeType, QString::fromLatin1("Application"), constraint);
494  return !services.isEmpty() ? services.first() : KService::Ptr();
495 }
496 
497 void KFileItemActions::addOpenWithActionsTo(QMenu* topMenu, const QString& traderConstraint)
498 {
499  if (!KAuthorized::authorizeKAction("openwith")) {
500  return;
501  }
502 
503  d->m_traderConstraint = traderConstraint;
504  KService::List offers = associatedApplications(d->m_mimeTypeList, traderConstraint);
505 
507 
508  const KFileItemList items = d->m_props.items();
509  const KFileItem firstItem = items.first();
510  const bool isLocal = firstItem.url().isLocalFile();
511  // "Open With..." for folders is really not very useful, especially for remote folders.
512  // (media:/something, or trash:/, or ftp://...)
513  if (!d->m_props.isDirectory() || isLocal) {
514  if (!topMenu->actions().isEmpty()) {
515  topMenu->addSeparator();
516  }
517 
518  KAction *runAct = new KAction(d->m_parentWidget);
519  QString runActionName;
520 
521 
522  const QStringList serviceIdList = d->listPreferredServiceIds(d->m_mimeTypeList, traderConstraint);
523  //kDebug(7010) << "serviceIdList=" << serviceIdList;
524 
525  // When selecting files with multiple mimetypes, offer either "open with <app for all>"
526  // or a generic <open> (if there are any apps associated).
527  if (d->m_mimeTypeList.count() > 1
528  && !serviceIdList.isEmpty()
529  && !(serviceIdList.count()==1 && serviceIdList.first().isEmpty())) { // empty means "no apps associated"
530 
531  d->m_ownActions.append(runAct);
532 
533  if (serviceIdList.count() == 1) {
534  const KService::Ptr app = preferredService(d->m_mimeTypeList.first(), traderConstraint);
535  runActionName = i18n("&Open with %1", app->name());
536  runAct->setIcon(KIcon(app->icon()));
537 
538  // Remove that app from the offers list (#242731)
539  for (int i = 0; i < offers.count() ; ++i) {
540  if (offers[i]->storageId() == app->storageId()) {
541  offers.removeAt(i);
542  break;
543  }
544  }
545  } else {
546  runActionName = i18n("&Open");
547  }
548 
549  runAct->setText(runActionName);
550 
551  d->m_traderConstraint = traderConstraint;
552  d->m_fileOpenList = d->m_props.items();
553  QObject::connect(runAct, SIGNAL(triggered()), d, SLOT(slotRunPreferredApplications()));
554  topMenu->addAction(runAct);
555  }
556 
557  if (!offers.isEmpty()) {
558  QMenu* menu = topMenu;
559 
560  if (offers.count() > 1) { // submenu 'open with'
561  menu = new QMenu(i18nc("@title:menu", "&Open With"), topMenu);
562  menu->menuAction()->setObjectName("openWith_submenu"); // for the unittest
563  topMenu->addMenu(menu);
564  }
565  //kDebug() << offers.count() << "offers" << topMenu << menu;
566 
567  KService::List::ConstIterator it = offers.constBegin();
568  for(; it != offers.constEnd(); it++) {
569  KAction* act = d->createAppAction(*it,
570  // no submenu -> prefix single offer
571  menu == topMenu);
572  menu->addAction(act);
573  }
574 
575  QString openWithActionName;
576  if (menu != topMenu) { // submenu
577  menu->addSeparator();
578  openWithActionName = i18nc("@action:inmenu Open With", "&Other...");
579  } else {
580  openWithActionName = i18nc("@title:menu", "&Open With...");
581  }
582  KAction *openWithAct = new KAction(d->m_parentWidget);
583  d->m_ownActions.append(openWithAct);
584  openWithAct->setText(openWithActionName);
585  openWithAct->setObjectName("openwith_browse"); // for the unittest
586  QObject::connect(openWithAct, SIGNAL(triggered()), d, SLOT(slotOpenWithDialog()));
587  menu->addAction(openWithAct);
588  }
589  else // no app offers -> Open With...
590  {
591  KAction *act = new KAction(d->m_parentWidget);
592  act->setObjectName("openwith"); // for the unittest
593  d->m_ownActions.append(act);
594  act->setText(i18nc("@title:menu", "&Open With..."));
595  QObject::connect(act, SIGNAL(triggered()), d, SLOT(slotOpenWithDialog()));
596  topMenu->addAction(act);
597  }
598 
599  }
600 }
601 
602 void KFileItemActionsPrivate::slotRunPreferredApplications()
603 {
604  const KFileItemList fileItems = m_fileOpenList;
605 
606  const QStringList mimeTypeList = listMimeTypes(fileItems);
607  const QStringList serviceIdList = listPreferredServiceIds(mimeTypeList, m_traderConstraint);
608 
609  foreach (const QString serviceId, serviceIdList) {
610  KFileItemList serviceItems;
611  foreach (const KFileItem& item, fileItems) {
612  const KService::Ptr serv = preferredService(item.mimetype(), m_traderConstraint);
613  const QString preferredServiceId = serv ? serv->storageId() : QString();
614  if (preferredServiceId == serviceId) {
615  serviceItems << item;
616  }
617  }
618 
619  if (serviceId.isEmpty()) { // empty means: no associated app for this mimetype
620  openWithByMime(serviceItems);
621  continue;
622  }
623 
624  const KService::Ptr servicePtr = KService::serviceByStorageId(serviceId);
625  if (servicePtr.isNull()) {
626  KRun::displayOpenWithDialog(serviceItems.urlList(), m_parentWidget);
627  continue;
628  }
629  KRun::run(*servicePtr, serviceItems.urlList(), m_parentWidget);
630  }
631 }
632 
633 void KFileItemActions::runPreferredApplications(const KFileItemList& fileOpenList, const QString& traderConstraint)
634 {
635  d->m_fileOpenList = fileOpenList;
636  d->m_traderConstraint = traderConstraint;
637  d->slotRunPreferredApplications();
638 }
639 
640 void KFileItemActionsPrivate::openWithByMime(const KFileItemList& fileItems)
641 {
642  const QStringList mimeTypeList = listMimeTypes(fileItems);
643  foreach (const QString mimeType, mimeTypeList) {
644  KFileItemList mimeItems;
645  foreach (const KFileItem& item, fileItems) {
646  if (item.mimetype() == mimeType) {
647  mimeItems << item;
648  }
649  }
650  KRun::displayOpenWithDialog(mimeItems.urlList(), m_parentWidget);
651  }
652 }
653 
654 void KFileItemActionsPrivate::slotRunApplication(QAction* act)
655 {
656  // Is it an application, from one of the "Open With" actions
657  KService::Ptr app = act->data().value<KService::Ptr>();
658  Q_ASSERT(app);
659  if (app) {
660  KRun::run(*app, m_props.urlList(), m_parentWidget);
661  }
662 }
663 
664 void KFileItemActionsPrivate::slotOpenWithDialog()
665 {
666  // The item 'Other...' or 'Open With...' has been selected
667  emit q->openWithDialogAboutToBeShown();
668  KRun::displayOpenWithDialog(m_props.urlList(), m_parentWidget);
669 }
670 
671 QStringList KFileItemActionsPrivate::listMimeTypes(const KFileItemList& items)
672 {
673  QStringList mimeTypeList;
674  foreach (const KFileItem& item, items) {
675  if (!mimeTypeList.contains(item.mimetype()))
676  mimeTypeList << item.mimetype();
677  }
678  return mimeTypeList;
679 }
680 
681 QStringList KFileItemActionsPrivate::listPreferredServiceIds(const QStringList& mimeTypeList, const QString& traderConstraint)
682 {
683  QStringList serviceIdList;
684  Q_FOREACH(const QString& mimeType, mimeTypeList) {
685  const KService::Ptr serv = preferredService(mimeType, traderConstraint);
686  const QString newOffer = serv ? serv->storageId() : QString();
687  serviceIdList << newOffer;
688  }
689  serviceIdList.removeDuplicates();
690  return serviceIdList;
691 }
692 
693 KAction* KFileItemActionsPrivate::createAppAction(const KService::Ptr& service, bool singleOffer)
694 {
695  QString actionName(service->name().replace('&', "&&"));
696  if (singleOffer) {
697  actionName = i18n("Open &with %1", actionName);
698  } else {
699  actionName = i18nc("@item:inmenu Open With, %1 is application name", "%1", actionName);
700  }
701 
702  KAction *act = new KAction(m_parentWidget);
703  act->setObjectName("openwith"); // for the unittest
704  m_ownActions.append(act);
705  act->setIcon(KIcon(service->icon()));
706  act->setText(actionName);
707  act->setData(QVariant::fromValue(service));
708  m_runApplicationActionGroup.addAction(act);
709  return act;
710 }
711 
712 KAction* KFileItemActions::preferredOpenWithAction(const QString& traderConstraint)
713 {
714  const KService::List offers = associatedApplications(d->m_mimeTypeList, traderConstraint);
715  if (offers.isEmpty()) {
716  return 0;
717  }
718  return d->createAppAction(offers.first(), true);
719 }
720 
721 void KFileItemActions::setParentWidget(QWidget* widget)
722 {
723  d->m_parentWidget = widget;
724 }
KFileItemActionsPrivate::insertServicesSubmenus
int insertServicesSubmenus(const QMap< QString, ServiceList > &list, QMenu *menu, bool isBuiltin)
Definition: kfileitemactions.cpp:111
QAction::setText
void setText(const QString &text)
i18n
QString i18n(const char *text)
KFileItemActions::setItemListProperties
void setItemListProperties(const KFileItemListProperties &itemList)
Sets all the data for the next instance of the popupmenu.
Definition: kfileitemactions.cpp:190
QList::clear
void clear()
KFileItemActionsPrivate::m_ownActions
QList< KAction * > m_ownActions
Definition: kfileitemactions_p.h:86
KRun::run
static bool run(const KService &service, const KUrl::List &urls, QWidget *window, bool tempFiles=false, const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Open a list of URLs with a certain service (application).
Definition: krun.cpp:984
KSharedPtr
Definition: kprotocolmanager.h:31
KFileItemActions::runPreferredApplications
void runPreferredApplications(const KFileItemList &fileOpenList, const QString &traderConstraint)
Slot used to execute a list of files in their respective preferred application.
Definition: kfileitemactions.cpp:633
QWidget
KFileItemActions::addOpenWithActionsTo
void addOpenWithActionsTo(QMenu *menu, const QString &traderConstraint=QString())
Generate the "Open With " actions, and adds them to the menu.
Definition: kfileitemactions.cpp:497
KFileItemActionsPrivate::~KFileItemActionsPrivate
~KFileItemActionsPrivate()
Definition: kfileitemactions.cpp:106
kdebug.h
KUrl::AddTrailingSlash
KFileItemActionsPrivate
Definition: kfileitemactions_p.h:36
KFileItem::mimetype
QString mimetype() const
Returns the mimetype of the file item.
Definition: kfileitem.cpp:770
KFileItemActionsPrivate::KFileItemActionsPrivate
KFileItemActionsPrivate(KFileItemActions *qq)
Definition: kfileitemactions.cpp:93
KServiceTypeTrader::self
static KServiceTypeTrader * self()
kauthorized.h
KDesktopFileActions::userDefinedServices
QList< KServiceAction > userDefinedServices(const QString &path, bool bLocalFiles)
Returns a list of services defined by the user as possible actions on the given .desktop file...
Definition: kdesktopfileactions.cpp:230
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QAction::data
QVariant data() const
KFileItemActionsPrivate::m_runApplicationActionGroup
QActionGroup m_runApplicationActionGroup
Definition: kfileitemactions_p.h:85
QStringList::removeDuplicates
int removeDuplicates()
KMenu
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
QAction::setIcon
void setIcon(const QIcon &icon)
QList::at
const T & at(int i) const
QMap
Definition: netaccess.h:36
QMenu::addAction
void addAction(QAction *action)
QList::removeAt
void removeAt(int i)
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
QDBusMessage::arguments
QList< QVariant > arguments() const
KSharedPtr::isNull
bool isNull() const
QVariant::value
T value() const
KUrl::fromPath
static KUrl fromPath(const QString &text)
KConfig::group
KConfigGroup group(const QByteArray &group)
KFileItemActions::preferredOpenWithAction
KAction * preferredOpenWithAction(const QString &traderConstraint)
Returns an action for the preferred application only.
Definition: kfileitemactions.cpp:712
QActionGroup::addAction
QAction * addAction(QAction *action)
QDBusConnection::sessionBus
QDBusConnection sessionBus()
KFileItemActions::setParentWidget
void setParentWidget(QWidget *widget)
Set the parent widget for any dialogs being shown.
Definition: kfileitemactions.cpp:721
QFile::exists
bool exists() const
KFileItemActionsPrivate::slotRunPreferredApplications
void slotRunPreferredApplications()
Definition: kfileitemactions.cpp:602
KFileItemActions::KFileItemActions
KFileItemActions(QObject *parent=0)
Creates a KFileItemActions instance.
Definition: kfileitemactions.cpp:179
KFileItemActions
This class creates and handles the actions for a url (or urls) in a popupmenu.
Definition: kfileitemactions.h:44
kdesktopfile.h
klocale.h
KServiceAction
QList::const_iterator
i18nc
QString i18nc(const char *ctxt, const char *text)
KDesktopFileActions::builtinServices
QList< KServiceAction > builtinServices(const KUrl &url)
Returns a list of services for the given .desktop file that are handled by kio itself.
Definition: kdesktopfileactions.cpp:156
KFileItemListProperties::mimeType
QString mimeType() const
Definition: kfileitemlistproperties.cpp:170
config
KSharedConfigPtr config()
QString::lastIndexOf
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
KFileItemActionsPrivate::m_parentWidget
QWidget * m_parentWidget
Definition: kfileitemactions_p.h:87
kservicetypetrader.h
kdesktopfileactions.h
kglobal.h
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
KFileItemActionsPrivate::m_traderConstraint
QString m_traderConstraint
Definition: kfileitemactions_p.h:82
KConfig::NoGlobals
KFileItemActionsPrivate::ServiceRank::service
KService::Ptr service
Definition: kfileitemactions_p.h:53
kmenu.h
KFileItemActionsPrivate::ServiceRank
Definition: kfileitemactions_p.h:50
QObject
KService::Ptr
KSharedPtr< KService > Ptr
KFileItemActions::addServiceActionsTo
int addServiceActionsTo(QMenu *menu)
Generate the user-defined actions and submenus, and adds them to the menu.
Definition: kfileitemactions.cpp:204
KUrl::protocol
QString protocol() const
KMimeTypeTrader::query
KService::List query(const QString &mimeType, const QString &genericServiceType=QString::fromLatin1("Application"), const QString &constraint=QString()) const
QList::isEmpty
bool isEmpty() const
QObject::setObjectName
void setObjectName(const QString &name)
KFileItem::localPath
QString localPath() const
Returns the local path if isLocalFile() == true or the KIO item has a UDS_LOCAL_PATH atom...
Definition: kfileitem.cpp:602
QString::isEmpty
bool isEmpty() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
kmimetypetrader.h
KFileItemList
List of KFileItems, which adds a few helper methods to QList.
Definition: kfileitem.h:674
KIcon
KMimeTypeTrader::self
static KMimeTypeTrader * self()
KFileItemActionsPrivate::m_fileOpenList
KFileItemList m_fileOpenList
Definition: kfileitemactions_p.h:83
KConfigGroup::readXdgListEntry
QStringList readXdgListEntry(const QString &pKey, const QStringList &aDefault=QStringList()) const
QMenu::setTitle
void setTitle(const QString &title)
QList::first
T & first()
QMenu::addSeparator
QAction * addSeparator()
QString
QList< KServiceAction >
QMap::end
iterator end()
KService::List
QList< Ptr > List
QMap::begin
iterator begin()
QStringList
KRun::displayOpenWithDialog
static bool displayOpenWithDialog(const KUrl::List &lst, QWidget *window, bool tempFiles=false, const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Display the Open-With dialog for those URLs, and run the chosen application.
Definition: krun.cpp:193
QDBusInterface
KFileItemListProperties::isDirectory
bool isDirectory() const
Definition: kfileitemlistproperties.cpp:165
KFileItemListProperties::urlList
KUrl::List urlList() const
List of urls, gathered from the fileitems.
Definition: kfileitemlistproperties.cpp:160
KFileItemActionsPrivate::m_executeServiceActionGroup
QActionGroup m_executeServiceActionGroup
Definition: kfileitemactions_p.h:84
KImageIO::types
QStringList types(Mode mode=Writing)
Returns a list of all KImageIO supported formats.
Definition: kimageio.cpp:82
QAction::setData
void setData(const QVariant &userData)
kaction.h
QList::end
iterator end()
QMenu
KService::icon
QString icon() const
KFileItemListProperties
Provides information about the common properties of a group of KFileItem objects. ...
Definition: kfileitemlistproperties.h:49
preferredService
static KService::Ptr preferredService(const QString &mimeType, const QString &constraint)
Definition: kfileitemactions.cpp:491
QLatin1Char
QVariant::fromValue
QVariant fromValue(const T &value)
KDesktopFile
KFileItemActions::~KFileItemActions
~KFileItemActions()
Destructor.
Definition: kfileitemactions.cpp:185
ok
KGuiItem ok()
KConfigGroup::hasKey
bool hasKey(const QString &key) const
QMap::key
const Key key(const T &value) const
KConfigGroup
QString::replace
QString & replace(int position, int n, QChar after)
KUrl::List
krun.h
KFileItemActionsPrivate::m_props
KFileItemListProperties m_props
Definition: kfileitemactions_p.h:80
KServiceTypeTrader::query
KService::List query(const QString &servicetype, const QString &constraint=QString()) const
KConfig
KFileItemActionsPrivate::lessRank
static bool lessRank(const ServiceRank &id1, const ServiceRank &id2)
Definition: kfileitemactions_p.h:57
KFileItemActions::associatedApplications
static KService::List associatedApplications(const QStringList &mimeTypeList, const QString &traderConstraint)
Helper method used internally, can also be used for similar GUIs that show the list of associated app...
Definition: kfileitemactions.cpp:431
QString::mid
QString mid(int position, int n) const
QDBusMessage
KFileItemListProperties::items
KFileItemList items() const
List of fileitems passed to the constructor or to setItems().
Definition: kfileitemlistproperties.cpp:155
kstandarddirs.h
QMenu::addMenu
QAction * addMenu(QMenu *menu)
KService::storageId
QString storageId() const
kfileitemactions_p.h
QAction
KAction
QList::last
T & last()
QList::ConstIterator
typedef ConstIterator
KFileItemActions::openWithDialogAboutToBeShown
void openWithDialogAboutToBeShown()
Emitted before the "Open With" dialog is shown This is used e.g in folderview to close the folder pee...
KFileItemActionsPrivate::insertServices
int insertServices(const ServiceList &list, QMenu *menu, bool isBuiltin)
Definition: kfileitemactions.cpp:133
KUrl::List::toStringList
QStringList toStringList() const
KFileItemListProperties::mimeGroup
QString mimeGroup() const
Definition: kfileitemlistproperties.cpp:177
KAuthorized::authorize
bool authorize(const QString &genericAction)
kfileitemactions.h
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QStringList::indexOf
int indexOf(const QRegExp &rx, int from) const
QMenu::menuAction
QAction * menuAction() const
KServiceAction::name
QString name() const
KFileItemActionsPrivate::ServiceRank::score
int score
Definition: kfileitemactions_p.h:52
KFileItemActionsPrivate::listPreferredServiceIds
QStringList listPreferredServiceIds(const QStringList &mimeTypeList, const QString &traderConstraint)
Definition: kfileitemactions.cpp:681
QList::constEnd
const_iterator constEnd() const
QList::constBegin
const_iterator constBegin() const
KDesktopFileActions::executeService
void executeService(const KUrl::List &urls, const KServiceAction &service)
Execute service on the list of urls.
Definition: kdesktopfileactions.cpp:288
kicon.h
KUrl::isLocalFile
bool isLocalFile() const
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QWidget::actions
QList< QAction * > actions() const
KFileItemActionsPrivate::listMimeTypes
QStringList listMimeTypes(const KFileItemList &items)
Definition: kfileitemactions.cpp:671
KFileItemActionsPrivate::q
KFileItemActions *const q
Definition: kfileitemactions_p.h:79
KConfigGroup::readEntry
T readEntry(const QString &key, const T &aDefault) const
KFileItemActionsPrivate::createAppAction
KAction * createAppAction(const KService::Ptr &service, bool singleOffer)
Definition: kfileitemactions.cpp:693
KFileItemListProperties::supportsWriting
bool supportsWriting() const
Check if writing capability is supported (file managers use this mostly for directories) ...
Definition: kfileitemlistproperties.cpp:140
KDesktopFile::desktopGroup
KConfigGroup desktopGroup() const
QList::begin
iterator begin()
KAuthorized::authorizeKAction
bool authorizeKAction(const QString &action)
KFileItemList::urlList
KUrl::List urlList() const
Definition: kfileitem.cpp:1751
KFileItem::url
KUrl url() const
Returns the url of the file.
Definition: kfileitem.cpp:1543
KFileItem
A KFileItem is a generic class to handle a file, local or remote.
Definition: kfileitem.h:45
KFileItemActionsPrivate::m_mimeTypeList
QStringList m_mimeTypeList
Definition: kfileitemactions_p.h:81
kconfiggroup.h
KIOSKAuthorizedAction
static bool KIOSKAuthorizedAction(const KConfigGroup &cfg)
Definition: kfileitemactions.cpp:42
KService::serviceByStorageId
static Ptr serviceByStorageId(const QString &_storageId)
KRecentDirs::list
QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
Definition: krecentdirs.cpp:60
QMap::value
const T value(const Key &key) const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:24:53 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal