]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Merge branch 'release/22.04'
authorKai Uwe Broulik <kde@privat.broulik.de>
Tue, 12 Apr 2022 13:47:42 +0000 (15:47 +0200)
committerKai Uwe Broulik <kde@privat.broulik.de>
Tue, 12 Apr 2022 13:47:42 +0000 (15:47 +0200)
27 files changed:
.gitlab-ci.yml
.kde-ci.yml
CMakeLists.txt
src/CMakeLists.txt
src/dolphincontextmenu.cpp
src/dolphincontextmenu.h
src/dolphinmainwindow.cpp
src/dolphinmainwindow.h
src/dolphinpart.cpp
src/dolphinpart.h
src/kitemviews/kfileitemlisttostring.cpp [new file with mode: 0644]
src/kitemviews/kfileitemlisttostring.h [new file with mode: 0644]
src/kitemviews/kfileitemmodel.cpp
src/kitemviews/kitemlistcontroller.cpp
src/kitemviews/kstandarditemlistwidget.cpp
src/kitemviews/private/ktwofingerswipe.cpp [deleted file]
src/kitemviews/private/ktwofingerswipe.h [deleted file]
src/kitemviews/private/ktwofingertap.cpp [deleted file]
src/kitemviews/private/ktwofingertap.h [deleted file]
src/org.kde.dolphin.desktop
src/settings/contextmenu/servicemenuinstaller/servicemenuinstaller.cpp
src/trash/dolphintrash.h
src/views/dolphinview.cpp
src/views/dolphinview.h
src/views/dolphinviewactionhandler.cpp
src/views/tooltips/tooltipmanager.cpp
src/views/tooltips/tooltipmanager.h

index 84fe503fa4f1aacf1faf69490a064b6a722776f4..9b09627599143a8cfdf42d6e6961c38842a7ebec 100644 (file)
@@ -1,3 +1,4 @@
 include:
   - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/linux.yml
   - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/freebsd.yml
+  - https://invent.kde.org/sysadmin/ci-utilities/raw/master/gitlab-templates/windows.yml
index 3f3b7f8bc423ad2ed63c2106e5205408d4d6704e..18cd5eab93757f97aaab45bd6f03daeaefde7b63 100644 (file)
@@ -23,9 +23,13 @@ Dependencies:
     'frameworks/kwindowsystem': '@stable'
     'frameworks/kactivities': '@stable'
     'frameworks/kdoctools': '@stable'
-    'frameworks/baloo': '@stable'
     'frameworks/kwindowsystem': '@stable'
     'frameworks/kfilemetadata': '@stable'
-    'libraries/baloo-widgets': '@same'
     'libraries/kuserfeedback': '@stable'
     'libraries/phonon': '@stable'
+
+- 'on': ['Linux', 'FreeBSD']
+  'require':
+    'frameworks/baloo': '@stable'
+    'libraries/baloo-widgets': '@same'
+
index 96b3f4264583165df689a6d994a6157598db9b77..ae9507ef6d257cc14ac9df0e78b13b4904f9fbe0 100644 (file)
@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.16)
 
 # KDE Application Version, managed by release script
 set (RELEASE_SERVICE_VERSION_MAJOR "22")
-set (RELEASE_SERVICE_VERSION_MINOR "03")
-set (RELEASE_SERVICE_VERSION_MICRO "90")
+set (RELEASE_SERVICE_VERSION_MINOR "07")
+set (RELEASE_SERVICE_VERSION_MICRO "70")
 set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
 project(Dolphin VERSION ${RELEASE_SERVICE_VERSION})
 
@@ -67,9 +67,10 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
     Notifications
     Crash
     WindowSystem
+    WidgetsAddons
 )
 
