File indexing completed on 2025-01-19 03:50:38

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-02-15
0007  * Description : contextmenu helper class - Services methods.
0008  *
0009  * SPDX-FileCopyrightText: 2009-2011 by Andi Clemens <andi dot clemens at gmail dot com>
0010  * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "contextmenuhelper_p.h"
0017 
0018 namespace Digikam
0019 {
0020 
0021 void ContextMenuHelper::addServicesMenu(const QList<QUrl>& selectedItems)
0022 {
0023     setSelectedItems(selectedItems);
0024 
0025 #ifdef Q_OS_WIN
0026 
0027     if (selectedItems.length() == 1)
0028     {
0029         QAction* const openWith = new QAction(i18nc("@action: context menu", "Open With"), this);
0030         addAction(openWith);
0031 
0032         connect(openWith, SIGNAL(triggered()),
0033                 this, SLOT(slotOpenWith()));
0034     }
0035 
0036 #elif defined Q_OS_MAC
0037 
0038     QList<QUrl> appUrls = DServiceMenu::MacApplicationsForFiles(selectedItems);
0039 
0040     if (!appUrls.isEmpty())
0041     {
0042         QMenu* const servicesMenu    = new QMenu(d->parent);
0043         qDeleteAll(servicesMenu->actions());
0044 
0045         QAction* const serviceAction = servicesMenu->menuAction();
0046         serviceAction->setText(i18nc("@action: context menu", "Open With"));
0047 
0048         Q_FOREACH (const QUrl& aurl, appUrls)
0049         {
0050             QAction* const action = servicesMenu->addAction(DServiceMenu::MacApplicationBundleName(aurl));
0051             action->setIcon(DServiceMenu::MacApplicationBundleIcon(aurl));
0052             action->setData(aurl);
0053         }
0054 
0055         addAction(serviceAction);
0056 
0057         connect(servicesMenu, SIGNAL(triggered(QAction*)),
0058                 this, SLOT(slotOpenWith(QAction*)));
0059     }
0060 
0061 #else // LINUX
0062 
0063     KService::List offers = DServiceMenu::servicesForOpenWith(selectedItems);
0064 
0065     if (!offers.isEmpty())
0066     {
0067         QMenu* const servicesMenu    = new QMenu(d->parent);
0068         qDeleteAll(servicesMenu->actions());
0069 
0070         QAction* const serviceAction = servicesMenu->menuAction();
0071         serviceAction->setText(i18nc("@action: context menu", "Open With"));
0072 
0073         Q_FOREACH (const KService::Ptr& service, offers)
0074         {
0075             QString name          = service->name().replace(QLatin1Char('&'), QLatin1String("&&"));
0076             QAction* const action = servicesMenu->addAction(name);
0077             action->setIcon(QIcon::fromTheme(service->icon()));
0078             action->setData(service->name());
0079             d->servicesMap[name]  = service;
0080         }
0081 
0082 #   ifdef HAVE_KIO
0083 
0084         servicesMenu->addSeparator();
0085         servicesMenu->addAction(i18nc("@action: open item with other application", "Other..."));
0086 
0087         addAction(serviceAction);
0088 
0089         connect(servicesMenu, SIGNAL(triggered(QAction*)),
0090                 this, SLOT(slotOpenWith(QAction*)));
0091     }
0092     else
0093     {
0094         QAction* const serviceAction = new QAction(i18nc("@action: context menu", "Open With..."), this);
0095         addAction(serviceAction);
0096 
0097         connect(serviceAction, SIGNAL(triggered()),
0098                 this, SLOT(slotOpenWith()));
0099 
0100 #   endif // HAVE_KIO
0101 
0102     }
0103 
0104 #endif // Q_OS_WIN
0105 
0106 }
0107 
0108 void ContextMenuHelper::slotOpenWith()
0109 {
0110     // call the slot with an "empty" action
0111 
0112     slotOpenWith(nullptr);
0113 }
0114 
0115 void ContextMenuHelper::slotOpenWith(QAction* action)
0116 {
0117 
0118 #ifdef Q_OS_WIN
0119 
0120     Q_UNUSED(action);
0121 
0122     // See Bug #380065 for details.
0123 
0124     if (d->selectedItems.length() == 1)
0125     {
0126         SHELLEXECUTEINFO sei = {};
0127         sei.cbSize           = sizeof(sei);
0128         sei.fMask            = SEE_MASK_INVOKEIDLIST | SEE_MASK_NOASYNC;
0129         sei.nShow            = SW_SHOWNORMAL;
0130         sei.lpVerb           = (LPCWSTR)QString::fromLatin1("openas").utf16();
0131         sei.lpFile           = (LPCWSTR)QDir::toNativeSeparators(d->selectedItems.first().toLocalFile()).utf16();
0132         ShellExecuteEx(&sei);
0133 
0134         qCDebug(DIGIKAM_GENERAL_LOG) << "ShellExecuteEx::openas return code:" << GetLastError();
0135     }
0136 
0137 #elif defined Q_OS_MAC
0138 
0139     QList<QUrl> list = d->selectedItems;
0140     QUrl aurl        = action ? action->data().toUrl() : QUrl();
0141 
0142     if (!aurl.isEmpty())
0143     {
0144         DServiceMenu::MacOpenFilesWithApplication(list, aurl);
0145     }
0146 
0147 #else // LINUX
0148 
0149     KService::Ptr service;
0150     QList<QUrl> list = d->selectedItems;
0151     QString name     = action ? action->data().toString() : QString();
0152 
0153 #   ifdef HAVE_KIO
0154 
0155     if (name.isEmpty())
0156     {
0157         QPointer<KOpenWithDialog> dlg = new KOpenWithDialog(list);
0158 
0159         if (dlg->exec() != KOpenWithDialog::Accepted)
0160         {
0161             delete dlg;
0162             return;
0163         }
0164 
0165         service = dlg->service();
0166 
0167         if (!service)
0168         {
0169             // User entered a custom command
0170 
0171             if (!dlg->text().isEmpty())
0172             {
0173                 DServiceMenu::runFiles(dlg->text(), list);
0174             }
0175 
0176             delete dlg;
0177             return;
0178         }
0179 
0180         delete dlg;
0181     }
0182     else
0183 
0184 #   endif // HAVE_KIO
0185 
0186     {
0187         service = d->servicesMap[name];
0188     }
0189 
0190     DServiceMenu::runFiles(service, list);
0191 
0192 #endif // Q_OS_WIN
0193 
0194 }
0195 
0196 void ContextMenuHelper::slotOpenInFileManager()
0197 {
0198     DFileOperations::openInFileManager(d->selectedItems);
0199 }
0200 
0201 } // namespace Digikam