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

KIO

  • 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 }
KUrl::AddTrailingSlash
AddTrailingSlash
KIcon
KFileItemActions
This class creates and handles the actions for a url (or urls) in a popupmenu.
Definition: kfileitemactions.h:45
KFileItemActions::preferredOpenWithAction
KAction * preferredOpenWithAction(const QString &traderConstraint)
Returns an action for the preferred application only.
Definition: kfileitemactions.cpp:712
KFileItemActionsPrivate::~KFileItemActionsPrivate
~KFileItemActionsPrivate()
Definition: kfileitemactions.cpp:106
QObject
KFileItemListProperties::mimeType
QString mimeType() const
Definition: kfileitemlistproperties.cpp:170
krun.h
kstandarddirs.h
KUrl::protocol
QString protocol() const
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
kdesktopfile.h
KFileItemActionsPrivate::ServiceRank::service
KService::Ptr service
Definition: kfileitemactions_p.h:53
KConfig::NoGlobals
NoGlobals
kglobal.h
KFileItemActionsPrivate::m_runApplicationActionGroup
QActionGroup m_runApplicationActionGroup
Definition: kfileitemactions_p.h:85
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
KAuthorized::authorizeKAction
bool authorizeKAction(const QString &action)
KService::storageId
QString storageId() const
KAuthorized::authorize
bool authorize(const QString &genericAction)
kdebug.h
KFileItemList
List of KFileItems, which adds a few helper methods to QList<KFileItem>.
Definition: kfileitem.h:675
i18nc
QString i18nc(const char *ctxt, const char *text)
KFileItemActionsPrivate::KFileItemActionsPrivate
KFileItemActionsPrivate(KFileItemActions *qq)
Definition: kfileitemactions.cpp:93
KConfig
KFileItemActions::setParentWidget
void setParentWidget(QWidget *widget)
Set the parent widget for any dialogs being shown.
Definition: kfileitemactions.cpp:721
KService::Ptr
KSharedPtr< KService > Ptr
KService::List
QList< Ptr > List
KFileItemActionsPrivate::slotRunPreferredApplications
void slotRunPreferredApplications()
Definition: kfileitemactions.cpp:602
KFileItemActions::addServiceActionsTo
int addServiceActionsTo(QMenu *menu)
Generate the user-defined actions and submenus, and adds them to the menu.
Definition: kfileitemactions.cpp:204
kmimetypetrader.h
KFileItemActions::KFileItemActions
KFileItemActions(QObject *parent=0)
Creates a KFileItemActions instance.
Definition: kfileitemactions.cpp:179
KFileItemActions::setItemListProperties
void setItemListProperties(const KFileItemListProperties &itemList)
Sets all the data for the next instance of the popupmenu.
Definition: kfileitemactions.cpp:190
kauthorized.h
KRecentDirs::list
QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
Definition: krecentdirs.cpp:60
QList< KServiceAction >
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
KFileItemActions::addOpenWithActionsTo
void addOpenWithActionsTo(QMenu *menu, const QString &traderConstraint=QString())
Generate the "Open With <Application>" actions, and adds them to the menu.
Definition: kfileitemactions.cpp:497
QWidget
KImageIO::types
QStringList types(Mode mode=Writing)
Returns a list of all KImageIO supported formats.
Definition: kimageio.cpp:82
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
KFileItemListProperties::supportsWriting
bool supportsWriting() const
Check if writing capability is supported (file managers use this mostly for directories)
Definition: kfileitemlistproperties.cpp:140
preferredService
static KService::Ptr preferredService(const QString &mimeType, const QString &constraint)
Definition: kfileitemactions.cpp:491
KFileItemList::urlList
KUrl::List urlList() const
Definition: kfileitem.cpp:1751
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
QMap
KConfigGroup::readXdgListEntry
QStringList readXdgListEntry(const char *pKey, const QStringList &aDefault=QStringList()) const
KFileItemActionsPrivate::m_parentWidget
QWidget * m_parentWidget
Definition: kfileitemactions_p.h:87
KServiceAction::name
QString name() const
KMimeTypeTrader::query
KService::List query(const QString &mimeType, const QString &genericServiceType=QString::fromLatin1("Application"), const QString &constraint=QString()) const
KServiceAction::data
QVariant data() const
kicon.h
KUrl::isLocalFile
bool isLocalFile() const
KFileItemActionsPrivate::m_traderConstraint
QString m_traderConstraint
Definition: kfileitemactions_p.h:82
KFileItemActionsPrivate::m_fileOpenList
KFileItemList m_fileOpenList
Definition: kfileitemactions_p.h:83
kaction.h
KService::icon
QString icon() const
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KFileItem::url
KUrl url() const
Returns the url of the file.
Definition: kfileitem.cpp:1543
KFileItemActionsPrivate::ServiceRank
Definition: kfileitemactions_p.h:51
KFileItemListProperties::isDirectory
bool isDirectory() const
Definition: kfileitemlistproperties.cpp:165
kfileitemactions_p.h
kconfiggroup.h
kservicetypetrader.h
KSharedPtr< KMimeType >
KConfigGroup
KFileItemActionsPrivate::ServiceRank::score
int score
Definition: kfileitemactions_p.h:52
KServiceTypeTrader::self
static KServiceTypeTrader * self()
KConfigGroup::hasKey
bool hasKey(const char *key) const
config
KSharedConfigPtr config()
KFileItemActionsPrivate
Definition: kfileitemactions_p.h:37
kmenu.h
i18n
QString i18n(const char *text)
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
KIOSKAuthorizedAction
static bool KIOSKAuthorizedAction(const KConfigGroup &cfg)
Definition: kfileitemactions.cpp:42
KAction
KFileItemActionsPrivate::lessRank
static bool lessRank(const ServiceRank &id1, const ServiceRank &id2)
Definition: kfileitemactions_p.h:57
KFileItemActionsPrivate::m_executeServiceActionGroup
QActionGroup m_executeServiceActionGroup
Definition: kfileitemactions_p.h:84
KUrl::fromPath
static KUrl fromPath(const QString &text)
KMenu
KDesktopFile::desktopGroup
KConfigGroup desktopGroup() const
KSycocaEntry::name
QString name() const
KDesktopFileActions::executeService
void executeService(const KUrl::List &urls, const KServiceAction &service)
Execute service on the list of urls.
Definition: kdesktopfileactions.cpp:288
KService::serviceByStorageId
static Ptr serviceByStorageId(const QString &_storageId)
KFileItemActionsPrivate::insertServices
int insertServices(const ServiceList &list, QMenu *menu, bool isBuiltin)
Definition: kfileitemactions.cpp:133
KFileItemActionsPrivate::m_props
KFileItemListProperties m_props
Definition: kfileitemactions_p.h:80
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
kfileitemactions.h
KFileItemListProperties::mimeGroup
QString mimeGroup() const
Definition: kfileitemlistproperties.cpp:177
KMimeType::mimeType
static Ptr mimeType(const QString &name, FindByNameOption options=ResolveAliases)
KDesktopFile
KIO
A namespace for KIO globals.
Definition: kbookmarkmenu.h:55
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
KSharedPtr< KService >::isNull
bool isNull() const
KServiceAction
KUrl::List
ok
KGuiItem ok()
KServiceTypeTrader::query
KService::List query(const QString &servicetype, const QString &constraint=QString()) const
KFileItemListProperties::urlList
KUrl::List urlList() const
List of urls, gathered from the fileitems.
Definition: kfileitemlistproperties.cpp:160
KFileItem::mimetype
QString mimetype() const
Returns the mimetype of the file item.
Definition: kfileitem.cpp:770
KFileItemActions::~KFileItemActions
~KFileItemActions()
Destructor.
Definition: kfileitemactions.cpp:185
KUrl::List::toStringList
QStringList toStringList() const
KFileItemActionsPrivate::listPreferredServiceIds
QStringList listPreferredServiceIds(const QStringList &mimeTypeList, const QString &traderConstraint)
Definition: kfileitemactions.cpp:681
KFileItemActionsPrivate::m_mimeTypeList
QStringList m_mimeTypeList
Definition: kfileitemactions_p.h:81
KFileItem
A KFileItem is a generic class to handle a file, local or remote.
Definition: kfileitem.h:46
klocale.h
KMimeType::Ptr
KSharedPtr< KMimeType > Ptr
KFileItemListProperties
Provides information about the common properties of a group of KFileItem objects.
Definition: kfileitemlistproperties.h:50
KConfigGroup::readEntry
QString readEntry(const char *key, const char *aDefault=0) const
kdesktopfileactions.h
KFileItemActionsPrivate::insertServicesSubmenus
int insertServicesSubmenus(const QMap< QString, ServiceList > &list, QMenu *menu, bool isBuiltin)
Definition: kfileitemactions.cpp:111
KFileItemActionsPrivate::listMimeTypes
QStringList listMimeTypes(const KFileItemList &items)
Definition: kfileitemactions.cpp:671
KMimeTypeTrader::self
static KMimeTypeTrader * self()
KFileItemActionsPrivate::q
KFileItemActions *const q
Definition: kfileitemactions_p.h:79
KFileItemActionsPrivate::m_ownActions
QList< KAction * > m_ownActions
Definition: kfileitemactions_p.h:86
KMimeType::is
bool is(const QString &mimeTypeName) const
QMenu
KFileItemListProperties::items
KFileItemList items() const
List of fileitems passed to the constructor or to setItems().
Definition: kfileitemlistproperties.cpp:155
KFileItemActionsPrivate::createAppAction
KAction * createAppAction(const KService::Ptr &service, bool singleOffer)
Definition: kfileitemactions.cpp:693
KFileItemActions::openWithDialogAboutToBeShown
void openWithDialogAboutToBeShown()
Emitted before the "Open With" dialog is shown This is used e.g in folderview to close the folder pee...
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Aug 27 2020 00:00:00 by doxygen 1.8.20 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-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 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
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