-find_package(KUserFeedback 1.0.0)
+find_package(KUserFeedback 1.2.0)
 set_package_properties(KUserFeedback
         PROPERTIES TYPE OPTIONAL
         PURPOSE "Used for submission of telemetry data"
@@ -91,13 +92,13 @@ set_package_properties(KF5Activities PROPERTIES DESCRIPTION "KActivities librari
 
 find_package(Phonon4Qt${QT_MAJOR_VERSION} CONFIG REQUIRED)
 
-find_package(PackageKitQt5)
-set_package_properties(PackageKitQt5
+find_package(PackageKitQt${QT_MAJOR_VERSION})
+set_package_properties(PackageKitQt${QT_MAJOR_VERSION}
         PROPERTIES DESCRIPTION "Software Manager integration"
         TYPE OPTIONAL
         PURPOSE "Used in the service menu installer"
         )
-if(PackageKitQt5_FOUND)
+if(PackageKitQt${QT_MAJOR_VERSION}_FOUND)
     set(HAVE_PACKAGEKIT TRUE)
 endif()
 
index 0c1bcb2b9f2ef764e6bb9e7122ae7abd844d3a6a..364f12a74d11c514c4cabb89aa232702e42125c0 100644 (file)
@@ -61,6 +61,7 @@ add_library(dolphinprivate SHARED)
 target_sources(dolphinprivate PRIVATE
     kitemviews/kfileitemlistview.cpp
     kitemviews/kfileitemlistwidget.cpp
+    kitemviews/kfileitemlisttostring.cpp
     kitemviews/kfileitemmodel.cpp
     kitemviews/kfileitemmodelrolesupdater.cpp
     kitemviews/kitemlistcontainer.cpp
@@ -91,8 +92,6 @@ target_sources(dolphinprivate PRIVATE
     kitemviews/private/kitemlistviewanimation.cpp
     kitemviews/private/kitemlistviewlayouter.cpp
     kitemviews/private/kpixmapmodifier.cpp
-    kitemviews/private/ktwofingerswipe.cpp
-    kitemviews/private/ktwofingertap.cpp
     settings/applyviewpropsjob.cpp
     settings/viewmodes/viewmodesettings.cpp
     settings/viewpropertiesdialog.cpp
@@ -158,6 +157,7 @@ target_link_libraries(
     KF5::NewStuff
     KF5::Parts
     KF5::WindowSystem
+    KF5::WidgetsAddons
 )
 
 if(HAVE_BALOO)
@@ -307,7 +307,7 @@ target_link_libraries(dolphinstatic
     KF5::KCMUtils
     KF5::DBusAddons
     KF5::Notifications
-    Phonon::phonon4qt5
+    Phonon::phonon4qt${QT_MAJOR_VERSION}
 )
 
 if (HAVE_KACTIVITIES)
index 340af6bd0223be8e0c68e81725cda0719cd62c4c..65d84106067b2b7123ac80d09d7e23e65297fc27 100644 (file)
@@ -13,6 +13,7 @@
 #include "dolphinplacesmodelsingleton.h"
 #include "dolphinremoveaction.h"
 #include "dolphinviewcontainer.h"
+#include "global.h"
 #include "trash/dolphintrash.h"
 #include "views/dolphinview.h"
 #include "views/viewmodecontroller.h"
 #include <QMimeDatabase>
 
 DolphinContextMenu::DolphinContextMenu(DolphinMainWindow* parent,
-                                       const QPoint& pos,
                                        const KFileItem& fileInfo,
+                                       const KFileItemList &selectedItems,
                                        const QUrl& baseUrl,
                                        KFileItemActions *fileItemActions) :
     QMenu(parent),
-    m_pos(pos),
     m_mainWindow(parent),
     m_fileInfo(fileInfo),
     m_baseUrl(baseUrl),
     m_baseFileItem(nullptr),
-    m_selectedItems(),
+    m_selectedItems(selectedItems),
     m_selectedItemsProperties(nullptr),
     m_context(NoContext),
     m_copyToMenu(parent),
-    m_customActions(),
-    m_command(None),
     m_removeAction(nullptr),
     m_fileItemActions(fileItemActions)
 {
-    // The context menu either accesses the URLs of the selected items
-    // or the items itself. To increase the performance both lists are cached.
-    const DolphinView* view = m_mainWindow->activeViewContainer()->view();
-    m_selectedItems = view->selectedItems();
-
     QApplication::instance()->installEventFilter(this);
 
-    static_cast<KHamburgerMenu *>(m_mainWindow->actionCollection()->
-                action(QStringLiteral("hamburger_menu")))->addToMenu(this);
+    addAllActions();
 }
 
 DolphinContextMenu::~DolphinContextMenu()
@@ -76,13 +68,11 @@ DolphinContextMenu::~DolphinContextMenu()
     m_selectedItemsProperties = nullptr;
 }
 
-void DolphinContextMenu::setCustomActions(const QList<QAction*>& actions)
+void DolphinContextMenu::addAllActions()
 {
-    m_customActions = actions;
-}
+    static_cast<KHamburgerMenu *>(m_mainWindow->actionCollection()->
+                action(QStringLiteral("hamburger_menu")))->addToMenu(this);
 
-DolphinContextMenu::Command DolphinContextMenu::open()
-{
     // get the context information
     const auto scheme = m_baseUrl.scheme();
     if (scheme == QLatin1String("trash")) {
@@ -101,17 +91,15 @@ DolphinContextMenu::Command DolphinContextMenu::open()
     // open the corresponding popup for the context
     if (m_context & TrashContext) {
         if (m_context & ItemContext) {
-            openTrashItemContextMenu();
+            addTrashItemContextMenu();
         } else {
-            openTrashContextMenu();
+            addTrashContextMenu();
         }
     } else if (m_context & ItemContext) {
-        openItemContextMenu();
+        addItemContextMenu();
     } else {
-        openViewportContextMenu();
+        addViewportContextMenu();
     }
-
-    return m_command;
 }
 
 bool DolphinContextMenu::eventFilter(QObject* object, QEvent* event)
@@ -133,39 +121,25 @@ bool DolphinContextMenu::eventFilter(QObject* object, QEvent* event)
     return false;
 }
 
-void DolphinContextMenu::openTrashContextMenu()
+void DolphinContextMenu::addTrashContextMenu()
 {
     Q_ASSERT(m_context & TrashContext);
 
-    QAction* emptyTrashAction = new QAction(QIcon::fromTheme(QStringLiteral("trash-empty")), i18nc("@action:inmenu", "Empty Trash"), this);
+    QAction *emptyTrashAction = addAction(QIcon::fromTheme(QStringLiteral("trash-empty")), i18nc("@action:inmenu", "Empty Trash"), [this](){
+        Trash::empty(m_mainWindow);
+    });
     emptyTrashAction->setEnabled(!Trash::isEmpty());
-    addAction(emptyTrashAction);
-
-    addCustomActions();
 
     QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties"));
     addAction(propertiesAction);
-
-    if (exec(m_pos) == emptyTrashAction) {
-        Trash::empty(m_mainWindow);
-    }
 }
 
-void DolphinContextMenu::openTrashItemContextMenu()
+void DolphinContextMenu::addTrashItemContextMenu()
 {
     Q_ASSERT(m_context & TrashContext);
     Q_ASSERT(m_context & ItemContext);
 
-    QAction* restoreAction = new QAction(QIcon::fromTheme("restoration"), i18nc("@action:inmenu", "Restore"), m_mainWindow);
-    addAction(restoreAction);
-
-    QAction* deleteAction = m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::DeleteFile));
-    addAction(deleteAction);
-
-    QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties"));
-    addAction(propertiesAction);
-
-    if (exec(m_pos) == restoreAction) {
+    addAction(QIcon::fromTheme("restoration"), i18nc("@action:inmenu", "Restore"), [this](){
         QList<QUrl> selectedUrls;
         selectedUrls.reserve(m_selectedItems.count());
         for (const KFileItem &item : qAsConst(m_selectedItems)) {
@@ -175,7 +149,13 @@ void DolphinContextMenu::openTrashItemContextMenu()
         KIO::RestoreJob *job = KIO::restoreFromTrash(selectedUrls);
         KJobWidgets::setWindow(job, m_mainWindow);
         job->uiDelegate()->setAutoErrorHandlingEnabled(true);
-    }
+    });
+
+    QAction* deleteAction = m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::DeleteFile));
+    addAction(deleteAction);
+
+    QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties"));
+    addAction(propertiesAction);
 }
 
 void DolphinContextMenu::addDirectoryItemContextMenu()
@@ -194,7 +174,6 @@ void DolphinContextMenu::addDirectoryItemContextMenu()
 
     // set up 'Create New' menu
     DolphinNewFileMenu* newFileMenu = new DolphinNewFileMenu(m_mainWindow->actionCollection(), m_mainWindow);
-    const DolphinView* view = m_mainWindow->activeViewContainer()->view();
     newFileMenu->checkUpToDate();
     newFileMenu->setPopupFiles(QList<QUrl>() << m_fileInfo.url());
     newFileMenu->setEnabled(selectedItemsProps.supportsWriting());
@@ -209,16 +188,12 @@ void DolphinContextMenu::addDirectoryItemContextMenu()
     addSeparator();
 }
 
-void DolphinContextMenu::openItemContextMenu()
+void DolphinContextMenu::addItemContextMenu()
 {
     Q_ASSERT(!m_fileInfo.isNull());
 
-    QAction* openParentAction = nullptr;
-    QAction* openParentInNewWindowAction = nullptr;
-    QAction* openParentInNewTabAction = nullptr;
     const KFileItemListProperties& selectedItemsProps = selectedItemsProperties();
 
-
     m_fileItemActions->setItemListProperties(selectedItemsProps);
 
     if (m_selectedItems.count() == 1) {
@@ -228,23 +203,28 @@ void DolphinContextMenu::openItemContextMenu()
         } else if (m_context & TimelineContext || m_context & SearchContext) {
             addOpenWithActions();
 
-            openParentAction = new QAction(QIcon::fromTheme(QStringLiteral("document-open-folder")),
+            addAction(QIcon::fromTheme(QStringLiteral("document-open-folder")),
                                            i18nc("@action:inmenu",
                                                  "Open Path"),
-                                           this);
-            addAction(openParentAction);
+                                           [this](){
+                m_mainWindow->changeUrl(KIO::upUrl(m_fileInfo.url()));
+                m_mainWindow->activeViewContainer()->view()->markUrlsAsSelected({m_fileInfo.url()});
+                m_mainWindow->activeViewContainer()->view()->markUrlAsCurrent(m_fileInfo.url());
+            });
 
-            openParentInNewWindowAction = new QAction(QIcon::fromTheme(QStringLiteral("window-new")),
+            addAction(QIcon::fromTheme(QStringLiteral("window-new")),
                                                     i18nc("@action:inmenu",
                                                           "Open Path in New Window"),
-                                                    this);
-            addAction(openParentInNewWindowAction);
+                                                    [this](){
+                Dolphin::openNewWindow({m_fileInfo.url()}, m_mainWindow, Dolphin::OpenNewWindowFlag::Select);
+            });
 
-            openParentInNewTabAction = new QAction(QIcon::fromTheme(QStringLiteral("tab-new")),
+            addAction(QIcon::fromTheme(QStringLiteral("tab-new")),
                                                    i18nc("@action:inmenu",
                                                          "Open Path in New Tab"),
-                                                   this);
-            addAction(openParentInNewTabAction);
+                                                   [this](){
+                m_mainWindow->openNewTab(KIO::upUrl(m_fileInfo.url()));
+            });
 
             addSeparator();
         } else {
@@ -290,23 +270,10 @@ void DolphinContextMenu::openItemContextMenu()
     addSeparator();
     QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties"));
     addAction(propertiesAction);
-
-    QAction* activatedAction = exec(m_pos);
-    if (activatedAction) {
-        if (activatedAction == openParentAction) {
-            m_command = OpenParentFolder;
-        } else if (activatedAction == openParentInNewWindowAction) {
-            m_command = OpenParentFolderInNewWindow;
-        } else if (activatedAction == openParentInNewTabAction) {
-            m_command = OpenParentFolderInNewTab;
-        }
-    }
 }
 
-void DolphinContextMenu::openViewportContextMenu()
+void DolphinContextMenu::addViewportContextMenu()
 {
-    const DolphinView* view = m_mainWindow->activeViewContainer()->view();
-
     const KFileItemListProperties baseUrlProperties(KFileItemList() << baseFileItem());
     m_fileItemActions->setItemListProperties(baseUrlProperties);
 
@@ -344,14 +311,11 @@ void DolphinContextMenu::openViewportContextMenu()
     }
 
     addAdditionalActions(baseUrlProperties);
-    addCustomActions();
 
     addSeparator();
 
     QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties"));
     addAction(propertiesAction);
-
-    exec(m_pos);
 }
 
 void DolphinContextMenu::insertDefaultItemActions(const KFileItemListProperties& properties)
