]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Merge branch 'Applications/19.08'
authorKai Uwe Broulik <kde@privat.broulik.de>
Mon, 2 Sep 2019 07:13:29 +0000 (09:13 +0200)
committerKai Uwe Broulik <kde@privat.broulik.de>
Mon, 2 Sep 2019 07:13:29 +0000 (09:13 +0200)
26 files changed:
.gitignore
CMakeLists.txt
src/dolphincontextmenu.cpp
src/dolphinmainwindow.cpp
src/dolphinmainwindow.h
src/dolphintabwidget.cpp
src/dolphinui.rc
src/dolphinviewcontainer.cpp
src/dolphinviewcontainer.h
src/global.cpp
src/kitemviews/kfileitemmodel.cpp
src/kitemviews/kfileitemmodel.h
src/kitemviews/kstandarditemlistwidget.cpp
src/panels/information/informationpanelcontent.cpp
src/panels/information/informationpanelcontent.h
src/panels/information/phononwidget.cpp
src/panels/information/phononwidget.h
src/panels/terminal/terminalpanel.cpp
src/settings/general/behaviorsettingspage.cpp
src/settings/services/servicemenuinstaller/servicemenuinstaller.cpp
src/views/dolphinview.cpp
src/views/dolphinview.h
src/views/dolphinviewactionhandler.cpp
src/views/tooltips/tooltipmanager.cpp
src/views/tooltips/tooltipmanager.h
src/views/viewproperties.cpp

index 59d534347018d8fb0ac9e9aa70cc0901741e9057..c48f92390db5edc685e822fdc67e9900d4765815 100644 (file)
@@ -3,3 +3,4 @@ doxygen.log
 CMakeLists.txt.user
 .directory
 *.kdev4
+/build*/
index ee37f38b6153b5a5350910282903119e72ccc51b..91ce0dfa01a1b1136c42b588b2d03aafc9e1880b 100644 (file)
@@ -2,13 +2,13 @@ cmake_minimum_required(VERSION 3.0)
 
 # KDE Application Version, managed by release script
 set (KDE_APPLICATIONS_VERSION_MAJOR "19")
-set (KDE_APPLICATIONS_VERSION_MINOR "08")
-set (KDE_APPLICATIONS_VERSION_MICRO "1")
+set (KDE_APPLICATIONS_VERSION_MINOR "11")
+set (KDE_APPLICATIONS_VERSION_MICRO "70")
 set (KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}")
 project(Dolphin VERSION ${KDE_APPLICATIONS_VERSION})
 
 set(QT_MIN_VERSION "5.8.0")
-set(KF5_MIN_VERSION "5.57.0")
+set(KF5_MIN_VERSION "5.61.0")
 
 # ECM setup
 find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED)
