File indexing completed on 2023-11-26 04:58:11

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