@@ -476,11 +440,6 @@ void DolphinContextMenu::addOpenWithActions()
     m_fileItemActions->insertOpenWithActionsTo(nullptr, this, QStringList{qApp->desktopFileName()});
 }
 
-void DolphinContextMenu::addCustomActions()
-{
-    addActions(m_customActions);
-}
-
 void DolphinContextMenu::addAdditionalActions(const KFileItemListProperties &props)
 {
     addSeparator();
index e033fca6e1ac41eddfb01d42678d6e41cf0beb61..627a6e3b84838e87011c66742f6a6847010b0cc6 100644 (file)
@@ -37,60 +37,42 @@ class DolphinContextMenu : public QMenu
     Q_OBJECT
 
 public:
-    enum Command
-    {
-        None,
-        OpenParentFolder,
-        OpenParentFolderInNewWindow,
-        OpenParentFolderInNewTab
-    };
-
     /**
      * @parent        Pointer to the main window the context menu
      *                belongs to.
-     * @pos           Position in screen coordinates.
      * @fileInfo      Pointer to the file item the context menu
      *                is applied. If 0 is passed, the context menu
      *                is above the viewport.
+     * @selectedItems The selected items for which the context menu
+     *                is opened. This list generally includes \a fileInfo.
      * @baseUrl       Base URL of the viewport where the context menu
      *                should be opened.
      */
     DolphinContextMenu(DolphinMainWindow* parent,
-                       const QPoint& pos,
                        const KFileItem& fileInfo,
+                       const KFileItemList &selectedItems,
                        const QUrl& baseUrl,
                        KFileItemActions *fileItemActions);
 
     ~DolphinContextMenu() override;
 
-    void setCustomActions(const QList<QAction*>& actions);
-
-    /**
-     * Opens the context menu model and returns the requested
-     * command, that should be triggered by the caller. If
-     * Command::None has been returned, either the context-menu
-     * had been closed without executing an action or an
-     * already available action from the main-window has been
-     * executed.
-     */
-    Command open();
-
 protected:
     bool eventFilter(QObject* object, QEvent* event) override;
 
 private:
-    void openTrashContextMenu();
-    void openTrashItemContextMenu();
-    void openItemContextMenu();
-    void openViewportContextMenu();
-
-    void insertDefaultItemActions(const KFileItemListProperties&);
-
     /**
-     * Adds the "Show menubar" action to the menu if the
-     * menubar is hidden.
+     * Adds all the actions and menus to this menu based on all given information.
+     * This method calls the other helper methods for adding actions
+     * based on the context given in the constructor.
      */
-    void addShowMenuBarAction();
+    void addAllActions();
+
+    void addTrashContextMenu();
+    void addTrashItemContextMenu();
+    void addItemContextMenu();
+    void addViewportContextMenu();
+
+    void insertDefaultItemActions(const KFileItemListProperties&);
 
     bool placeExists(const QUrl& url) const;
 
@@ -108,18 +90,12 @@ private:
      */
     void addOpenWithActions();
 
-    /**
-     * Adds custom actions e.g. like the "[x] Expandable Folders"-action
-     * provided in the details view.
-     */
-    void addCustomActions();
-
-private:
     /**
      * Add services, custom actions, plugins and version control items to the menu
      */
     void addAdditionalActions(const KFileItemListProperties &props);
 
+private:
     struct Entry
     {
         int type;
@@ -139,7 +115,6 @@ private:
         SearchContext = 8,
     };
 
-    QPoint m_pos;
     DolphinMainWindow* m_mainWindow;
 
     KFileItem m_fileInfo;
@@ -152,9 +127,6 @@ private:
 
     int m_context;
     KFileCopyToMenu m_copyToMenu;
-    QList<QAction*> m_customActions;
-
-    Command m_command;
 
     DolphinRemoveAction* m_removeAction; // Action that represents either 'Move To Trash' or 'Delete'
     void addDirectoryItemContextMenu();
index 166091ca7e9ef70cf909952a365d141d02894ab1..589c2c185b5fc1cbc9fb76eacb8bef3e0749619d 100644 (file)
@@ -749,13 +749,45 @@ void DolphinMainWindow::slotToolBarActionMiddleClicked(QAction *action)
     }
 }
 
+QAction *DolphinMainWindow::urlNavigatorHistoryAction(const KUrlNavigator *urlNavigator, int historyIndex, QObject *parent)
+{
+    const QUrl url = urlNavigator->locationUrl(historyIndex);
+
+    QString text = url.toDisplayString(QUrl::PreferLocalFile);
+
+    if (!urlNavigator->showFullPath()) {
+        const KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel();
+
+        const QModelIndex closestIdx = placesModel->closestItem(url);
+        if (closestIdx.isValid()) {
+            const QUrl placeUrl = placesModel->url(closestIdx);
+
+            text = placesModel->text(closestIdx);
+
+            QString pathInsidePlace = url.path().mid(placeUrl.path().length());
+
+            if (!pathInsidePlace.isEmpty() && !pathInsidePlace.startsWith(QLatin1Char('/'))) {
+                pathInsidePlace.prepend(QLatin1Char('/'));
+            }
+
+            if (pathInsidePlace != QLatin1Char('/')) {
+                text.append(pathInsidePlace);
+            }
+        }
+    }
+
+    QAction *action = new QAction(QIcon::fromTheme(KIO::iconNameForUrl(url)), text, parent);
+    action->setData(historyIndex);
+    return action;
+}
+
 void DolphinMainWindow::slotAboutToShowBackPopupMenu()
 {
     const KUrlNavigator *urlNavigator = m_activeViewContainer->urlNavigatorInternalWithHistory();
     int entries = 0;
     m_backAction->menu()->clear();
     for (int i = urlNavigator->historyIndex() + 1; i < urlNavigator->historySize() && entries < MaxNumberOfNavigationentries; ++i, ++entries) {
-        QAction* action = new QAction(urlNavigator->locationUrl(i).toDisplayString(QUrl::PreferLocalFile), m_backAction->menu());
+        QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_backAction->menu());
         action->setData(i);
         m_backAction->menu()->addAction(action);
     }
@@ -784,7 +816,7 @@ void DolphinMainWindow::slotAboutToShowForwardPopupMenu()
     int entries = 0;
     m_forwardAction->menu()->clear();
     for (int i = urlNavigator->historyIndex() - 1; i >= 0 && entries < MaxNumberOfNavigationentries; --i, ++entries) {
-        QAction* action = new QAction(urlNavigator->locationUrl(i).toDisplayString(QUrl::PreferLocalFile), m_forwardAction->menu());
+        QAction *action = urlNavigatorHistoryAction(urlNavigator, i, m_forwardAction->menu());
         action->setData(i);
         m_forwardAction->menu()->addAction(action);
     }