index 1dfbe054dd12a8afe251bfe44d5b72d5896540d0..7e6a45171f3560d1b60494141c19da7db18dca61 100644 (file)
@@ -1,4 +1,4 @@
-/***************************************************************************
+  /***************************************************************************
  *   Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) and              *
  *   Cvetoslav Ludmiloff                                                   *
  *                                                                         *
@@ -192,7 +192,6 @@ void DolphinContextMenu::openItemContextMenu()
     QAction* openParentAction = nullptr;
     QAction* openParentInNewWindowAction = nullptr;
     QAction* openParentInNewTabAction = nullptr;
-    QAction* addToPlacesAction = nullptr;
     const KFileItemListProperties& selectedItemsProps = selectedItemsProperties();
 
     KFileItemActions fileItemActions;
@@ -210,9 +209,7 @@ void DolphinContextMenu::openItemContextMenu()
 
             // insert 'Add to Places' entry
             if (!placeExists(m_fileInfo.url())) {
-                addToPlacesAction = addAction(QIcon::fromTheme(QStringLiteral("bookmark-new")),
-                                                       i18nc("@action:inmenu Add selected folder to places",
-                                                             "Add to Places"));
+                addAction(m_mainWindow->actionCollection()->action(QStringLiteral("add_to_places")));
             }
 
             addSeparator();
@@ -314,14 +311,7 @@ void DolphinContextMenu::openItemContextMenu()
 
     QAction* activatedAction = exec(m_pos);
     if (activatedAction) {
-        if (activatedAction == addToPlacesAction) {
-            const QUrl selectedUrl(m_fileInfo.url());
-            if (selectedUrl.isValid()) {
-                PlacesItemModel model;
-                const QString text = selectedUrl.fileName();
-                model.createPlacesItem(text, selectedUrl, KIO::iconNameForUrl(selectedUrl));
-            }
-        } else if (activatedAction == openParentAction) {
+        if (activatedAction == openParentAction) {
             m_command = OpenParentFolder;
         } else if (activatedAction == openParentInNewWindowAction) {
             m_command = OpenParentFolderInNewWindow;
@@ -365,10 +355,8 @@ void DolphinContextMenu::openViewportContextMenu()
     addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new_tab")));
 
     // Insert 'Add to Places' entry if exactly one item is selected
-    QAction* addToPlacesAction = nullptr;
     if (!placeExists(m_mainWindow->activeViewContainer()->url())) {
-        addToPlacesAction = addAction(QIcon::fromTheme(QStringLiteral("bookmark-new")),
-                                             i18nc("@action:inmenu Add current folder to places", "Add to Places"));
+        addAction(m_mainWindow->actionCollection()->action(QStringLiteral("add_to_places")));
     }
 
     addSeparator();
@@ -395,22 +383,6 @@ void DolphinContextMenu::openViewportContextMenu()
     addAction(propertiesAction);
 
     addShowMenuBarAction();
-
-    QAction* action = exec(m_pos);
-    if (addToPlacesAction && (action == addToPlacesAction)) {
-        const DolphinViewContainer* container =  m_mainWindow->activeViewContainer();
-        const QUrl url = container->url();
-        if (url.isValid()) {
-            PlacesItemModel model;
-            QString icon;
-            if (container->isSearchModeEnabled()) {
-                icon = QStringLiteral("folder-saved-search-symbolic");
-            } else {
-                icon = KIO::iconNameForUrl(url);
-            }
-            model.createPlacesItem(container->placesText(), url, icon);
-        }
-    }
 }
 
 void DolphinContextMenu::insertDefaultItemActions(const KFileItemListProperties& properties)
index 19f7906629ad75dd2145c15d2ea0b37b8c5d93e9..004e8e165e8fcfb2fe5812ed77ce6955bd4d3df1 100644 (file)
@@ -32,6 +32,7 @@
 #include "dolphintabpage.h"
 #include "middleclickactioneventfilter.h"
 #include "panels/folders/folderspanel.h"
+#include "panels/places/placesitemmodel.h"
 #include "panels/places/placespanel.h"
 #include "panels/information/informationpanel.h"
 #include "panels/terminal/terminalpanel.h"
@@ -272,7 +273,7 @@ void DolphinMainWindow::changeUrl(const QUrl &url)
     }
 
     m_activeViewContainer->setUrl(url);
-    updateEditActions();
+    updateFileAndEditActions();
     updatePasteAction();
     updateViewActions();
     updateGoActions();
@@ -301,7 +302,7 @@ void DolphinMainWindow::slotEditableStateChanged(bool editable)
 
 void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection)
 {
-    updateEditActions();
+    updateFileAndEditActions();
 
     const int selectedUrlsCount = m_tabWidget->currentTabPage()->selectedItemsCount();
 
@@ -352,6 +353,32 @@ void DolphinMainWindow::openNewActivatedTab()
     m_tabWidget->openNewActivatedTab();
 }
 
+void DolphinMainWindow::addToPlaces()
+{
+    QUrl url;
+    QString name;
+
+    // If nothing is selected, act on the current dir
+    if (m_activeViewContainer->view()->selectedItems().count() == 0) {
+        url = m_activeViewContainer->url();
+        name = m_activeViewContainer->placesText();
+    } else {
+        const auto dirToAdd = m_activeViewContainer->view()->selectedItems().first();
+        url = dirToAdd.url();
+        name = dirToAdd.name();
+    }
+    if (url.isValid()) {
+        PlacesItemModel model;
+        QString icon;
+        if (m_activeViewContainer->isSearchModeEnabled()) {
+            icon = QStringLiteral("folder-saved-search-symbolic");
+        } else {
+            icon = KIO::iconNameForUrl(url);
+        }
+        model.createPlacesItem(name, url, icon);
+    }
+}
+
 void DolphinMainWindow::openNewTab(const QUrl& url, DolphinTabWidget::TabPlacement tabPlacement)
 {
     m_tabWidget->openNewTab(url, QUrl(), tabPlacement);
@@ -617,6 +644,12 @@ void DolphinMainWindow::find()
     m_activeViewContainer->setSearchModeEnabled(true);
 }
 
+void DolphinMainWindow::updateSearchAction()
+{
+    QAction* toggleSearchAction = actionCollection()->action(QStringLiteral("toggle_search"));
+    toggleSearchAction->setChecked(m_activeViewContainer->isSearchModeEnabled());
+}
+
 void DolphinMainWindow::updatePasteAction()
 {
     QAction* pasteAction = actionCollection()->action(KStandardAction::name(KStandardAction::Paste));
@@ -751,7 +784,7 @@ void DolphinMainWindow::togglePanelLockState()
 
 void DolphinMainWindow::slotTerminalPanelVisibilityChanged()
 {
-    if (m_terminalPanel->isHiddenInVisibleWindow()) {
+    if (m_terminalPanel->isHiddenInVisibleWindow() && m_activeViewContainer) {
         m_activeViewContainer->view()->setFocus();
     }
 }
@@ -1084,6 +1117,9 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer)
     m_activeViewContainer = viewContainer;
 
     if (oldViewContainer) {
+        const QAction* toggleSearchAction = actionCollection()->action(QStringLiteral("toggle_search"));
+        toggleSearchAction->disconnect(oldViewContainer);
+
         // Disconnect all signals between the old view container (container,
         // view and url navigator) and main window.
         oldViewContainer->disconnect(this);
@@ -1100,10 +1136,11 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer)
     m_actionHandler->setCurrentView(viewContainer->view());
 
     updateHistory();
-    updateEditActions();
+    updateFileAndEditActions();
     updatePasteAction();
     updateViewActions();
     updateGoActions();
+    updateSearchAction();
 
     const QUrl url = viewContainer->url();
     emit urlChanged(url);
@@ -1156,6 +1193,7 @@ void DolphinMainWindow::setupActions()
 
     QAction* newWindow = KStandardAction::openNew(this, &DolphinMainWindow::openNewMainWindow, actionCollection());
     newWindow->setText(i18nc("@action:inmenu File", "New &Window"));
+    newWindow->setToolTip(i18nc("@info", "Open a new Dolphin window"));
     newWindow->setWhatsThis(xi18nc("@info:whatsthis", "This opens a new "
         "window just like this one with the current location and view."
         "<nl/>You can drag and drop items between windows."));
@@ -1171,6 +1209,12 @@ void DolphinMainWindow::setupActions()
     actionCollection()->setDefaultShortcuts(newTab, {Qt::CTRL + Qt::Key_T, Qt::CTRL + Qt::SHIFT + Qt::Key_N});
     connect(newTab, &QAction::triggered, this, &DolphinMainWindow::openNewActivatedTab);
 
+    QAction* addToPlaces = actionCollection()->addAction(QStringLiteral("add_to_places"));
+    addToPlaces->setIcon(QIcon::fromTheme(QStringLiteral("bookmark-new")));
+    addToPlaces->setWhatsThis(xi18nc("@info:whatsthis", "This adds the selected folder "
+        "to the Places panel."));
+    connect(addToPlaces, &QAction::triggered, this, &DolphinMainWindow::addToPlaces);
+
     QAction* closeTab = KStandardAction::close(m_tabWidget, QOverload<>::of(&DolphinTabWidget::closeTab), actionCollection());
     closeTab->setText(i18nc("@action:inmenu File", "Close Tab"));
     closeTab->setWhatsThis(i18nc("@info:whatsthis", "This closes the "
@@ -1224,6 +1268,17 @@ void DolphinMainWindow::setupActions()
         "the find bar so we can have a look at it while the settings are "
         "explained.</para>"));
 
+    // toggle_search acts as a copy of the main searchAction to be used mainly
+    // in the toolbar, with no default shortcut attached, to avoid messing with
+    // existing workflows (search bar always open and Ctrl-F to focus)
+    QAction *toggleSearchAction = actionCollection()->addAction(QStringLiteral("toggle_search"));
+    toggleSearchAction->setText(i18nc("@action:inmenu", "Toggle Search Bar"));
+    toggleSearchAction->setIconText(i18nc("@action:intoolbar", "Search"));
+    toggleSearchAction->setIcon(searchAction->icon());
+    toggleSearchAction->setToolTip(searchAction->toolTip());
+    toggleSearchAction->setWhatsThis(searchAction->whatsThis());
+    toggleSearchAction->setCheckable(true);
+
     QAction* selectAllAction = KStandardAction::selectAll(this, &DolphinMainWindow::selectAll, actionCollection());
     selectAllAction->setWhatsThis(xi18nc("@info:whatsthis", "This selects all "
         "files and folders in the current location."));
@@ -1659,15 +1714,20 @@ void DolphinMainWindow::setupDockWidgets()
     });
 }
 
-void DolphinMainWindow::updateEditActions()
+
+void DolphinMainWindow::updateFileAndEditActions()
 {
     const KFileItemList list = m_activeViewContainer->view()->selectedItems();
+    const KActionCollection* col = actionCollection();
+    QAction* addToPlacesAction = col->action(QStringLiteral("add_to_places"));
+
     if (list.isEmpty()) {
         stateChanged(QStringLiteral("has_no_selection"));
+
+        addToPlacesAction->setText(i18nc("@action:inmenu Add current folder to places", "Add '%1' to Places", m_activeViewContainer->placesText()));
     } else {
         stateChanged(QStringLiteral("has_selection"));
 
-        KActionCollection* col = actionCollection();
         QAction* renameAction            = col->action(KStandardAction::name(KStandardAction::RenameFile));
         QAction* moveToTrashAction       = col->action(KStandardAction::name(KStandardAction::MoveToTrash));
         QAction* deleteAction            = col->action(KStandardAction::name(KStandardAction::DeleteFile));
@@ -1675,6 +1735,14 @@ void DolphinMainWindow::updateEditActions()
         QAction* deleteWithTrashShortcut = col->action(QStringLiteral("delete_shortcut")); // see DolphinViewActionHandler
         QAction* showTarget              = col->action(QStringLiteral("show_target"));
 
+        if (list.length() == 1 && list.first().isDir()) {
+            addToPlacesAction->setEnabled(true);
+            addToPlacesAction->setText(i18nc("@action:inmenu Add current folder to places", "Add '%1' to Places", list.first().name()));
+        } else {
+            addToPlacesAction->setEnabled(false);
+            addToPlacesAction->setText(i18nc("@action:inmenu Add current folder to places", "Add to Places"));
+        }
+
         KFileItemListProperties capabilities(list);
         const bool enableMoveToTrash = capabilities.isLocal() && capabilities.supportsMoving();
 
@@ -1727,10 +1795,9 @@ void DolphinMainWindow::createControlButton()
 
     m_controlButton = new QToolButton(this);
     m_controlButton->setIcon(QIcon::fromTheme(QStringLiteral("application-menu")));
-    m_controlButton->setText(i18nc("@action", "Control"));
+    m_controlButton->setToolTip(i18nc("@action", "Show menu"));
     m_controlButton->setAttribute(Qt::WidgetAttribute::WA_CustomWhatsThis);
     m_controlButton->setPopupMode(QToolButton::InstantPopup);
-    m_controlButton->setToolButtonStyle(toolBar()->toolButtonStyle());
 
     QMenu* controlMenu = new QMenu(m_controlButton);
     connect(controlMenu, &QMenu::aboutToShow, this, &DolphinMainWindow::updateControlMenu);
@@ -1741,8 +1808,6 @@ void DolphinMainWindow::createControlButton()
     toolBar()->addWidget(m_controlButton);
     connect(toolBar(), &KToolBar::iconSizeChanged,
             m_controlButton, &QToolButton::setIconSize);
-    connect(toolBar(), &KToolBar::toolButtonStyleChanged,
-            m_controlButton, &QToolButton::setToolButtonStyle);
 
     // The added widgets are owned by the toolbar and may get deleted when e.g. the toolbar
     // gets edited. In this case we must add them again. The adding is done asynchronously by
@@ -1805,6 +1870,11 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
             this, &DolphinMainWindow::updateFilterBarAction);
     connect(container, &DolphinViewContainer::writeStateChanged,
             this, &DolphinMainWindow::slotWriteStateChanged);
+    connect(container, &DolphinViewContainer::searchModeEnabledChanged,
+            this, &DolphinMainWindow::updateSearchAction);
+
+    const QAction* toggleSearchAction = actionCollection()->action(QStringLiteral("toggle_search"));
+    connect(toggleSearchAction, &QAction::triggered, container, &DolphinViewContainer::setSearchModeEnabled);
 
     const DolphinView* view = container->view();
     connect(view, &DolphinView::selectionChanged,
index dcfd9bce2dd022414c899616d705bd230c7bdc78..253fc74d4ebc9c358f5c54bbbc471fdc3772e04e 100644 (file)
@@ -255,6 +255,9 @@ private slots:
     /** Replaces the URL navigator by a search box to find files. */
     void find();
 
