• 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
42static 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.
59namespace KIO {
60class PopupServices
61{
62public:
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
70ServiceList& 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
93KFileItemActionsPrivate::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
106KFileItemActionsPrivate::~KFileItemActionsPrivate()
107{
108 qDeleteAll(m_ownActions);
109}
110
111int 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
133int 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
169void 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
179KFileItemActions::KFileItemActions(QObject* parent)
180 : QObject(parent), d(new KFileItemActionsPrivate(this))
181{
182}
183
184
185KFileItemActions::~KFileItemActions()
186{
187 delete d;
188}
189
190void 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
204int 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
431KService::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
491static 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
497void 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
602void 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
633void KFileItemActions::runPreferredApplications(const KFileItemList& fileOpenList, const QString& traderConstraint)
634{
635 d->m_fileOpenList = fileOpenList;
636 d->m_traderConstraint = traderConstraint;
637 d->slotRunPreferredApplications();
638}
639
640void 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
654void 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
664void 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
671QStringList 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
681QStringList 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
693KAction* 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
712KAction* 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
721void KFileItemActions::setParentWidget(QWidget* widget)
722{
723 d->m_parentWidget = widget;
724}
KAction
KConfigGroup
KConfigGroup::hasKey
bool hasKey(const char *key) const
KConfigGroup::readXdgListEntry
QStringList readXdgListEntry(const char *pKey, const QStringList &aDefault=QStringList()) const
KConfigGroup::readEntry
QString readEntry(const char *key, const char *aDefault=0) const
KConfig
KConfig::NoGlobals
NoGlobals
KDesktopFile
KDesktopFile::desktopGroup
KConfigGroup desktopGroup() const
KFileItemActionsPrivate
Definition: kfileitemactions_p.h:37
KFileItemActionsPrivate::insertServicesSubmenus
int insertServicesSubmenus(const QMap< QString, ServiceList > &list, QMenu *menu, bool isBuiltin)
Definition: kfileitemactions.cpp:111
KFileItemActionsPrivate::insertServices
int insertServices(const ServiceList &list, QMenu *menu, bool isBuiltin)
Definition: kfileitemactions.cpp:133
KFileItemActionsPrivate::m_runApplicationActionGroup
QActionGroup m_runApplicationActionGroup
Definition: kfileitemactions_p.h:85
KFileItemActionsPrivate::m_props
KFileItemListProperties m_props
Definition: kfileitemactions_p.h:80
KFileItemActionsPrivate::KFileItemActionsPrivate
KFileItemActionsPrivate(KFileItemActions *qq)
Definition: kfileitemactions.cpp:93
KFileItemActionsPrivate::~KFileItemActionsPrivate
~KFileItemActionsPrivate()
Definition: kfileitemactions.cpp:106
KFileItemActionsPrivate::listPreferredServiceIds
QStringList listPreferredServiceIds(const QStringList &mimeTypeList, const QString &traderConstraint)
Definition: kfileitemactions.cpp:681
KFileItemActionsPrivate::m_fileOpenList
KFileItemList m_fileOpenList
Definition: kfileitemactions_p.h:83
KFileItemActionsPrivate::m_parentWidget
QWidget * m_parentWidget
Definition: kfileitemactions_p.h:87
KFileItemActionsPrivate::listMimeTypes
QStringList listMimeTypes(const KFileItemList &items)
Definition: kfileitemactions.cpp:671
KFileItemActionsPrivate::m_traderConstraint
QString m_traderConstraint
Definition: kfileitemactions_p.h:82
KFileItemActionsPrivate::m_executeServiceActionGroup
QActionGroup m_executeServiceActionGroup
Definition: kfileitemactions_p.h:84
KFileItemActionsPrivate::createAppAction
KAction * createAppAction(const KService::Ptr &service, bool singleOffer)
Definition: kfileitemactions.cpp:693
KFileItemActionsPrivate::lessRank
static bool lessRank(const ServiceRank &id1, const ServiceRank &id2)
Definition: kfileitemactions_p.h:57
KFileItemActionsPrivate::q
KFileItemActions *const q
Definition: kfileitemactions_p.h:79
KFileItemActionsPrivate::m_mimeTypeList
QStringList m_mimeTypeList
Definition: kfileitemactions_p.h:81
KFileItemActionsPrivate::slotRunPreferredApplications
void slotRunPreferredApplications()
Definition: kfileitemactions.cpp:602
KFileItemActionsPrivate::m_ownActions
QList< KAction * > m_ownActions
Definition: kfileitemactions_p.h:86
KFileItemActions
This class creates and handles the actions for a url (or urls) in a popupmenu.
Definition: kfileitemactions.h:45
KFileItemActions::addServiceActionsTo
int addServiceActionsTo(QMenu *menu)
Generate the user-defined actions and submenus, and adds them to the menu.
Definition: kfileitemactions.cpp:204
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
KFileItemActions::openWithDialogAboutToBeShown
void openWithDialogAboutToBeShown()
Emitted before the "Open With" dialog is shown This is used e.g in folderview to close the folder pee...
KFileItemActions::preferredOpenWithAction
KAction * preferredOpenWithAction(const QString &traderConstraint)
Returns an action for the preferred application only.
Definition: kfileitemactions.cpp:712
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
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
KFileItemActions::setParentWidget
void setParentWidget(QWidget *widget)
Set the parent widget for any dialogs being shown.
Definition: kfileitemactions.cpp:721
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::~KFileItemActions
~KFileItemActions()
Destructor.
Definition: kfileitemactions.cpp:185
KFileItemListProperties
Provides information about the common properties of a group of KFileItem objects.
Definition: kfileitemlistproperties.h:50
KFileItemListProperties::items
KFileItemList items() const
List of fileitems passed to the constructor or to setItems().
Definition: kfileitemlistproperties.cpp:155
KFileItemListProperties::urlList
KUrl::List urlList() const
List of urls, gathered from the fileitems.
Definition: kfileitemlistproperties.cpp:160
KFileItemListProperties::mimeGroup
QString mimeGroup() const
Definition: kfileitemlistproperties.cpp:177
KFileItemListProperties::mimeType
QString mimeType() const
Definition: kfileitemlistproperties.cpp:170
KFileItemListProperties::isDirectory
bool isDirectory() const
Definition: kfileitemlistproperties.cpp:165
KFileItemListProperties::supportsWriting
bool supportsWriting() const
Check if writing capability is supported (file managers use this mostly for directories)
Definition: kfileitemlistproperties.cpp:140
KFileItemList
List of KFileItems, which adds a few helper methods to QList<KFileItem>.
Definition: kfileitem.h:675
KFileItemList::urlList
KUrl::List urlList() const
Definition: kfileitem.cpp:1751
KFileItem
A KFileItem is a generic class to handle a file, local or remote.
Definition: kfileitem.h:46
KFileItem::mimetype
QString mimetype() const
Returns the mimetype of the file item.
Definition: kfileitem.cpp:770
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
KFileItem::url
KUrl url() const
Returns the url of the file.
Definition: kfileitem.cpp:1543
KIcon
KMenu
KMimeTypeTrader::query
KService::List query(const QString &mimeType, const QString &genericServiceType=QString::fromLatin1("Application"), const QString &constraint=QString()) const
KMimeTypeTrader::self
static KMimeTypeTrader * self()
KMimeType::mimeType
static Ptr mimeType(const QString &name, FindByNameOption options=ResolveAliases)
KMimeType::Ptr
KSharedPtr< KMimeType > Ptr
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
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
KServiceAction
KServiceAction::name
QString name() const
KServiceTypeTrader::self
static KServiceTypeTrader * self()
KServiceTypeTrader::query
KService::List query(const QString &servicetype, const QString &constraint=QString()) const
KService::serviceByStorageId
static Ptr serviceByStorageId(const QString &_storageId)
KService::Ptr
KSharedPtr< KService > Ptr
KService::List
QList< Ptr > List
KSharedPtr< KMimeType >
KSharedPtr::isNull
bool isNull() const
KStandardDirs::locate
static QString locate(const char *type, const QString &filename, const KComponentData &cData=KGlobal::mainComponent())
KUrl::List
KUrl::List::toStringList
QStringList toStringList() const
KUrl::fromPath
static KUrl fromPath(const QString &text)
KUrl::AddTrailingSlash
AddTrailingSlash
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::isLocalFile
bool isLocalFile() const
KUrl::protocol
QString protocol() const
QAction
QList< KServiceAction >
QMap
QMenu
QObject
QWidget
kaction.h
kauthorized.h
kconfiggroup.h
kdebug.h
kdesktopfile.h
kdesktopfileactions.h
preferredService
static KService::Ptr preferredService(const QString &mimeType, const QString &constraint)
Definition: kfileitemactions.cpp:491
KIOSKAuthorizedAction
static bool KIOSKAuthorizedAction(const KConfigGroup &cfg)
Definition: kfileitemactions.cpp:42
kfileitemactions.h
kfileitemactions_p.h
kglobal.h
kicon.h
klocale.h
i18n
QString i18n(const char *text)
i18nc
QString i18nc(const char *ctxt, const char *text)
kmenu.h
kmimetypetrader.h
krun.h
kservicetypetrader.h
kstandarddirs.h
KAuthorized::authorize
bool authorize(const QString &genericAction)
KAuthorized::authorizeKAction
bool authorizeKAction(const QString &action)
KDesktopFileActions::executeService
void executeService(const KUrl::List &urls, const KServiceAction &service)
Execute service on the list of urls.
Definition: kdesktopfileactions.cpp:288
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
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
config
KSharedConfigPtr config()
KIO
A namespace for KIO globals.
Definition: kbookmarkmenu.h:55
ok
KGuiItem ok()
KFileItemActionsPrivate::ServiceRank
Definition: kfileitemactions_p.h:51
KFileItemActionsPrivate::ServiceRank::score
int score
Definition: kfileitemactions_p.h:52
KFileItemActionsPrivate::ServiceRank::service
KService::Ptr service
Definition: kfileitemactions_p.h:53
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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