File indexing completed on 2024-04-21 05:01:48

0001 /*
0002     smb4ksharesmenu  -  Shares menu
0003 
0004     SPDX-FileCopyrightText: 2011-2023 Alexander Reinholdt <alexander.reinholdt@kdemail.net>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 // application specific includes
0009 #include "smb4ksharesmenu.h"
0010 #include "core/smb4kglobal.h"
0011 #include "core/smb4kmounter.h"
0012 #include "smb4kbookmarkdialog.h"
0013 #include "smb4kcustomsettingseditor.h"
0014 #include "smb4kpreviewdialog.h"
0015 #include "smb4ksynchronizationdialog.h"
0016 
0017 #if defined(Q_OS_LINUX)
0018 #include "smb4kmountsettings_linux.h"
0019 #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD)
0020 #include "smb4kmountsettings_bsd.h"
0021 #endif
0022 
0023 // Qt includes
0024 #include <QMap>
0025 #include <QMenu>
0026 #include <QPointer>
0027 #include <QStandardPaths>
0028 #include <QString>
0029 #include <QStringList>
0030 #include <QVariant>
0031 
0032 // KDE includes
0033 #include <KIconLoader>
0034 #include <KLocalizedString>
0035 
0036 using namespace Smb4KGlobal;
0037 
0038 Smb4KSharesMenu::Smb4KSharesMenu(QObject *parent)
0039     : KActionMenu(KDE::icon(QStringLiteral("folder-network"), QStringList(QStringLiteral("emblem-mounted"))), i18n("Mounted Shares"), parent)
0040 {
0041     //
0042     // Set up action group for the shares menus
0043     //
0044     m_menus = new QActionGroup(menu());
0045 
0046     //
0047     // Set up action group for the shares actions
0048     //
0049     m_actions = new QActionGroup(menu());
0050 
0051     //
0052     // Add the Unmount All action
0053     //
0054     m_unmountAll = new QAction(KDE::icon(QStringLiteral("system-run")), i18n("U&nmount All"), menu());
0055     m_unmountAll->setEnabled(false);
0056     connect(m_unmountAll, SIGNAL(triggered(bool)), SLOT(slotUnmountAllShares()));
0057     addAction(m_unmountAll);
0058 
0059     //
0060     // Add the separator
0061     //
0062     m_separator = addSeparator();
0063 
0064     //
0065     // Connections
0066     //
0067     connect(m_actions, SIGNAL(triggered(QAction *)), SLOT(slotShareAction(QAction *)));
0068 
0069     connect(Smb4KMounter::self(), SIGNAL(mounted(SharePtr)), SLOT(slotShareMounted(SharePtr)));
0070     connect(Smb4KMounter::self(), SIGNAL(unmounted(SharePtr)), SLOT(slotShareUnmounted(SharePtr)));
0071     connect(Smb4KMounter::self(), SIGNAL(mountedSharesListChanged()), SLOT(slotMountedSharesListChanged()));
0072 }
0073 
0074 Smb4KSharesMenu::~Smb4KSharesMenu()
0075 {
0076 }
0077 
0078 void Smb4KSharesMenu::refreshMenu()
0079 {
0080     //
0081     // Delete all shares from the menu
0082     //
0083     while (!m_menus->actions().isEmpty()) {
0084         QAction *shareMenu = m_menus->actions().takeFirst();
0085         removeAction(shareMenu);
0086         delete shareMenu;
0087     }
0088 
0089     //
0090     // Add share menus, if necessary
0091     //
0092     if (!mountedSharesList().isEmpty()) {
0093         for (const SharePtr &share : mountedSharesList()) {
0094             addShareToMenu(share);
0095         }
0096     }
0097 
0098     //
0099     // Make the separator visible, if necessary
0100     //
0101     m_separator->setVisible(!m_menus->actions().isEmpty());
0102 
0103     //
0104     // Enable or disable the Unmount All action, depending on the number of
0105     // mounted shares present.
0106     //
0107     m_unmountAll->setEnabled(((!onlyForeignMountedShares() || Smb4KMountSettings::unmountForeignShares()) && !m_menus->actions().isEmpty()));
0108 
0109     //
0110     // Make sure the correct menu entries are shown
0111     //
0112     menu()->update();
0113 
0114     //
0115     // Work around a display glitch were the first bookmark
0116     // might not be shown (see also BUG 442187)
0117     //
0118     menu()->adjustSize();
0119     QCoreApplication::processEvents();
0120 }
0121 
0122 void Smb4KSharesMenu::addShareToMenu(const SharePtr &share)
0123 {
0124     //
0125     // For sorting purposes, get the display strings of all
0126     // shares that are already in the action menu.
0127     //
0128     QStringList displayNames;
0129 
0130     for (QAction *entry : m_menus->actions()) {
0131         displayNames << entry->data().toMap().value(QStringLiteral("text")).toString();
0132     }
0133 
0134     //
0135     // Add the display string of the current share as well
0136     //
0137     displayNames << share->displayString();
0138 
0139     //
0140     // Sort the display strings
0141     //
0142     displayNames.sort();
0143 
0144     //
0145     // Create the share menu
0146     //
0147     KActionMenu *shareMenu = new KActionMenu(share->displayString(), menu());
0148     shareMenu->setIcon(share->icon());
0149 
0150     QMap<QString, QVariant> data;
0151     data[QStringLiteral("text")] = share->displayString();
0152     data[QStringLiteral("mountpoint")] = share->path();
0153 
0154     shareMenu->setData(data);
0155     m_menus->addAction(shareMenu);
0156 
0157     //
0158     // Add the unmount action to the menu
0159     //
0160     QAction *unmount = new QAction(KDE::icon(QStringLiteral("media-eject")), i18n("Unmount"), shareMenu->menu());
0161 
0162     QMap<QString, QVariant> unmountData;
0163     unmountData[QStringLiteral("type")] = QStringLiteral("unmount");
0164     unmountData[QStringLiteral("mountpoint")] = share->path();
0165 
0166     unmount->setData(unmountData);
0167     unmount->setEnabled(!share->isForeign() || Smb4KMountSettings::unmountForeignShares());
0168     shareMenu->addAction(unmount);
0169     m_actions->addAction(unmount);
0170 
0171     //
0172     // Add a separator
0173     //
0174     shareMenu->addSeparator();
0175 
0176     //
0177     // Add the bookmark action to the menu
0178     //
0179     QAction *addBookmark = new QAction(KDE::icon(QStringLiteral("bookmark-new")), i18n("Add Bookmark"), shareMenu->menu());
0180 
0181     QMap<QString, QVariant> bookmarkData;
0182     bookmarkData[QStringLiteral("type")] = QStringLiteral("bookmark");
0183     bookmarkData[QStringLiteral("mountpoint")] = share->path();
0184 
0185     addBookmark->setData(bookmarkData);
0186     shareMenu->addAction(addBookmark);
0187     m_actions->addAction(addBookmark);
0188 
0189     //
0190     // Add the custom options action to the menau
0191     //
0192     QAction *addCustomOptions = new QAction(KDE::icon(QStringLiteral("settings-configure")), i18n("Add &Custom Settings"), shareMenu->menu());
0193 
0194     QMap<QString, QVariant> customOptionsData;
0195     customOptionsData[QStringLiteral("type")] = QStringLiteral("options");
0196     customOptionsData[QStringLiteral("mountpoint")] = share->path();
0197 
0198     addCustomOptions->setData(customOptionsData);
0199     shareMenu->addAction(addCustomOptions);
0200     m_actions->addAction(addCustomOptions);
0201 
0202     //
0203     // Add the synchronization action to the menu
0204     //
0205     QAction *synchronize = new QAction(KDE::icon(QStringLiteral("folder-sync")), i18n("Synchronize"), shareMenu->menu());
0206 
0207     QMap<QString, QVariant> syncData;
0208     syncData[QStringLiteral("type")] = QStringLiteral("sync");
0209     syncData[QStringLiteral("mountpoint")] = share->path();
0210 
0211     synchronize->setData(syncData);
0212     synchronize->setEnabled(!QStandardPaths::findExecutable(QStringLiteral("rsync")).isEmpty() && !share->isInaccessible());
0213     shareMenu->addAction(synchronize);
0214     m_actions->addAction(synchronize);
0215 
0216     //
0217     // Add a separator
0218     //
0219     shareMenu->addSeparator();
0220 
0221     //
0222     // Add the Open with Konsole action to the menu
0223     //
0224     QAction *konsole = new QAction(KDE::icon(QStringLiteral("utilities-terminal")), i18n("Open with Konsole"), shareMenu->menu());
0225 
0226     QMap<QString, QVariant> konsoleData;
0227     konsoleData[QStringLiteral("type")] = QStringLiteral("konsole");
0228     konsoleData[QStringLiteral("mountpoint")] = share->path();
0229 
0230     konsole->setData(konsoleData);
0231     konsole->setEnabled(!QStandardPaths::findExecutable(QStringLiteral("konsole")).isEmpty() && !share->isInaccessible());
0232     shareMenu->addAction(konsole);
0233     m_actions->addAction(konsole);
0234 
0235     //
0236     // Add the Open with Filemanager action to the menu
0237     //
0238     QAction *filemanager = new QAction(KDE::icon(QStringLiteral("system-file-manager")), i18n("Open with File Manager"), shareMenu->menu());
0239 
0240     QMap<QString, QVariant> fileManagerData;
0241     fileManagerData[QStringLiteral("type")] = QStringLiteral("filemanager");
0242     fileManagerData[QStringLiteral("mountpoint")] = share->path();
0243 
0244     filemanager->setData(fileManagerData);
0245     filemanager->setEnabled(!share->isInaccessible());
0246     shareMenu->addAction(filemanager);
0247     m_actions->addAction(filemanager);
0248 
0249     //
0250     // Add the share menu to the action menu at the right place
0251     //
0252     if (displayNames.size() == 1) {
0253         addAction(shareMenu);
0254     } else {
0255         int index = displayNames.indexOf(share->displayString(), 0);
0256 
0257         if (index != displayNames.size() - 1) {
0258             QString displayStringBefore = displayNames.at(index + 1);
0259 
0260             for (QAction *action : m_menus->actions()) {
0261                 if (action->data().toMap().value(QStringLiteral("text")).toString() == displayStringBefore) {
0262                     insertAction(action, shareMenu);
0263                     break;
0264                 }
0265             }
0266         } else {
0267             addAction(shareMenu);
0268         }
0269     }
0270 }
0271 
0272 void Smb4KSharesMenu::removeShareFromMenu(const SharePtr &share)
0273 {
0274     //
0275     // Remove the share from the action group and the menu and delete
0276     // it. We do not need to take care of the actions in the menu. They
0277     // are delete with their parent.
0278     //
0279     for (int i = 0; i < m_menus->actions().size(); ++i) {
0280         if (m_menus->actions().at(i)->data().toMap().value(QStringLiteral("mountpoint")).toString() == share->path()) {
0281             QAction *menuAction = m_menus->actions().takeAt(i);
0282             removeAction(menuAction);
0283             delete menuAction;
0284             break;
0285         }
0286     }
0287 }
0288 
0289 /////////////////////////////////////////////////////////////////////////////
0290 // SLOT IMPLEMENTATIONS
0291 /////////////////////////////////////////////////////////////////////////////
0292 
0293 void Smb4KSharesMenu::slotShareMounted(const SharePtr &share)
0294 {
0295     addShareToMenu(share);
0296 }
0297 
0298 void Smb4KSharesMenu::slotShareUnmounted(const SharePtr &share)
0299 {
0300     removeShareFromMenu(share);
0301 }
0302 
0303 void Smb4KSharesMenu::slotUnmountAllShares()
0304 {
0305     //
0306     // Unmount all shares
0307     //
0308     Smb4KMounter::self()->unmountAllShares(false);
0309 }
0310 
0311 void Smb4KSharesMenu::slotMountedSharesListChanged()
0312 {
0313     //
0314     // Enable or disable the Unmount All action
0315     //
0316     m_unmountAll->setEnabled(((!onlyForeignMountedShares() || Smb4KMountSettings::unmountForeignShares()) && !m_menus->actions().isEmpty()));
0317 
0318     //
0319     // Make the separator visible, if necessary
0320     //
0321     m_separator->setVisible(!m_menus->actions().isEmpty());
0322 
0323     //
0324     // Make sure the correct menu entries are shown
0325     //
0326     menu()->update();
0327 
0328     //
0329     // Work around a display glitch were the first bookmark
0330     // might not be shown (see also BUG 442187)
0331     //
0332     menu()->adjustSize();
0333     QCoreApplication::processEvents();
0334 }
0335 
0336 void Smb4KSharesMenu::slotShareAction(QAction *action)
0337 {
0338     //
0339     // Create a share
0340     //
0341     SharePtr share;
0342 
0343     //
0344     // Check that we have a share related action
0345     //
0346     if (action->data().toMap().contains(QStringLiteral("type"))) {
0347         share = findShareByPath(action->data().toMap().value(QStringLiteral("mountpoint")).toString());
0348     }
0349 
0350     //
0351     // Now process the action
0352     //
0353     if (share) {
0354         QString type = action->data().toMap().value(QStringLiteral("type")).toString();
0355 
0356         if (type == QStringLiteral("unmount")) {
0357             Smb4KMounter::self()->unmountShare(share, false);
0358         } else if (type == QStringLiteral("bookmark")) {
0359             QPointer<Smb4KBookmarkDialog> bookmarkDialog = new Smb4KBookmarkDialog(menu());
0360             if (bookmarkDialog->setShares(QList<SharePtr>({share}))) {
0361                 bookmarkDialog->open();
0362             } else {
0363                 delete bookmarkDialog;
0364             }
0365         } else if (type == QStringLiteral("options")) {
0366             QPointer<Smb4KCustomSettingsEditor> customSettingsEditor = new Smb4KCustomSettingsEditor(menu());
0367             if (customSettingsEditor->setNetworkItem(share)) {
0368                 customSettingsEditor->show();
0369             } else {
0370                 delete customSettingsEditor;
0371             }
0372         } else if (type == QStringLiteral("sync")) {
0373             QPointer<Smb4KSynchronizationDialog> synchronizationDialog = new Smb4KSynchronizationDialog(menu());
0374             if (synchronizationDialog->setShare(share)) {
0375                 synchronizationDialog->show();
0376             } else {
0377                 delete synchronizationDialog;
0378             }
0379         } else if (type == QStringLiteral("konsole")) {
0380             openShare(share, Smb4KGlobal::Konsole);
0381         } else if (type == QStringLiteral("filemanager")) {
0382             openShare(share, Smb4KGlobal::FileManager);
0383         }
0384     }
0385 }