+    /** Updates the state of the search action according to the view container. */
+    void updateSearchAction();
+
     /**
      * Updates the text of the paste action dependent on
      * the number of items which are in the clipboard.
@@ -381,6 +384,11 @@ private slots:
      */
     void openNewActivatedTab();
 
+    /**
+     * Adds the current URL as an entry to the Places panel
+     */
+    void addToPlaces();
+
     /**
      * Opens a new tab in the background showing the URL \a url.
      */
@@ -512,7 +520,7 @@ private:
      */
     void setupDockWidgets();
 
-    void updateEditActions();
+    void updateFileAndEditActions();
     void updateViewActions();
     void updateGoActions();
 
index defd089c16075cf48e1ca31e0a3779eb0aba7faf..afb5462e1ad4fcdc9cff9fdd12a1b705d0c23ca4 100644 (file)
@@ -161,6 +161,7 @@ void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryU
     QWidget* focusWidget = QApplication::focusWidget();
 
     DolphinTabPage* tabPage = new DolphinTabPage(primaryUrl, secondaryUrl, this);
+    tabPage->setActive(false);
     tabPage->setPlacesSelectorVisible(m_placesSelectorVisible);
     connect(tabPage, &DolphinTabPage::activeViewChanged,
             this, &DolphinTabWidget::activeViewChanged);
index b90321d0592e19d6e1beb3d818b8e4fc180336d9..754670a7ef32827d74cc68b8005f7b989f319f83 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<kpartgui name="dolphin" version="22">
+<kpartgui name="dolphin" version="25">
     <MenuBar>
         <Menu name="file">
             <Action name="new_menu" />
@@ -8,6 +8,8 @@
             <Action name="file_close" />
             <Action name="undo_close_tab" />
             <Separator/>
+            <Action name="add_to_places" />
+            <Separator/>
             <Action name="renamefile" />
             <Action name="movetotrash" />
             <Action name="deletefile" />
         <Action name="compact" />
         <Action name="details" />
         <Separator name="separator_0" />
-        <Action name="edit_find"/>
-        <Action name="show_preview" />
+        <Action name="sort" />
+        <Spacer name="spacer_0" />
         <Action name="split_view" />
         <Action name="split_stash" />
+        <Action name="toggle_search" />
     </ToolBar>
     <ActionProperties scheme="Default">
         <Action priority="0" name="go_back"/>
         <Action priority="0" name="edit_cut"/>
         <Action priority="0" name="edit_copy"/>
         <Action priority="0" name="edit_paste"/>
+        <Action priority="0" name="toggle_search"/>
     </ActionProperties>
 </kpartgui>
index 585610550573c4c1962edf0276fc76ffdcae57b3..93e785f0d594f3e2234f98079c5148b00e27b1c3 100644 (file)
@@ -412,6 +412,8 @@ void DolphinViewContainer::setSearchModeEnabled(bool enabled)
     }
 
     m_searchModeEnabled = enabled;
+
+    emit searchModeEnabledChanged(enabled);
 }
 
 bool DolphinViewContainer::isSearchModeEnabled() const
index 2c4c7a7e196e0ba4d768c072d016fd6ae2de462f..5207d2d35d47cf39572d156916d8ce504d65809f 100644 (file)
@@ -118,11 +118,8 @@ public:
     /** Returns true, if the filter bar is visible. */
     bool isFilterBarVisible() const;
 
-    /**
-     * Enables the search mode, if \p enabled is true. In the search mode the URL navigator
-     * will be hidden and replaced by a line editor that allows to enter a search term.
-     */
-    void setSearchModeEnabled(bool enabled);
+
+    /** Returns true if the search mode is enabled. */
     bool isSearchModeEnabled() const;
 
     /**
@@ -160,11 +157,21 @@ public slots:
      */
     void setFilterBarVisible(bool visible);
 
+    /**
+     * Enables the search mode, if \p enabled is true. In the search mode the URL navigator
+     * will be hidden and replaced by a line editor that allows to enter a search term.
+     */
+    void setSearchModeEnabled(bool enabled);
+
 signals:
     /**
      * Is emitted whenever the filter bar has changed its visibility state.
      */
     void showFilterBarChanged(bool shown);