@@ -1146,32 +1178,11 @@ void DolphinMainWindow::slotWriteStateChanged(bool isFolderWritable)
 
 void DolphinMainWindow::openContextMenu(const QPoint& pos,
                                         const KFileItem& item,
-                                        const QUrl& url,
-                                        const QList<QAction*>& customActions)
+                                        const KFileItemList &selectedItems,
+                                        const QUrl& url)
 {
-    QPointer<DolphinContextMenu> contextMenu = new DolphinContextMenu(this, pos, item, url, &m_fileItemActions);
-    contextMenu.data()->setCustomActions(customActions);
-    const DolphinContextMenu::Command command = contextMenu.data()->open();
-
-    switch (command) {
-    case DolphinContextMenu::OpenParentFolder:
-        changeUrl(KIO::upUrl(item.url()));
-        m_activeViewContainer->view()->markUrlsAsSelected({item.url()});
-        m_activeViewContainer->view()->markUrlAsCurrent(item.url());
-        break;
-
-    case DolphinContextMenu::OpenParentFolderInNewWindow:
-        Dolphin::openNewWindow({item.url()}, this, Dolphin::OpenNewWindowFlag::Select);
-        break;
-
-    case DolphinContextMenu::OpenParentFolderInNewTab:
-        openNewTab(KIO::upUrl(item.url()));
-        break;
-
-    case DolphinContextMenu::None:
-    default:
-        break;
-    }
+    QPointer<DolphinContextMenu> contextMenu = new DolphinContextMenu(this, item, selectedItems, url, &m_fileItemActions);
+    contextMenu.data()->exec(pos);
 
     // Delete the menu, unless it has been deleted in its own nested event loop already.
     if (contextMenu) {
index 1a3ec4efb7a7e8d3b9e112df506fc48c7b93abef..17327f2de9f3bbafd6027b9b89b99f34eef19e24 100644 (file)
@@ -475,14 +475,11 @@ private Q_SLOTS:
      * @pos           Position in screen coordinates.
      * @item          File item context. If item is null, the context menu
      *                should be applied to \a url.
+     * @selectedItems The selected items for which the context menu
+     *                is opened. This list generally includes \a item.
      * @url           URL which contains \a item.
-     * @customActions Actions that should be added to the context menu,
-     *                if the file item is null.
      */
-    void openContextMenu(const QPoint& pos,
-                         const KFileItem& item,
-                         const QUrl& url,
-                         const QList<QAction*>& customActions);
+    void openContextMenu(const QPoint& pos, const KFileItem& item, const KFileItemList &selectedItems, const QUrl& url);
 
     /**
      * Updates the menu that is by default at the right end of the toolbar.
@@ -653,6 +650,9 @@ private:
      */
     bool addHamburgerMenuToToolbar();
 
+    /** Creates an action representing an item in the URL navigator history */
+    static QAction *urlNavigatorHistoryAction(const KUrlNavigator *urlNavigator, int historyIndex, QObject *parent = nullptr);
+
 private:
     /**
      * Implements a custom error handling for the undo manager. This
index 0595087784a33ea37b75623688eb34c91567008c..0f10a7769fe2513688f4da5b9ca0869d81bf9dfa 100644 (file)
@@ -385,8 +385,8 @@ void DolphinPart::createNewWindow(const QUrl& url)
 
 void DolphinPart::slotOpenContextMenu(const QPoint& pos,
                                       const KFileItem& _item,
-                                      const QUrl &,
-                                      const QList<QAction*>& customActions)
+                                      const KFileItemList &selectedItems,
+                                      const QUrl &)
 {
     KParts::BrowserExtension::PopupFlags popupFlags = KParts::BrowserExtension::DefaultPopupItems
                                                       | KParts::BrowserExtension::ShowProperties
@@ -402,13 +402,11 @@ void DolphinPart::slotOpenContextMenu(const QPoint& pos,
             item.setUrl(url()); // ensure we use the view url, not the canonical path (#213799)
     }
 
-    // TODO: We should change the signature of the slots (and signals) for being able
-    //       to tell for which items we want a popup.
     KFileItemList items;
-    if (m_view->selectedItems().isEmpty()) {
+    if (selectedItems.isEmpty()) {
         items.append(item);
     } else {
-        items = m_view->selectedItems();
+        items = selectedItems;
     }
 
     KFileItemListProperties capabilities(items);
@@ -416,7 +414,6 @@ void DolphinPart::slotOpenContextMenu(const QPoint& pos,
     KParts::BrowserExtension::ActionGroupMap actionGroups;
     QList<QAction *> editActions;
     editActions += m_view->versionControlActions(m_view->selectedItems());
-    editActions += customActions;
 
     if (!_item.isNull()) { // only for context menu on one or more items
         const bool supportsMoving = capabilities.supportsMoving();
index 25d76950c0c1b50f57decdeeb07ec70dd8100671..a49603ca877fc2c5bd27ab27a1609953d3cf9ca1 100644 (file)
@@ -123,14 +123,11 @@ private Q_SLOTS:
      * @pos           Position in screen coordinates.
      * @item          File item context. If item is null, the context menu
      *                should be applied to \a url.
+     * @selectedItems The selected items for which the context menu
+     *                is opened. This list generally includes \a item.
      * @url           URL which contains \a item.
-     * @customActions Actions that should be added to the context menu,
-     *                if the file item is null.
      */
-    void slotOpenContextMenu(const QPoint& pos,
-                             const KFileItem& item,
-                             const QUrl& url,
-                             const QList<QAction*>& customActions);
+    void slotOpenContextMenu(const QPoint &pos, const KFileItem &_item, const KFileItemList &selectedItems, const QUrl &);
 
     /**
      * Informs the host that we are opening \a url (e.g. after a redirection
diff --git a/src/kitemviews/kfileitemlisttostring.cpp b/src/kitemviews/kfileitemlisttostring.cpp
new file mode 100644 (file)
index 0000000..8e8f880
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+    This file is part of the KDE project
+    SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
+
+    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
+
+#include "kfileitemlisttostring.h"
+
+#include <KFileItem>
+#include <KFileItemListProperties>
+#include <KLocalizedString>
+
+#include <QFontMetrics>
+#include <QString>
+
+QString fileItemListToString(KFileItemList items, int maximumTextWidth, QFontMetrics fontMetrics, ItemsState itemsState)
+{
+    QString text;
+    switch (items.count()) {
+    case 1:
+        text = i18nc("Textual representation of a file. %1 is the name of the file/folder.",
+                "\"%1\"", items.first().name());
+        break;
+    case 2:
+        text = i18nc("Textual representation of two files. %1 and %2 are names of files/folders.",
+                "\"%1\" and \"%2\"", items.first().name(), items.last().name());
+        break;
+    case 3:
+        text = i18nc("Textual representation of three files. %1, %2 and %3 are names of files/folders.",
+                "\"%1\", \"%2\" and \"%3\"",
+                items.first().name(), items.at(1).name(), items.last().name());
+        break;
+    case 4:
+        text = i18nc("Textual representation of four files. %1, %2, %3 and %4 are names of files/folders.",
+                "\"%1\", \"%2\", \"%3\" and \"%4\"",
+                items.first().name(), items.at(1).name(), items.at(2).name(), items.last().name());
+        break;
+    case 5:
+        text = i18nc("Textual representation of five files. %1, %2, %3, %4 and %5 are names of files/folders.",
+                "\"%1\", \"%2\", \"%3\", \"%4\" and \"%5\"",
+                items.first().name(), items.at(1).name(), items.at(2).name(), items.at(3).name(), items.last().name());
+        break;
+    default:
+        text = QString();
+        break;
+    }
+
+    // At some point the added clarity from the text starts being less important than the text width.
+    if (!text.isEmpty() && fontMetrics.horizontalAdvance(text) <= maximumTextWidth) {
+        return text;
+    }
+
+    const KFileItemListProperties properties(items);
+    if (itemsState == Selected) {
+        if (properties.isFile()) {
+            text = i18ncp("Textual representation of selected files. %1 is the number of files.",
+                    "One Selected File", "%1 Selected Files", items.count());
+        } else if (properties.isDirectory()) {
+            text = i18ncp("Textual representation of selected folders. %1 is the number of folders.",
+                    "One Selected Folder", "%1 Selected Folders", items.count());
+        } else {
+            text = i18ncp("Textual representation of selected fileitems. %1 is the number of files/folders.",
+                    "One Selected Item", "%1 Selected Items", items.count());
+        }
+
+        if (fontMetrics.horizontalAdvance(text) <= maximumTextWidth) {
+            return text;
+        }
+    }
+
+    if (properties.isFile()) {
+        return i18ncp("Textual representation of files. %1 is the number of files.",
+                "One File", "%1 Files", items.count());
+    } else if (properties.isDirectory()) {
+        return i18ncp("Textual representation of folders. %1 is the number of folders.",
+                "One Folder", "%1 Folders", items.count());
+    } else {
+        return i18ncp("Textual representation of fileitems. %1 is the number of files/folders.",
+                "One Item", "%1 Items", items.count());
+    }
+}
diff --git a/src/kitemviews/kfileitemlisttostring.h b/src/kitemviews/kfileitemlisttostring.h
new file mode 100644 (file)
index 0000000..7eee0ae
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    This file is part of the KDE project
+    SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
+
+    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
+*/
+
+#ifndef KFILEITEMLISTTOSTRING_H
+#define KFILEITEMLISTTOSTRING_H
+
+class KFileItemList;
+class QFontMetrics;
+class QString;
+
+enum ItemsState {
+    None,
+    Selected
+};
+
+/**
+ * @brief Generates a textual representation of the given list of KFileItems.
+ *
+ * This method is especially useful to be very explicit about which items will be affected by an action.
+ * For example can a label for a delete button be enriched to say "Permanantly Delete `picture1` and `picture2`"
+ * but also "Permanently Delete 7 Selected Folders" without requiring a huge amount of new translations for this.
+ *
+ * Unfortunately this doesn't always work.
+ *
+ * For some texts and some languages this wide range of words cannot be inserted into a text while staying
+ * grammatically correct. Because of this you will probably need to write a fallback for these languages.
+ * Something like this:
+ * \code
+ * // i18n: @action:inmenu menu with actions like copy, paste, rename.
+ * // %2 is a textual representation of the currently selected files or folders. This can be the name of
+ * // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders".
+ * // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes)
+ * // and a fallback will be used.
+ * auto buttonText = i18ncp("@action A more elaborate and clearly worded version of the Delete action", "Permanently Delete %2", "Permanently Delete %2", items.count(), fileItemListToString(items, fontMetrics.averageCharWidth() * 20, fontMetrics));
+ * if (buttonText == QStringLiteral("NULL")) {
+ *      buttonText = i18ncp("@action Delete button label. %1 is the number of items to be deleted.",
+ *              "Permanently Delete %1 Item", "Permanently Delete %1 Items", items.count())
+ * }
+ * \endcode
+ * (The i18n call should be completely in the line following the i18n: comment without any line breaks within the i18n call or the comment might not be correctly extracted. See: https://commits.kde.org/kxmlgui/a31135046e1b3335b5d7bbbe6aa9a883ce3284c1 )
+ *
+ * @param items The KFileItemList for which a QString should be generated.
+ * @param maximumTextWidth The maximum width/horizontalAdvance the QString should have. Keep scaling in mind.
+ * @param fontMetrics the fontMetrics for the font that is used to calculate the maximumTextWidth.
+ * @param itemsState A state of the @p items that should be spelled out in the returned QString.
+ * @returns the names of the @p items separated by commas if that is below the @p maximumCharacterWidth.
+ *          Otherwise returns something like "5 Files", "8 Selected Folders" or "60 Items"
+ *          while being as specific as possible.
+ */
+QString fileItemListToString(KFileItemList items, int maximumTextWidth, QFontMetrics fontMetrics, ItemsState itemsState = ItemsState::None);
+
+#endif // KFILEITEMLISTTOSTRING_H
index 6391d7d3facd1f2154e303e5867ac2235f15032d..052a71cbd4863020469da79c89adba18fe952a99 100644 (file)
@@ -15,7 +15,7 @@
 
 #include <KDirLister>
 #include <KIO/Job>
-#include <KIO/kio_version.h>
+#include <kio_version.h>
 #include <KLocalizedString>
 #include <KLazyLocalizedString>
 #include <KUrlMimeData>
index 7ef37481d49d65c8994ba67691bbabfb40a3fe0c..ba4047dbe8c85661f50ec3a7e311b451f06872c2 100644 (file)
 #include "kitemlistview.h"
 #include "private/kitemlistkeyboardsearchmanager.h"
 #include "private/kitemlistrubberband.h"
-#include "private/ktwofingerswipe.h"
-#include "private/ktwofingertap.h"
 #include "views/draganddrophelper.h"
 
+#include <KTwoFingerSwipe>
+#include <KTwoFingerTap>
+
 #include <QAccessible>
 #include <QApplication>
 #include <QDrag>
index b531b8641499d0a07ed2e330e6a0c1ea5d43d4fc..247581a4ec374ed4e2e0921a1a5ebea13c4d0ec7 100644 (file)
@@ -1196,7 +1196,11 @@ QString KStandardItemListWidget::elideRightKeepExtension(const QString &text, in
             QString ret = m_customizedFontMetrics.elidedText(text.chopped(extensionLength),
                                                              Qt::ElideRight,
                                                              elidingWidth - extensionWidth);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
             ret.append(text.rightRef(extensionLength));
+#else
+            ret.append(QStringView(text).right(extensionLength));
+#endif
             return ret;
         }
     }
diff --git a/src/kitemviews/private/ktwofingerswipe.cpp b/src/kitemviews/private/ktwofingerswipe.cpp
deleted file mode 100644 (file)
index 6d0e18e..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2020 Steffen Hartleib <steffenhartleib@t-online.de>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-// Self
-#include "ktwofingerswipe.h"
-
-// Qt
-#include <QTouchEvent>
-#include <QLineF>
-
-KTwoFingerSwipeRecognizer::KTwoFingerSwipeRecognizer() :
-    QGestureRecognizer(),
-    m_touchBeginnTimestamp(0),
-    m_gestureAlreadyTriggered(false)
-{
-}
-
-KTwoFingerSwipeRecognizer::~KTwoFingerSwipeRecognizer()
-{
-}
-
-QGesture* KTwoFingerSwipeRecognizer::create(QObject*)
-{
-    return static_cast<QGesture*>(new KTwoFingerSwipe());
-}
-
-QGestureRecognizer::Result KTwoFingerSwipeRecognizer::recognize(QGesture* gesture, QObject* watched, QEvent* event)
-{
-    Q_UNUSED(watched)
-
-    KTwoFingerSwipe* const kTwoFingerSwipe = static_cast<KTwoFingerSwipe*>(gesture);
-    const QTouchEvent* touchEvent = static_cast<const QTouchEvent*>(event);
-
-    const int maxTimeFrameForSwipe = 90;
-    const int minDistanceForSwipe = 30;
-
-    switch (event->type()) {
-    case QEvent::TouchBegin: {
-        m_touchBeginnTimestamp = touchEvent->timestamp();
-        m_gestureAlreadyTriggered = false;
-        kTwoFingerSwipe->setHotSpot(touchEvent->touchPoints().first().startScreenPos());
-        kTwoFingerSwipe->setPos(touchEvent->touchPoints().first().startPos());
-        kTwoFingerSwipe->setScreenPos(touchEvent->touchPoints().first().startScreenPos());
-        kTwoFingerSwipe->setScenePos(touchEvent->touchPoints().first().startScenePos());
-        return MayBeGesture;
-    }
-
-    case QEvent::TouchUpdate: {
-        const qint64 now = touchEvent->timestamp();
-        const qint64 elapsedTime = now - m_touchBeginnTimestamp;
-        const QPointF distance = touchEvent->touchPoints().first().startPos() - touchEvent->touchPoints().first().pos();
-        kTwoFingerSwipe->setHotSpot(touchEvent->touchPoints().first().startScreenPos());
-        kTwoFingerSwipe->setPos(touchEvent->touchPoints().first().startPos());
-        kTwoFingerSwipe->setScreenPos(touchEvent->touchPoints().first().startScreenPos());
-        kTwoFingerSwipe->setScenePos(touchEvent->touchPoints().first().startScenePos());
-        const QLineF ql = QLineF(touchEvent->touchPoints().first().startPos(), touchEvent->touchPoints().first().pos());
-        kTwoFingerSwipe->setSwipeAngle(ql.angle());
-
-        if (touchEvent->touchPoints().size() > 2) {
-            return CancelGesture;
-        }
-
-        if (touchEvent->touchPoints().size() == 2) {
-            if ((elapsedTime) > maxTimeFrameForSwipe) {
-                return CancelGesture;
-            }
-
-            if (distance.manhattanLength() >= minDistanceForSwipe &&
-                    (elapsedTime) <= maxTimeFrameForSwipe && !m_gestureAlreadyTriggered) {
-                m_gestureAlreadyTriggered = true;
-                return FinishGesture;
-            } else if ((elapsedTime) <= maxTimeFrameForSwipe && !m_gestureAlreadyTriggered) {
-                return TriggerGesture;
-            }
-        }
-        break;
-    }
-
-    default:
-        return Ignore;
-    }
-    return Ignore;
-}
-
-KTwoFingerSwipe::KTwoFingerSwipe(QObject* parent) :
-    QGesture(parent),
-    m_pos(QPointF(-1, -1)),
-    m_screenPos(QPointF(-1, -1)),
-    m_scenePos(QPointF(-1, -1)),
-    m_swipeAngle(0.0)
-{
-}
-
-KTwoFingerSwipe::~KTwoFingerSwipe()
-{
-}
-
-QPointF KTwoFingerSwipe::pos() const
-{
-    return m_pos;
-}
-
-void KTwoFingerSwipe::setPos(QPointF _pos)
-{
-    m_pos = _pos;
-}
-
-QPointF KTwoFingerSwipe::screenPos() const
-{
-    return m_screenPos;
-}
-
-void KTwoFingerSwipe::setScreenPos(QPointF _screenPos)
-{
-    m_screenPos = _screenPos;
-}
-
-QPointF KTwoFingerSwipe::scenePos() const
-{
-    return m_scenePos;
-}
-
-void KTwoFingerSwipe::setScenePos(QPointF _scenePos)
-{
-    m_scenePos = _scenePos;
-}
-
-qreal KTwoFingerSwipe::swipeAngle() const
-{
-    return m_swipeAngle;
-}
- void KTwoFingerSwipe::setSwipeAngle(qreal _swipeAngle)
-{
-    m_swipeAngle = _swipeAngle;
-}
-
diff --git a/src/kitemviews/private/ktwofingerswipe.h b/src/kitemviews/private/ktwofingerswipe.h
deleted file mode 100644 (file)
index 6d64d8f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2020 Steffen Hartleib <steffenhartleib@t-online.de>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef KTWOFINGERSWIPE_H
-#define KTWOFINGERSWIPE_H
-
-#include "dolphin_export.h"
-// Qt
-#include <QGesture>
-#include <QGestureRecognizer>
-
-class DOLPHIN_EXPORT KTwoFingerSwipe : public QGesture
-{
-    Q_OBJECT
-    Q_PROPERTY(QPointF pos READ pos WRITE setPos)
-    Q_PROPERTY(QPointF screenPos READ screenPos WRITE setScreenPos)
-    Q_PROPERTY(QPointF scenePos READ scenePos WRITE setScenePos)
-    Q_PROPERTY(qreal swipeAngle READ swipeAngle WRITE setSwipeAngle)
-public:
-    explicit KTwoFingerSwipe(QObject* parent = nullptr);
-    ~KTwoFingerSwipe() override;
-    QPointF pos() const;
-    void setPos(QPointF pos);
-    QPointF screenPos() const;
-    void setScreenPos(QPointF screenPos);
-    QPointF scenePos() const;
-    void setScenePos(QPointF scenePos);
-    qreal swipeAngle() const;
-    void setSwipeAngle(qreal swipeAngle);
-private:
-    QPointF m_pos;
-    QPointF m_screenPos;
-    QPointF m_scenePos;
-    qreal m_swipeAngle;
-};
-
-class DOLPHIN_EXPORT KTwoFingerSwipeRecognizer : public QGestureRecognizer
-{
-public:
-    explicit KTwoFingerSwipeRecognizer();
-    ~KTwoFingerSwipeRecognizer() override;
-    QGesture* create(QObject*) override;
-    Result recognize(QGesture*, QObject*, QEvent*) override;
-private:
-    Q_DISABLE_COPY( KTwoFingerSwipeRecognizer )
-    qint64 m_touchBeginnTimestamp;
-    bool m_gestureAlreadyTriggered;
-};
-
-#endif /* KTWOFINGERSWIPE_H */
-
diff --git a/src/kitemviews/private/ktwofingertap.cpp b/src/kitemviews/private/ktwofingertap.cpp
deleted file mode 100644 (file)
index edd9d1d..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2020 Steffen Hartleib <steffenhartleib@t-online.de>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-// Self
-#include "ktwofingertap.h"
-
-// Qt
-#include <QTouchEvent>
-#include <QApplication>
-#include <QGraphicsWidget>
-
-KTwoFingerTapRecognizer::KTwoFingerTapRecognizer() :
-    QGestureRecognizer(),
-    m_gestureTriggered(false)
-{
-}
-
-KTwoFingerTapRecognizer::~KTwoFingerTapRecognizer()
-{
-}
-
-QGesture* KTwoFingerTapRecognizer::create(QObject*)
-{
-    return static_cast<QGesture*>(new KTwoFingerTap());
-}
-
-QGestureRecognizer::Result KTwoFingerTapRecognizer::recognize(QGesture* gesture, QObject* watched, QEvent* event)
-{
-    if (qobject_cast<QGraphicsWidget*>(watched)) {
-        return Ignore;
-    }
-
-    KTwoFingerTap* const kTwoFingerTap = static_cast<KTwoFingerTap*>(gesture);
-    const QTouchEvent* touchEvent = static_cast<const QTouchEvent*>(event);
-
-    switch (event->type()) {
-    case QEvent::TouchBegin: {
-        kTwoFingerTap->setHotSpot(touchEvent->touchPoints().first().startScreenPos());
-        kTwoFingerTap->setPos(touchEvent->touchPoints().first().startPos());
-        kTwoFingerTap->setScreenPos(touchEvent->touchPoints().first().startScreenPos());
-        kTwoFingerTap->setScenePos(touchEvent->touchPoints().first().startScenePos());
-        m_gestureTriggered = false;
-        return MayBeGesture;
-    }
-
-    case QEvent::TouchUpdate: {
-
-        if (touchEvent->touchPoints().size() > 2) {
-            m_gestureTriggered = false;
-            return CancelGesture;
-        }
-
-        if (touchEvent->touchPoints().size() == 2) {
-            if ((touchEvent->touchPoints().first().startPos() - touchEvent->touchPoints().first().pos()).manhattanLength() >= QApplication::startDragDistance()) {
-                m_gestureTriggered = false;
-                return CancelGesture;
-            }
-            if ((touchEvent->touchPoints().at(1).startPos() - touchEvent->touchPoints().at(1).pos()).manhattanLength() >= QApplication::startDragDistance()) {
-                m_gestureTriggered = false;
-                return CancelGesture;
-            }
-            if (touchEvent->touchPointStates() & Qt::TouchPointPressed) {
-                m_gestureTriggered = true;
-            }
-            if (touchEvent->touchPointStates() & Qt::TouchPointReleased && m_gestureTriggered) {
-                m_gestureTriggered = false;
-                return FinishGesture;
-            }
-        }
-        break;
-    }
-
-    default:
-        return Ignore;
-    }
-    return Ignore;
-}
-
-KTwoFingerTap::KTwoFingerTap(QObject* parent) :
-    QGesture(parent),
-    m_pos(QPointF(-1, -1)),
-    m_screenPos(QPointF(-1, -1)),
-    m_scenePos(QPointF(-1, -1))
-{
-}
-
-KTwoFingerTap::~KTwoFingerTap()
-{
-}
-
-QPointF KTwoFingerTap::pos() const
-{
-    return m_pos;
-}
-
-void KTwoFingerTap::setPos(QPointF _pos)
-{
-    m_pos = _pos;
-}
-
-QPointF KTwoFingerTap::screenPos() const
-{
-    return m_screenPos;
-}
-
-void KTwoFingerTap::setScreenPos(QPointF _screenPos)
-{
-    m_screenPos = _screenPos;
-}
-
-QPointF KTwoFingerTap::scenePos() const
-{
-    return m_scenePos;
-}
-
-void KTwoFingerTap::setScenePos(QPointF _scenePos)
-{
-    m_scenePos = _scenePos;
-}
diff --git a/src/kitemviews/private/ktwofingertap.h b/src/kitemviews/private/ktwofingertap.h
deleted file mode 100644 (file)
index 6d40990..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2020 Steffen Hartleib <steffenhartleib@t-online.de>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef KTWOFINGERTAP_H
-#define KTWOFINGERTAP_H
-
-#include <dolphin_export.h>
-// Qt
-#include <QGesture>
-#include <QGestureRecognizer>
-
-class DOLPHIN_EXPORT KTwoFingerTap : public QGesture
-{
-    Q_OBJECT
-    Q_PROPERTY(QPointF pos READ pos WRITE setPos)
-    Q_PROPERTY(QPointF screenPos READ screenPos WRITE setScreenPos)
-    Q_PROPERTY(QPointF scenePos READ scenePos WRITE setScenePos)
-public:
-    explicit KTwoFingerTap(QObject* parent = nullptr);
-    ~KTwoFingerTap() override;
-    QPointF pos() const;
-    void setPos(QPointF pos);
-    QPointF screenPos() const;
-    void setScreenPos(QPointF screenPos);
-    QPointF scenePos() const;
-    void setScenePos(QPointF scenePos);
-private:
-    QPointF m_pos;
-    QPointF m_screenPos;
-    QPointF m_scenePos;
-};
-
-class DOLPHIN_EXPORT KTwoFingerTapRecognizer : public QGestureRecognizer
-{
-public:
-    explicit KTwoFingerTapRecognizer();
-    ~KTwoFingerTapRecognizer() override;
-    QGesture* create(QObject*) override; 
-    Result recognize(QGesture*, QObject*, QEvent*) override;
-private:
-    Q_DISABLE_COPY(KTwoFingerTapRecognizer)
-    bool m_gestureTriggered;
-};
-
-#endif /* KTWOFINGERTAP_H */
index a6ab14067b946451cb3e0756c4c2eb9b5e10ed50..d3a4e8680ad07dc09b0a3bb24736545dbbcb7d15 100755 (executable)
@@ -135,10 +135,11 @@ Keywords[ko]=files;file management;file browsing;samba;network shares;Explorer;F
 Keywords[nl]=bestanden;bestandsbeheer;bladeren in bestanden;samba;netwerk-shares;verkenner;zoeksysteem;
 Keywords[nn]=filer;filhandsaming;filutforsking;samba;nettverksressursar;Explorer;Finder;
 Keywords[pl]=pliki;zarządzenie plikami;przeglądanie plików;samba;udziały sieciowe;Przeglądarka;Finder;
+Keywords[pt]=ficheiros;gestão de ficheiros;navegação de ficheiros;samba;partilhas de rede;Explorador;Pesquisa;
 Keywords[pt_BR]=arquivo;gerenciamento de arquivos;navegação de arquivos;samba;compartilhamentos de rede;explorador;localizador;
 Keywords[ro]=fișiere;gestiune fișiere;răsfoire fișiere;samba;partajări de rețea;unități de rețea;Explorer;Finder;
 Keywords[ru]=files;file management;file browsing;samba;network shares;Explorer;Finder;файлы,управление файлами,просмотр файлов,сетевые папки
-Keywords[sk]=súbory;správa súborov;prehliadanie súborov;samba;sieťové akcie;Prieskumník;Vyhľadávač;
+Keywords[sk]=súbory;správa súborov;prehliadanie súborov;samba;zdieľanie v sieti;Prieskumník;Vyhľadávač;
 Keywords[sl]=datoteke;upravljanje z datotekami;brskanje po datotekah;samba;mrežni diski;Raziskovalec;Iskalec;
 Keywords[sv]=filer;filhantering;filbläddring;samba;delade nätverksresurser;Utforskare;Finder;
 Keywords[tr]=dosyalar;dosya yönetimi;dosya göz at;samba;ağ paylaşımları;Explorer;Finder;
index 91da3d256ea367c407a9084d891b3c783079b6fe..7f42ee3bd5927e3ec109ffac44d259491eea3401 100644 (file)
@@ -50,7 +50,7 @@ Q_NORETURN void fail(const QString &str)
 QString getServiceMenusDir()
 {
     const QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
-    return QDir(dataLocation).absoluteFilePath("kservices5/ServiceMenus");
+    return QDir(dataLocation).absoluteFilePath("kio/servicemenus");
 }
 
 #ifdef HAVE_PACKAGEKIT
@@ -300,6 +300,8 @@ bool cmdInstall(const QString &archive, QString &errorText)
             errorText = i18n("Failed to copy .desktop file %1 to %2: %3", archive, dest, source.errorString());
             return false;
         }