+    /**
+     * Is emitted whenever the search mode has changed its state.
+     */
+    void searchModeEnabledChanged(bool enabled);
 
     /**
      * Is emitted when the write state of the folder has been changed. The application
index 21660a8281a66311216c0a0e41cd314720027b36..12f86a2f369ace55f2dc082acdee69a09f6e479c 100644 (file)
@@ -77,12 +77,6 @@ bool Dolphin::attachToExistingInstance(const QList<QUrl>& inputUrls, bool openFi
         return false;
     }
 
-    const QStringList services = QDBusConnection::sessionBus().interface()->registeredServiceNames().value();
-
-    // Don't match the service without trailing "-" (unique instance)
-    const QString pattern = QStringLiteral("org.kde.dolphin-");
-    // Don't match the pid without leading "-"
-    const QString myPid = QStringLiteral("-") + QString::number(QCoreApplication::applicationPid());
     QVector<QPair<QSharedPointer<QDBusInterface>, QStringList>> dolphinServices;
     if (!preferredService.isEmpty()) {
         QSharedPointer<QDBusInterface> preferred(
@@ -91,11 +85,16 @@ bool Dolphin::attachToExistingInstance(const QList<QUrl>& inputUrls, bool openFi
             QStringLiteral("org.kde.dolphin.MainWindow"))
         );
         if (preferred->isValid() && !preferred->lastError().isValid()) {
-            dolphinServices.append(qMakePair(preferred, QStringList() ));
+            dolphinServices.append(qMakePair(preferred, QStringList()));
         }
     }
 
     // find all dolphin instances
+    const QStringList services = QDBusConnection::sessionBus().interface()->registeredServiceNames().value();
+    // Don't match the service without trailing "-" (unique instance)
+    const QString pattern = QStringLiteral("org.kde.dolphin-");
+    // Don't match the pid without leading "-"
+    const QString myPid = QStringLiteral("-") + QString::number(QCoreApplication::applicationPid());
     for (const QString& service : services) {
         if (service.startsWith(pattern) && !service.endsWith(myPid)) {
             // Check if instance can handle our URLs
@@ -104,10 +103,9 @@ bool Dolphin::attachToExistingInstance(const QList<QUrl>& inputUrls, bool openFi
                 QStringLiteral("/dolphin/Dolphin_1"),
                 QStringLiteral("org.kde.dolphin.MainWindow"))
             );
-            if (!instance->isValid() || instance->lastError().isValid()) {
-                continue;
+            if (instance->isValid() && !instance->lastError().isValid()) {
+                dolphinServices.append(qMakePair(instance, QStringList()));
             }
-            dolphinServices.append(qMakePair(instance, QStringList()));
         }
     }
 
@@ -124,9 +122,9 @@ bool Dolphin::attachToExistingInstance(const QList<QUrl>& inputUrls, bool openFi
         for (auto& service: dolphinServices) {
             QDBusReply<bool> isUrlOpen = service.first->call(QStringLiteral("isUrlOpen"), url);
             if (isUrlOpen.isValid() && isUrlOpen.value()) {
-                    service.second.append(url);
-                    urlFound = true;
-                    break;
+                service.second.append(url);
+                urlFound = true;
+                break;
             }
         }
         if (!urlFound) {
index 8145a00f11ba1f2fc22bd9f7aca0679c3ddfdfdb..091044c06c4e00480db701157891d3dbd49a525f 100644 (file)
@@ -917,6 +917,7 @@ void KFileItemModel::resortAllItems()
 
 void KFileItemModel::slotCompleted()
 {
+    m_maximumUpdateIntervalTimer->stop();
     dispatchPendingItemsToInsert();
 
     if (!m_urlsToExpand.isEmpty()) {
@@ -1007,7 +1008,7 @@ void KFileItemModel::slotItemsAdded(const QUrl &directoryUrl, const KFileItemLis
         }
     }
 
-    if (useMaximumUpdateInterval() && !m_maximumUpdateIntervalTimer->isActive()) {
+    if (!m_maximumUpdateIntervalTimer->isActive()) {
         // Assure that items get dispatched if no completed() or canceled() signal is
         // emitted during the maximum update interval.
         m_maximumUpdateIntervalTimer->start();
@@ -1828,8 +1829,15 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
 
     default: {
         const QByteArray role = roleForType(m_sortRole);
-        result = QString::compare(a->values.value(role).toString(),
-                                  b->values.value(role).toString());
+        const QString roleValueA = a->values.value(role).toString();
+        const QString roleValueB = b->values.value(role).toString();
+        if (!roleValueA.isEmpty() && roleValueB.isEmpty()) {
+            result = -1;
+        } else if (roleValueA.isEmpty() && !roleValueB.isEmpty()) {
+            result = +1;
+        } else {
+            result = QString::compare(roleValueA, roleValueB);
+        }
         break;
     }
 
@@ -1875,11 +1883,6 @@ int KFileItemModel::stringCompare(const QString& a, const QString& b, const QCol
     return QString::compare(a, b, Qt::CaseSensitive);
 }
 
-bool KFileItemModel::useMaximumUpdateInterval() const
-{
-    return !m_dirLister->url().isLocalFile();
-}
-
 QList<QPair<int, QVariant> > KFileItemModel::nameRoleGroups() const
 {
     Q_ASSERT(!m_itemData.isEmpty());
@@ -1905,28 +1908,35 @@ QList<QPair<int, QVariant> > KFileItemModel::nameRoleGroups() const
         if (firstChar != newFirstChar) {
             QString newGroupValue;
             if (newFirstChar.isLetter()) {
-                // Try to find a matching group in the range 'A' to 'Z'.
-                static std::vector<QChar> lettersAtoZ;
-                lettersAtoZ.reserve('Z' - 'A' + 1);
-                if (lettersAtoZ.empty()) {
-                    for (char c = 'A'; c <= 'Z'; ++c) {
-                        lettersAtoZ.push_back(QLatin1Char(c));
+
+                if (m_collator.compare(newFirstChar, QChar(QLatin1Char('A'))) >= 0 && m_collator.compare(newFirstChar, QChar(QLatin1Char('Z'))) <= 0) {
+                    // WARNING! Symbols based on latin 'Z' like 'Z' with acute are treated wrong as non Latin and put in a new group.
+
+                    // Try to find a matching group in the range 'A' to 'Z'.
+                    static std::vector<QChar> lettersAtoZ;
+                    lettersAtoZ.reserve('Z' - 'A' + 1);
+                    if (lettersAtoZ.empty()) {
+                        for (char c = 'A'; c <= 'Z'; ++c) {
+                            lettersAtoZ.push_back(QLatin1Char(c));
+                        }
                     }
-                }
 
-                auto localeAwareLessThan = [this](QChar c1, QChar c2) -> bool {
-                    return m_collator.compare(c1, c2) < 0;
-                };
+                    auto localeAwareLessThan = [this](QChar c1, QChar c2) -> bool {
+                        return m_collator.compare(c1, c2) < 0;
+                    };
 
-                std::vector<QChar>::iterator it = std::lower_bound(lettersAtoZ.begin(), lettersAtoZ.end(), newFirstChar, localeAwareLessThan);
-                if (it != lettersAtoZ.end()) {
-                    if (localeAwareLessThan(newFirstChar, *it) && it != lettersAtoZ.begin()) {
-                        // newFirstChar belongs to the group preceding *it.
-                        // Example: for an umlaut 'A' in the German locale, *it would be 'B' now.
-                        --it;
+                    std::vector<QChar>::iterator it = std::lower_bound(lettersAtoZ.begin(), lettersAtoZ.end(), newFirstChar, localeAwareLessThan);
+                    if (it != lettersAtoZ.end()) {
+                        if (localeAwareLessThan(newFirstChar, *it)) {
+                            // newFirstChar belongs to the group preceding *it.
+                            // Example: for an umlaut 'A' in the German locale, *it would be 'B' now.
+                            --it;
+                        }
+                        newGroupValue = *it;
                     }
-                    newGroupValue = *it;
+
                 } else {
+                    // Symbols from non Latin-based scripts
                     newGroupValue = newFirstChar;
                 }
             } else if (newFirstChar >= QLatin1Char('0') && newFirstChar <= QLatin1Char('9')) {
index 0f7926aae1b432f5238999a03cc7247b0015d996..c2dfd01670a96680beb9c0730b860682b1d2dedc 100644 (file)
@@ -382,8 +382,6 @@ private:
 
     int stringCompare(const QString& a, const QString& b, const QCollator& collator) const;
 
-    bool useMaximumUpdateInterval() const;
-
     QList<QPair<int, QVariant> > nameRoleGroups() const;
     QList<QPair<int, QVariant> > sizeRoleGroups() const;
     QList<QPair<int, QVariant> > timeRoleGroups(const std::function<QDateTime(const ItemData *)> &fileTimeCb) const;
index 15c01726fa8b972775d71880bee0ca4cc7298f2d..296cd9bbbfbbbfabce6d14436d914c37411ae103 100644 (file)
@@ -1165,7 +1165,7 @@ void KStandardItemListWidget::updateIconsLayoutTextCache()
                 do {
                     QString lastTextLine = nameText.mid(line.textStart());
                     lastTextLine = m_customizedFontMetrics.elidedText(lastTextLine,
-                                                                      Qt::ElideRight,
+                                                                      Qt::ElideMiddle,
                                                                       elidingWidth);
                     const QString elidedText = nameText.left(line.textStart()) + lastTextLine;
                     nameTextInfo->staticText.setText(elidedText);
@@ -1221,7 +1221,7 @@ void KStandardItemListWidget::updateIconsLayoutTextCache()
             textLine.setLineWidth(maxWidth);
             requiredWidth = textLine.naturalTextWidth();
             if (requiredWidth > maxWidth) {
-                const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+                const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideMiddle, maxWidth);
                 textInfo->staticText.setText(elidedText);
                 requiredWidth = m_customizedFontMetrics.width(elidedText);
             } else if (role == "rating") {
@@ -1270,7 +1270,7 @@ void KStandardItemListWidget::updateCompactLayoutTextCache()
         qreal requiredWidth = m_customizedFontMetrics.width(text);
         if (requiredWidth > maxWidth) {
             requiredWidth = maxWidth;
-            const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+            const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideMiddle, maxWidth);
             textInfo->staticText.setText(elidedText);
         }
 
@@ -1327,7 +1327,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache()
         }
 
         if (requiredWidth > availableTextWidth) {
-            text = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, availableTextWidth);
+            text = m_customizedFontMetrics.elidedText(text, Qt::ElideMiddle, availableTextWidth);
             requiredWidth = m_customizedFontMetrics.width(text);
         }
 
index 363ad818d3dcbc1c027cfa7d935987d41427757e..d54ed66b6f5171f1b18874eb82e4265310731f75 100644 (file)
 #include <QTimer>
 #include <QVBoxLayout>
 #include <QStyle>
+#include <QPainter>
+#include <QBitmap>
+#include <QLinearGradient>
+#include <QPolygon>
 
 #include "dolphin_informationpanelsettings.h"
 #include "phononwidget.h"
 #include "pixmapviewer.h"
 
+const int PLAY_ARROW_SIZE = 24;
+const int PLAY_ARROW_BORDER_SIZE = 2;
+
 InformationPanelContent::InformationPanelContent(QWidget* parent) :
     QWidget(parent),
     m_item(),
@@ -61,7 +68,8 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) :
     m_nameLabel(nullptr),
     m_metaDataWidget(nullptr),
     m_metaDataArea(nullptr),
-    m_placesItemModel(nullptr)
+    m_placesItemModel(nullptr),
+    m_isVideo(false)
 {
     parent->installEventFilter(this);
 
@@ -166,6 +174,41 @@ void InformationPanelContent::showItem(const KFileItem& item)
     refreshPreview();
 }
 
+void InformationPanelContent::refreshPixmapView()
+{
+    // If there is a preview job, kill it to prevent that we have jobs for
+    // multiple items running, and thus a race condition (bug 250787).
+    if (m_previewJob) {
+        m_previewJob->kill();
+    }
+
+    // try to get a preview pixmap from the item...
+
+    // Mark the currently shown preview as outdated. This is done
+    // with a small delay to prevent a flickering when the next preview
+    // can be shown within a short timeframe. This timer is not started
+    // for directories, as directory previews might fail and return the
+    // same icon.
+    if (!m_item.isDir()) {
+        m_outdatedPreviewTimer->start();
+    }
+
+    QStringList plugins = KIO::PreviewJob::availablePlugins();
+    m_previewJob = new KIO::PreviewJob(KFileItemList() << m_item,
+                                       QSize(m_preview->width(), m_preview->height()),
+                                       &plugins);
+    m_previewJob->setScaleType(KIO::PreviewJob::Unscaled);
+    m_previewJob->setIgnoreMaximumSize(m_item.isLocalFile());
+    if (m_previewJob->uiDelegate()) {
+        KJobWidgets::setWindow(m_previewJob, this);
+    }
+
+    connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview,
+            this, &InformationPanelContent::showPreview);
+    connect(m_previewJob.data(), &KIO::PreviewJob::failed,
+            this, &InformationPanelContent::showIcon);
+}
+
 void InformationPanelContent::refreshPreview()
 {
     // If there is a preview job, kill it to prevent that we have jobs for
@@ -174,6 +217,8 @@ void InformationPanelContent::refreshPreview()
         m_previewJob->kill();
     }
 
+    m_preview->setCursor(Qt::ArrowCursor);
+    bool usePhonon = false;
     setNameLabelText(m_item.text());
     if (InformationPanelSettings::previewsShown()) {
 
@@ -188,53 +233,46 @@ void InformationPanelContent::refreshPreview()
                 QIcon::fromTheme(QStringLiteral("nepomuk")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous)
             );
         } else {
-            // try to get a preview pixmap from the item...
-
-            // Mark the currently shown preview as outdated. This is done
-            // with a small delay to prevent a flickering when the next preview
-            // can be shown within a short timeframe. This timer is not started
-            // for directories, as directory previews might fail and return the
-            // same icon.
-            if (!m_item.isDir()) {
-                m_outdatedPreviewTimer->start();
-            }
 
-            QStringList plugins = KIO::PreviewJob::availablePlugins();
-            m_previewJob = new KIO::PreviewJob(KFileItemList() << m_item,
-                                               QSize(m_preview->width(), m_preview->height()),
-                                               &plugins);
-            m_previewJob->setScaleType(KIO::PreviewJob::Unscaled);
-            m_previewJob->setIgnoreMaximumSize(m_item.isLocalFile());
-            if (m_previewJob->uiDelegate()) {
-                KJobWidgets::setWindow(m_previewJob, this);
-            }
-
-            connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview,
-                    this, &InformationPanelContent::showPreview);
-            connect(m_previewJob.data(), &KIO::PreviewJob::failed,
-                    this, &InformationPanelContent::showIcon);
+            refreshPixmapView();
 
             const QString mimeType = m_item.mimetype();
-            const bool isVideo = mimeType.startsWith(QLatin1String("video/"));
-            const bool usePhonon = mimeType.startsWith(QLatin1String("audio/")) || isVideo;
+            m_isVideo = mimeType.startsWith(QLatin1String("video/"));
+            usePhonon = m_isVideo || mimeType.startsWith(QLatin1String("audio/"));
 
             if (usePhonon) {
-
-                if (InformationPanelSettings::previewsAutoPlay() && isVideo) {
-                    // hides the preview now to avoid flickering when the autoplay video starts
-                    m_preview->hide();
-                } else {
-                    // the video won't play before the preview is displayed
-                    m_preview->show();
+                // change the cursor of the preview
+                m_preview->setCursor(Qt::PointingHandCursor);
+                m_preview->installEventFilter(m_phononWidget);
+
+                // if the video is playing, has been paused or stopped
+                // we don't need to update the preview/phonon widget states
+                // unless the previewed file has changed,
+                // or the setting previewshown has changed
+                if ((m_phononWidget->state() != Phonon::State::PlayingState &&
+                     m_phononWidget->state() != Phonon::State::PausedState &&
+                     m_phononWidget->state() != Phonon::State::StoppedState) ||
+                        m_item.targetUrl() != m_phononWidget->url() ||
+                        (!m_preview->isVisible() &&! m_phononWidget->isVisible())) {
+
+                    if (InformationPanelSettings::previewsAutoPlay() && m_isVideo) {
+                        // hides the preview now to avoid flickering when the autoplay video starts
+                        m_preview->hide();
+                    } else {
+                        // the video won't play before the preview is displayed
+                        m_preview->show();
+                    }
+
+                    m_phononWidget->show();
+                    m_phononWidget->setUrl(m_item.targetUrl(), m_isVideo ? PhononWidget::MediaKind::Video : PhononWidget::MediaKind::Audio);
+                    adjustWidgetSizes(parentWidget()->width());
                 }
-
-                m_phononWidget->show();
-                m_phononWidget->setUrl(m_item.targetUrl(), isVideo ? PhononWidget::MediaKind::Video : PhononWidget::MediaKind::Audio);
-                m_phononWidget->setVideoSize(m_preview->size());
             } else {
                 // When we don't need it, hide the phonon widget first to avoid flickering
                 m_phononWidget->hide();
                 m_preview->show();
+                m_preview->removeEventFilter(m_phononWidget);
+                m_phononWidget->clearUrl();
             }
         }
     } else {
@@ -319,10 +357,46 @@ void InformationPanelContent::showPreview(const KFileItem& item,
                                           const QPixmap& pixmap)
 {
     m_outdatedPreviewTimer->stop();
-    Q_UNUSED(item);
+    Q_UNUSED(item)
 
     QPixmap p = pixmap;
     KIconLoader::global()->drawOverlays(item.overlays(), p, KIconLoader::Desktop);
+
+    if (m_isVideo) {
+        // adds a play arrow
+
+        // compute relative pixel positions
+        const int zeroX = static_cast<int>(p.width() / 2 - PLAY_ARROW_SIZE / 2 / devicePixelRatio());
+        const int zeroY = static_cast<int>(p.height() / 2 - PLAY_ARROW_SIZE / 2 / devicePixelRatio());
+
+        QPolygon arrow;
+        arrow << QPoint(zeroX, zeroY);
+        arrow << QPoint(zeroX, zeroY + PLAY_ARROW_SIZE);
+        arrow << QPoint(zeroX + PLAY_ARROW_SIZE, zeroY + PLAY_ARROW_SIZE / 2);
+
+        QPainterPath path;
+        path.addPolygon(arrow);
+
+        QLinearGradient gradient(QPointF(zeroX, zeroY),
+                                 QPointF(zeroX + PLAY_ARROW_SIZE,zeroY + PLAY_ARROW_SIZE));
+
+        QColor whiteColor = Qt::white;
+        QColor blackColor = Qt::black;
+        gradient.setColorAt(0, whiteColor);
+        gradient.setColorAt(1, blackColor);
+
+        QBrush brush(gradient);
+
+        QPainter painter(&p);
+
+        QPen pen(blackColor, PLAY_ARROW_BORDER_SIZE, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
+        painter.setPen(pen);
+
+        painter.setRenderHint(QPainter::Antialiasing);
+        painter.drawPolygon(arrow);
+        painter.fillPath(path, brush);
+    }
+
     m_preview->setPixmap(p);
 }
 
@@ -343,6 +417,11 @@ KFileItemList InformationPanelContent::items()
 void InformationPanelContent::slotHasVideoChanged(bool hasVideo)
 {
     m_preview->setVisible(InformationPanelSettings::previewsShown() && !hasVideo);
+    if (m_preview->isVisible() && m_preview->size().width() != m_preview->pixmap().size().width()) {
+        // in case the information panel has been resized when the preview was not displayed
+        // we need to refresh its content
+        refreshPixmapView();
+    }
 }
 
 void InformationPanelContent::setPreviewAutoPlay(bool autoPlay) {
index 0d838b26882d30baa1d734e905adf92f87ec89f4..8daeb95b0c16479da827fde7ff58bd2610b5af10 100644 (file)
@@ -139,6 +139,11 @@ private:
      */
     void adjustWidgetSizes(int width);
 