+        QFile destFile(dest);
+        destFile.setPermissions(destFile.permissions() | QFile::ExeOwner);
     } else {
         if (binaryPackages->contains(QMimeDatabase().mimeTypeForFile(archive).name())) {
             packageKit(PackageOperation::Install, archive);
index 12f10f101e5540b8369a2c4ef3b09b1e29a89f95..2ee85e89a87a8bdef0a362e6604b98a6bcad27f6 100644 (file)
@@ -11,7 +11,7 @@
 #include <QWidget>
 
 #include <KIO/EmptyTrashJob>
-#include <KIOWidgets/KDirLister>
+#include <KDirLister>
 
 class Trash: public QObject
 {
index 5646fa9828ccabdcad33ffe746f682a58d2cb8bd..e6aecff80bad89fafc8909d89e9852061cc9997a 100644 (file)
@@ -1058,12 +1058,12 @@ void DolphinView::slotItemContextMenuRequested(int index, const QPointF& pos)
     }
 
     const KFileItem item = m_model->fileItem(index);
-    Q_EMIT requestContextMenu(pos.toPoint(), item, url(), QList<QAction*>());
+    Q_EMIT requestContextMenu(pos.toPoint(), item, selectedItems(), url());
 }
 
 void DolphinView::slotViewContextMenuRequested(const QPointF& pos)
 {
-    Q_EMIT requestContextMenu(pos.toPoint(), KFileItem(), url(), QList<QAction*>());
+    Q_EMIT requestContextMenu(pos.toPoint(), KFileItem(), selectedItems(), url());
 }
 
 void DolphinView::slotHeaderContextMenuRequested(const QPointF& pos)
index e93ca4fa026bebe041ad80791ad55d8d690ffdcf..b40be89367e12a1bc2f145a2ba7a2afc04f02b5f 100644 (file)
@@ -510,13 +510,12 @@ Q_SIGNALS:
     /**
      * Is emitted if a context menu is requested for the item \a item,
      * which is part of \a url. If the item is null, the context menu
-     * for the URL should be shown and the custom actions \a customActions
-     * will be added.
+     * for the URL should be shown.
      */
     void requestContextMenu(const QPoint& pos,
                             const KFileItem& item,
-                            const QUrl& url,
-                            const QList<QAction*>& customActions);
+                            const KFileItemList &selectedItems,
+                            const QUrl& url);
 
     /**
      * Is emitted if an information message with the content \a msg
index 2e524f8f224f438e011e4cc3984d7f30359c71cd..c02d7856b205d6aa9e65fea00ee38e68de942dda 100644 (file)
@@ -8,6 +8,7 @@
 #include "dolphinviewactionhandler.h"
 
 #include "dolphindebug.h"
+#include "kitemviews/kfileitemlisttostring.h"
 #include "kitemviews/kfileitemmodel.h"
 #include "settings/viewpropertiesdialog.h"
 #include "views/zoomlevelinfo.h"
@@ -763,49 +764,25 @@ void DolphinViewActionHandler::slotCopyPath()
 void DolphinViewActionHandler::slotSelectionChanged(const KFileItemList& selection)
 {
     QString basicActionsMenuText;
-    switch (selection.count()) {
-    case 0:
+    if (selection.isEmpty()) {
         basicActionsMenuText =
             i18nc("@action:inmenu menu with actions like copy, paste, rename. The user's selection is empty when this text is shown.",
                   "Actions for Current View");
-        break;
-    case 1:
-        basicActionsMenuText =
-            i18nc("@action:inmenu menu with actions like copy, paste, rename. %1 is the name of the singular selected file/folder.",
-                  "Actions for \"%1\"", selection.first().name());
-        break;
-    case 2:
-        basicActionsMenuText =
-            i18nc("@action:inmenu menu with actions like copy, paste, rename. %1 and %2 are names of files/folders.",
-                  "Actions for \"%1\" and \"%2\"", selection.first().name(), selection.last().name());
-        break;
-    case 3:
-        basicActionsMenuText =
-            i18nc("@action:inmenu menu with actions like copy, paste, rename. %1, %2 and %3 are names of files/folders.",
-                  "Actions for \"%1\", \"%2\" and \"%3\"",
-                  selection.first().name(), selection.at(1).name(), selection.last().name());
-        break;
-    default:
-        basicActionsMenuText = QString();
-        break;
+    } else {
+        QFontMetrics fontMetrics = QMenu().fontMetrics();
+        // i18n: @action:inmenu menu with actions like copy, paste, rename.
+        // %1 is a textual representation of the currently selected files or folders. This can be the name of
+        // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders".
+        // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes)
+        // and a fallback will be used.
+        basicActionsMenuText = i18n("Actions for %1", fileItemListToString(selection, fontMetrics.averageCharWidth() * 40, fontMetrics, ItemsState::Selected));
     }
 
-    // At some point the added clarity from the text starts being less important than the menu width.
-    if (basicActionsMenuText.isEmpty() || basicActionsMenuText.length() > 40) {
+    if (basicActionsMenuText == QStringLiteral("NULL")) {
         const KFileItemListProperties properties(selection);
-        if (properties.isFile()) {
-            basicActionsMenuText =
-                i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.",
-                       "Actions for One Selected File", "Actions for %1 Selected Files", selection.count());
-        } else if (properties.isDirectory()) {
-            basicActionsMenuText =
-                i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.",
-                       "Actions for One Selected Folder", "Actions for %1 Selected Folders", selection.count());
-        } else {
-            basicActionsMenuText =
-                i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.",
-                       "Actions for One Selected Item", "Actions for %1 Selected Items", selection.count());
-        }
+        basicActionsMenuText =
+            i18ncp("@action:inmenu menu with actions like copy, paste, rename. %1 is the amount of selected files/folders.",
+                    "Actions for One Selected Item", "Actions for %1 Selected Items", selection.count());
     }
 
     QAction *basicActionsMenu = m_actionCollection->action(QStringLiteral("basic_actions"));
index 54af9c94cf9e16e98a5efb8b8d0eaf82a9b23996..6372617027da3e892d6f640d088e79410cac7f0f 100644 (file)
@@ -38,7 +38,6 @@ ToolTipManager::ToolTipManager(QWidget* parent) :
     m_showToolTipTimer(nullptr),
     m_contentRetrievalTimer(nullptr),
     m_transientParent(nullptr),
-    m_fileMetaDataWidget(nullptr),
     m_toolTipRequested(false),
     m_metaDataRequested(false),
     m_appliedWaitCursor(false),
@@ -65,11 +64,14 @@ ToolTipManager::ToolTipManager(QWidget* parent) :
 
 ToolTipManager::~ToolTipManager()
 {
+    if (!m_fileMetaDatWidgetOwnershipTransferred) {
+        delete m_fileMetaDataWidget;
+    }
 }
 
 void ToolTipManager::showToolTip(const KFileItem& item, const QRectF& itemRect, QWindow *transientParent)
 {
-    hideToolTip();
+    hideToolTip(HideBehavior::Instantly);
 
     m_itemRect = itemRect.toRect();
 
@@ -81,11 +83,11 @@ void ToolTipManager::showToolTip(const KFileItem& item, const QRectF& itemRect,
     // Only start the retrieving of the content, when the mouse has been over this
     // item for 200 milliseconds. This prevents a lot of useless preview jobs and
     // meta data retrieval, when passing rapidly over a lot of items.
-    m_fileMetaDataWidget.reset(new DolphinFileMetaDataWidget());
-    connect(m_fileMetaDataWidget.data(), &DolphinFileMetaDataWidget::metaDataRequestFinished,
-            this, &ToolTipManager::slotMetaDataRequestFinished);
-    connect(m_fileMetaDataWidget.data(), &DolphinFileMetaDataWidget::urlActivated,
-            this, &ToolTipManager::urlActivated);
+    if (!m_fileMetaDataWidget) {
+        m_fileMetaDataWidget = new DolphinFileMetaDataWidget();
+        connect(m_fileMetaDataWidget, &DolphinFileMetaDataWidget::metaDataRequestFinished, this, &ToolTipManager::slotMetaDataRequestFinished);
+        connect(m_fileMetaDataWidget, &DolphinFileMetaDataWidget::urlActivated, this, &ToolTipManager::urlActivated);
+    }
 
     m_contentRetrievalTimer->start();
     m_showToolTipTimer->start();
@@ -220,7 +222,10 @@ void ToolTipManager::showToolTip()
     if (!m_tooltipWidget) {
         m_tooltipWidget.reset(new KToolTipWidget());
     }
-    m_tooltipWidget->showBelow(m_itemRect, m_fileMetaDataWidget.data(), m_transientParent);
+    m_tooltipWidget->showBelow(m_itemRect, m_fileMetaDataWidget, m_transientParent);
+    // At this point KToolTipWidget adopted our parent-less metadata widget.
+    m_fileMetaDatWidgetOwnershipTransferred = true;
+
     m_toolTipRequested = false;
 }
 
index 3688e815caa64a69fff976d7dbc2afbc50a9f1f7..c86c97f6bc821db8eb0c681c4896b1750565c3cb 100644 (file)
@@ -77,7 +77,12 @@ private:
     QWindow* m_transientParent;
 
     QScopedPointer<KToolTipWidget> m_tooltipWidget;
-    QScopedPointer<DolphinFileMetaDataWidget> m_fileMetaDataWidget;
+    DolphinFileMetaDataWidget *m_fileMetaDataWidget = nullptr;
+
+    /// Whether ownership of the metadata widget was transferred
+    /// over to the KToolTipWidget (i.e. we should not delete it
+    /// anymore)
+    bool m_fileMetaDatWidgetOwnershipTransferred = false;
 
     bool m_toolTipRequested;
     bool m_metaDataRequested;