+    /**
+     * Refreshes the image in the PixmapViewer
+     */
+    void refreshPixmapView();
+
 private:
     KFileItem m_item;
 
@@ -154,6 +159,7 @@ private:
     QDialogButtonBox* m_configureButtons;
 
     PlacesItemModel* m_placesItemModel;
+    bool m_isVideo;
 };
 
 #endif // INFORMATIONPANELCONTENT_H
index 4ea2e6666aaaf8b0a703cf4033af9df3f459d860..6911f79bd16cf8e9318f035d7e5827ceff7f33a1 100644 (file)
@@ -60,7 +60,7 @@ PhononWidget::PhononWidget(QWidget *parent)
     : QWidget(parent),
     m_url(),
     m_playButton(nullptr),
-    m_stopButton(nullptr),
+    m_pauseButton(nullptr),
     m_topLayout(nullptr),
     m_media(nullptr),
     m_seekSlider(nullptr),
@@ -95,6 +95,34 @@ QUrl PhononWidget::url() const
     return m_url;
 }
 
+void PhononWidget::clearUrl()
+{
+    m_url.clear();
+}
+
+void PhononWidget::togglePlayback()
+{
+    if (m_media && m_media->state() == Phonon::State::PlayingState) {
+        m_media->pause();
+    } else {
+        play();
+    }
+}
+
+bool PhononWidget::eventFilter(QObject *object, QEvent *event)
+{
+    Q_UNUSED(object)
+    if (event->type() == QEvent::MouseButtonPress) {
+        const QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+        if (mouseEvent->button() == Qt::LeftButton) {
+            // toggle playback
+            togglePlayback();
+            return true;
+        }
+    }
+    return false;
+}
+
 void PhononWidget::setVideoSize(const QSize& size)
 {
     if (m_videoSize != size) {
@@ -124,11 +152,11 @@ void PhononWidget::showEvent(QShowEvent *event)
         controlsLayout->setSpacing(0);
 
         m_playButton = new QToolButton(this);
-        m_stopButton = new QToolButton(this);
+        m_pauseButton = new QToolButton(this);
         m_seekSlider = new Phonon::SeekSlider(this);
 
         controlsLayout->addWidget(m_playButton);
-        controlsLayout->addWidget(m_stopButton);
+        controlsLayout->addWidget(m_pauseButton);
         controlsLayout->addWidget(m_seekSlider);
 
         m_topLayout->addLayout(controlsLayout);
@@ -142,12 +170,12 @@ void PhononWidget::showEvent(QShowEvent *event)
         m_playButton->setAutoRaise(true);
         connect(m_playButton, &QToolButton::clicked, this, &PhononWidget::play);
 
-        m_stopButton->setToolTip(i18n("stop"));
-        m_stopButton->setIconSize(buttonSize);
-        m_stopButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop")));
-        m_stopButton->setAutoRaise(true);
-        m_stopButton->hide();
-        connect(m_stopButton, &QToolButton::clicked, this, &PhononWidget::stop);
+        m_pauseButton->setToolTip(i18n("pause"));
+        m_pauseButton->setIconSize(buttonSize);
+        m_pauseButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause")));
+        m_pauseButton->setAutoRaise(true);
+        m_pauseButton->hide();
+        connect(m_pauseButton, &QToolButton::clicked, this, &PhononWidget::togglePlayback);
 
         m_seekSlider->setIconVisible(false);
 
@@ -172,11 +200,11 @@ void PhononWidget::stateChanged(Phonon::State newstate)
     switch (newstate) {
     case Phonon::PlayingState:
     case Phonon::BufferingState:
-        m_stopButton->show();
         m_playButton->hide();
+        m_pauseButton->show();
         break;
     default:
-        m_stopButton->hide();
+        m_pauseButton->hide();
         m_playButton->show();
         break;
     }
@@ -196,6 +224,7 @@ void PhononWidget::play()
 
     if (!m_videoPlayer) {
         m_videoPlayer = new EmbeddedVideoPlayer(this);
+        m_videoPlayer->setCursor(Qt::PointingHandCursor);
         m_videoPlayer->installEventFilter(this);
         m_topLayout->insertWidget(0, m_videoPlayer);
         Phonon::createPath(m_media, m_videoPlayer);
@@ -227,6 +256,11 @@ void PhononWidget::finished()
     }
 }
 
+Phonon::State PhononWidget::state() const
+{
+    return m_media == nullptr ? Phonon::State::StoppedState : m_media->state();
+}
+
 void PhononWidget::stop()
 {
     if (m_media) {
index b9e7d4f05ac4f87c0fe823d396c1418973b5b4c8..961443d2efa31775951259c557bef7034f71c596 100644 (file)
@@ -53,11 +53,14 @@ class PhononWidget : public QWidget
 
         void setUrl(const QUrl &url, MediaKind kind);
         QUrl url() const;
+        void clearUrl();
 
         void setVideoSize(const QSize& size);
         QSize videoSize() const;
+        Phonon::State state() const;
 
         void setAutoPlay(bool autoPlay);
+        bool eventFilter(QObject *object, QEvent *event) override;
 
     signals:
         /**
@@ -86,11 +89,13 @@ class PhononWidget : public QWidget
         void applyVideoSize();
 
     private:
+        void togglePlayback();
+
         QUrl m_url;
         QSize m_videoSize;
 
         QToolButton *m_playButton;
-        QToolButton *m_stopButton;
+        QToolButton *m_pauseButton;
 
         QVBoxLayout *m_topLayout;
         Phonon::MediaObject *m_media;
index 52d2a77df7a31dd08b8a26c76f49080e88789388..86974d200e4d23190222367c07b86d226037e813 100644 (file)
@@ -82,16 +82,14 @@ void TerminalPanel::terminalExited()
 bool TerminalPanel::isHiddenInVisibleWindow() const
 {
     return parentWidget()
-        && parentWidget()->isHidden()
-        && m_terminal
-        && !hasProgramRunning();
+        && parentWidget()->isHidden();
 }
 
 void TerminalPanel::dockVisibilityChanged()
 {
     // Only react when the DockWidget itself (not some parent) is hidden. This way we don't
     // respond when e.g. Dolphin is minimized.
-    if (isHiddenInVisibleWindow()) {
+    if (isHiddenInVisibleWindow() && m_terminal && !hasProgramRunning()) {
         // Make sure that the following "cd /" command will not affect the view.
         disconnect(m_konsolePart, SIGNAL(currentDirectoryChanged(QString)),
                    this, SLOT(slotKonsolePartCurrentDirectoryChanged(QString)));
index c7a909ecaafcb0cae16323dff12976dcd40edf77..df7ea21135f62b55e6d224ab3d0ad9bd5f610d36 100644 (file)
@@ -50,7 +50,7 @@ BehaviorSettingsPage::BehaviorSettingsPage(const QUrl& url, QWidget* parent) :
     // View properties
     m_globalViewProps = new QRadioButton(i18nc("@option:radio", "Use common properties for all folders"));
     m_localViewProps = new QRadioButton(i18nc("@option:radio", "Remember properties for each folder"));
-    m_localViewProps->setToolTip(i18nc("@info", "Dolphin will create an hidden .directory file in each folder you change view properties for."));
+    m_localViewProps->setToolTip(i18nc("@info", "Dolphin will create a hidden .directory file in each folder you change view properties for."));
 
     QButtonGroup* viewGroup = new QButtonGroup(this);
     viewGroup->addButton(m_globalViewProps);
index 037874539d76d3b2f53be877765fd582ddedc752..1144a50b88cfa8ab2c9a9a99237f419e6d2b1966 100644 (file)
@@ -24,6 +24,7 @@
 #include <QDir>
 #include <QDirIterator>
 #include <QCommandLineParser>
+#include <QMimeDatabase>
 
 #include <KLocalizedString>
 
@@ -42,41 +43,6 @@ Q_NORETURN void fail(const QString &str)
     exit(1);
 }
 
-bool evaluateShell(const QString &program, const QStringList &arguments, QString &output, QString &errorText)
-{
-    QProcess process;
-    process.start(program, arguments, QIODevice::ReadOnly);
-    if (!process.waitForStarted()) {
-        fail(i18n("Failed to run process: %1 %2", program, arguments.join(" ")));
-    }
-
-    if (!process.waitForFinished()) {
-        fail(i18n("Process did not finish in reasonable time: %1 %2", program, arguments.join(" ")));
-    }
-
-    const auto stdoutResult = QString::fromUtf8(process.readAllStandardOutput()).trimmed();
-    const auto stderrResult = QString::fromUtf8(process.readAllStandardError()).trimmed();
-
-    if (process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0) {
-        output = stdoutResult;
-        return true;
-    } else {
-        errorText = stderrResult + stdoutResult;
-        return false;
-    }
-}
-
-QString mimeType(const QString &path)
-{
-    QString result;
-    QString errorText;
-    if (evaluateShell("xdg-mime", QStringList{"query", "filetype", path}, result, errorText)) {
-        return result;
-    } else {
-        fail(i18n("Failed to run xdg-mime %1: %2", path, errorText));
-    }
-}
-
 QString getServiceMenusDir()
 {
     const QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
@@ -114,7 +80,7 @@ void runUncompress(const QString &inputPath, const QString &outputPath) {
                                           "multipart/x-zip"},
                               UncompressCommand{"unzip", QStringList{}, QStringList{"-d"}}});
 
-    const auto mime = mimeType(inputPath);
+    const auto mime = QMimeDatabase().mimeTypeForFile(inputPath).name();
 
     UncompressCommand command{};
     for (const auto &pair : mimeTypeToCommand) {
index 5b00fa36dcceefb6ca1b35f350e16512d1281f77..e6b232dcc14ed1d0f7a153f2bffa9d369b485a98 100644 (file)
@@ -128,8 +128,8 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
     m_container = new KItemListContainer(controller, this);
     m_container->installEventFilter(this);
     setFocusProxy(m_container);
-    connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, &DolphinView::hideToolTip);
-    connect(m_container->verticalScrollBar(), &QScrollBar::valueChanged, this, &DolphinView::hideToolTip);
+    connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); });
+    connect(m_container->verticalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); });
 
     controller->setSelectionBehavior(KItemListController::MultiSelection);
     connect(controller, &KItemListController::itemActivated, this, &DolphinView::slotItemActivated);
@@ -744,6 +744,7 @@ bool DolphinView::eventFilter(QObject* watched, QEvent* event)
         break;
 
     case QEvent::KeyPress:
+        hideToolTip(ToolTipManager::HideBehavior::Instantly);
         if (GeneralSettings::useTabForSwitchingSplitView()) {
             QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
             if (keyEvent->key() == Qt::Key_Tab && keyEvent->modifiers() == Qt::NoModifier) {
@@ -1414,11 +1415,11 @@ void DolphinView::updateViewState()
     }
 }
 
-void DolphinView::hideToolTip()
+void DolphinView::hideToolTip(const ToolTipManager::HideBehavior behavior)
 {
 #ifdef HAVE_BALOO
     if (GeneralSettings::showToolTips()) {
-        m_toolTipManager->hideToolTip();
+        m_toolTipManager->hideToolTip(behavior);
     }
 #endif
 }
index 7be2eed2d41ca36bb454b2d0602df0ec060d13b4..a4da92f2db317250dbe81b368781a2d78a3a6999 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "dolphintabwidget.h"
 #include "dolphin_export.h"
+#include "tooltips/tooltipmanager.h"
 
 #include <KFileItem>
 #include <KIO/Job>
@@ -697,8 +698,6 @@ private slots:
      */
     void updateViewState();
 
-    void hideToolTip();
-
     /**
      * Calculates the number of currently shown files into
      * \a fileCount and the number of folders into \a folderCount.
@@ -733,6 +732,11 @@ private:
      */
     void applyModeToView();
 
+    /**
+     * Hides tooltip displayed over element.
+     */
+    void hideToolTip(const ToolTipManager::HideBehavior behavior = ToolTipManager::HideBehavior::Later);
+
     /**
      * Helper method for DolphinView::paste() and DolphinView::pasteIntoFolder().
      * Pastes the clipboard data into the URL \a url.
index 41752e4f158e1f6c20695f635a6debc627a9b2e5..5746bb7cf76c7f6c4dfe9e5850c411104062301f 100644 (file)
@@ -163,7 +163,7 @@ void DolphinViewActionHandler::createActions()
         "</interface> option is enabled.</para>"));
     compactAction->setWhatsThis(xi18nc("@info:whatsthis Compact view mode",
         "<para>This switches to a compact view mode that lists the folders "
-        "and files in columns with the names beside the icons. <para></para>"
+        "and files in columns with the names beside the icons.</para><para>"
         "This helps to keep the overview in folders with many items.</para>"));
     detailsAction->setWhatsThis(xi18nc("@info:whatsthis Details view mode",
         "<para>This switches to a list view mode that focuses on folder "
@@ -191,7 +191,7 @@ void DolphinViewActionHandler::createActions()
     QAction* zoomOutAction = KStandardAction::zoomOut(this,
                              &DolphinViewActionHandler::zoomOut,
                              m_actionCollection);
-    zoomOutAction->setWhatsThis(i18nc("@info:whatsthis zoom in", "This reduces the icon size."));
+    zoomOutAction->setWhatsThis(i18nc("@info:whatsthis zoom out", "This reduces the icon size."));
 
     KToggleAction* showPreview = m_actionCollection->add<KToggleAction>(QStringLiteral("show_preview"));
     showPreview->setText(i18nc("@action:intoolbar", "Preview"));
@@ -280,7 +280,7 @@ void DolphinViewActionHandler::createActions()
 QActionGroup* DolphinViewActionHandler::createFileItemRolesActionGroup(const QString& groupPrefix)
 {
     const bool isSortGroup = (groupPrefix == QLatin1String("sort_by_"));
-    Q_ASSERT(isSortGroup || (!isSortGroup && groupPrefix == QLatin1String("show_")));
+    Q_ASSERT(isSortGroup || groupPrefix == QLatin1String("show_"));
 
     QActionGroup* rolesActionGroup = new QActionGroup(m_actionCollection);
     rolesActionGroup->setExclusive(isSortGroup);
index aae97458cfd6bbadfb606840366fec6b7765da7e..eaa78598732c12ba966181146535ad8e8e6939d4 100644 (file)
@@ -104,7 +104,7 @@ void ToolTipManager::showToolTip(const KFileItem& item, const QRectF& itemRect,
     Q_ASSERT(!m_metaDataRequested);
 }
 
-void ToolTipManager::hideToolTip()
+void ToolTipManager::hideToolTip(const HideBehavior behavior)
 {
     if (m_appliedWaitCursor) {
         QApplication::restoreOverrideCursor();
@@ -116,7 +116,14 @@ void ToolTipManager::hideToolTip()
     m_showToolTipTimer->stop();
     m_contentRetrievalTimer->stop();
     if (m_tooltipWidget) {
-        m_tooltipWidget->hideLater();
+        switch (behavior) {
+        case HideBehavior::Instantly:
+            m_tooltipWidget->hide();
+            break;
+        case HideBehavior::Later:
+            m_tooltipWidget->hideLater();
+            break;
+        }
     }
 }
 
index 10f88ad76e6cad0dc9a2ad96118bb925d6780bff..c09a40d31c9a84df777758aacce68cba4a72cf29 100644 (file)
@@ -42,6 +42,11 @@ class ToolTipManager : public QObject
     Q_OBJECT
 
 public:
+    enum class HideBehavior {
+        Instantly,
+        Later
+    };
+
     explicit ToolTipManager(QWidget* parent);
     ~ToolTipManager() override;
 
@@ -56,7 +61,7 @@ public:
     /**
      * Hides the currently shown tooltip.
      */
-    void hideToolTip();
+    void hideToolTip(const HideBehavior behavior = HideBehavior::Later);
 
 signals:
     /**
index eddc7225d09e86459b52c95de232789983fecea0..48ed654715ca55ccdcbaa697eebdc5d6ba49edcd 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <QCryptographicHash>
 
+#include <KFileItem>
+
 namespace {
     const int AdditionalInfoViewPropertiesVersion = 1;
     const int NameRolePropertiesVersion = 2;
@@ -70,6 +72,11 @@ ViewProperties::ViewProperties(const QUrl& url) :
         m_filePath = url.toLocalFile();
 
         bool useDestinationDir = !isPartOfHome(m_filePath);
+        if (!useDestinationDir) {
+            const KFileItem fileItem(url);
+            useDestinationDir = fileItem.isSlow();
+        }
+
         if (!useDestinationDir) {
             const QFileInfo dirInfo(m_filePath);
             const QFileInfo fileInfo(m_filePath + QDir::separator() + ViewPropertiesFileName);