]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Merge branch 'Applications/19.08'
authorElvis Angelaccio <elvis.angelaccio@kde.org>
Sun, 6 Oct 2019 09:51:34 +0000 (11:51 +0200)
committerElvis Angelaccio <elvis.angelaccio@kde.org>
Sun, 6 Oct 2019 09:51:34 +0000 (11:51 +0200)
58 files changed:
.gitignore
CMakeLists.txt
doc/index.docbook
src/dolphincontextmenu.cpp
src/dolphinmainwindow.cpp
src/dolphinmainwindow.h
src/dolphinpart.cpp
src/dolphinpart.desktop
src/dolphintabwidget.cpp
src/dolphintabwidget.h
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/kitemviews/private/kbaloorolesprovider.cpp
src/kitemviews/private/kitemlistheaderwidget.cpp
src/kitemviews/private/kitemlistkeyboardsearchmanager.cpp
src/middleclickactioneventfilter.cpp
src/org.kde.dolphin.desktop
src/panels/folders/folderspanel.cpp
src/panels/information/informationpanelcontent.cpp
src/panels/information/informationpanelcontent.h
src/panels/information/phononwidget.cpp
src/panels/information/phononwidget.h
src/panels/information/pixmapviewer.cpp
src/panels/information/pixmapviewer.h
src/panels/places/placespanel.cpp
src/panels/terminal/terminalpanel.cpp
src/search/dolphinfacetswidget.cpp
src/search/dolphinsearchbox.cpp
src/settings/applyviewpropsjob.cpp
src/settings/dolphinsettingsdialog.cpp
src/settings/general/behaviorsettingspage.cpp
src/settings/general/confirmationssettingspage.cpp
src/settings/general/confirmationssettingspage.h
src/settings/kcm/kcmdolphingeneral.desktop
src/settings/kcm/kcmdolphinnavigation.desktop
src/settings/kcm/kcmdolphinservices.desktop
src/settings/kcm/kcmdolphinviewmodes.desktop
src/settings/services/servicemenuinstaller/servicemenuinstaller.cpp
src/settings/services/servicessettingspage.cpp
src/tests/CMakeLists.txt
src/tests/dolphinmainwindowtest.cpp
src/tests/kfileitemmodeltest.cpp
src/tests/kitemsettest.cpp
src/tests/placesitemmodeltest.cpp
src/views/dolphinview.cpp
src/views/dolphinview.h
src/views/dolphinviewactionhandler.cpp
src/views/dolphinviewactionhandler.h
src/views/renamedialog.cpp
src/views/tooltips/tooltipmanager.cpp
src/views/tooltips/tooltipmanager.h
src/views/versioncontrol/fileviewversioncontrolplugin.desktop
src/views/viewproperties.cpp

index 59d534347018d8fb0ac9e9aa70cc0901741e9057..c48f92390db5edc685e822fdc67e9900d4765815 100644 (file)
@@ -3,3 +3,4 @@ doxygen.log
 CMakeLists.txt.user
 .directory
 *.kdev4
+/build*/
index ad3598fbb5f21d8adfb81e290f889fe7ea243055..90c1df10ef89ffc41d54d2679955ac9b05513a99 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 "2")
+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(QT_MIN_VERSION "5.11.0")
+set(KF5_MIN_VERSION "5.61.0")
 
 # ECM setup
 find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED)
@@ -149,12 +149,7 @@ configure_file(org.kde.dolphin.FileManager1.service.in
                ${CMAKE_CURRENT_BINARY_DIR}/org.kde.dolphin.FileManager1.service)
 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.dolphin.FileManager1.service
         DESTINATION ${DBUS_SERVICES_INSTALL_DIR})
-
-if (NOT ECM_VERSION VERSION_LESS "5.59.0")
-    install(FILES dolphin.categories  DESTINATION  ${KDE_INSTALL_LOGGINGCATEGORIESDIR})
-else()
-    install(FILES dolphin.categories  DESTINATION ${KDE_INSTALL_CONFDIR})
-endif()
+install(FILES dolphin.categories  DESTINATION  ${KDE_INSTALL_LOGGINGCATEGORIESDIR})
 
 feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
 
index f2b5c70a37183746cfc50a02dfeab25d782817d3..b8500118032ac07949cb693fd9a529cd3dfe3c8d 100644 (file)
@@ -70,8 +70,8 @@
 
 <legalnotice>&FDLNotice;</legalnotice>
 
-<date>2019-06-26</date>
-<releaseinfo>Applications 19.08</releaseinfo>
+<date>2019-09-30</date>
+<releaseinfo>Applications 19.12</releaseinfo>
 
 <abstract>
 <para>
@@ -681,7 +681,7 @@ the path starting with the current places entry.
 
 <para>
 &dolphin; allows a number of panels to be placed next to the view. These can
-be enabled in <menuchoice><guimenu>View</guimenu><guisubmenu>Panels</guisubmenu></menuchoice>.
+be enabled in <menuchoice><guimenu>View</guimenu><guisubmenu>Show Panels</guisubmenu></menuchoice>.
 By unlocking the panels and clicking and dragging a panel title, the panel can be moved 
 to a different position, even outside the window.
 </para>
@@ -1078,7 +1078,10 @@ be shown inside a folder's icon.
 <title>Confirmations Tab</title>
 <para>
 In the ask for confirmation section, you can enable warning dialogs that
-are shown before potentially harmful actions .
+are shown before potentially harmful actions.
+</para>
+<para>
+It is also possible to choose the default action <guilabel>When opening an executable file</guilabel>. There are three options, namely <guimenuitem>Always ask</guimenuitem>, <guimenuitem>Open in application</guimenuitem>, and <guimenuitem>Run script</guimenuitem>.
 </para>
 <warning><para>The confirmation settings for <guilabel>Moving files or folders to trash</guilabel> and
 <guilabel>Deleting files or folders</guilabel> affect file operations in &dolphin;, &konqueror;, 
@@ -1758,6 +1761,17 @@ Selects all unselected items and deselects all selected items in the current fol
 <listitem><para><action>Decreases the size of icons in the view.</action></para></listitem>
 </varlistentry>
 
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>0</keycap></keycombo>
+</shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom Reset</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Resets the size of icons in the view to default.</action></para></listitem>
+</varlistentry>
+
 <varlistentry>
 <term><menuchoice>
 <guimenu>View</guimenu>
@@ -1784,7 +1798,7 @@ or other criteria described in <link linkend="dolphin-view-information">Informat
 <varlistentry>
 <term><menuchoice>
 <guimenu>View</guimenu>
-<guisubmenu>Additional Information</guisubmenu>
+<guisubmenu>Show Additional Information</guisubmenu>
 </menuchoice></term>
 <listitem><para><action>Displays additional information</action> 
 described in <link linkend="dolphin-view-information">Information in the View</link>.
@@ -1794,7 +1808,7 @@ described in <link linkend="dolphin-view-information">Information in the View</l
 <varlistentry>
 <term><menuchoice>
 <guimenu>View</guimenu>
-<guimenuitem>Preview</guimenuitem>
+<guimenuitem>Show Previews</guimenuitem>
 </menuchoice></term>
 <listitem><para><action>Displays a symbolic preview of the file contents </action> in the different
 view modes.</para></listitem>
@@ -1816,7 +1830,7 @@ current folder grouped by the option selected in <guimenuitem>Sort By</guimenuit
 <keycombo action="simul">&Alt;<keycap>.</keycap></keycombo>
 </shortcut>
 <guimenu>View</guimenu>
-<guimenuitem>Hidden Files</guimenuitem>
+<guimenuitem>Show Hidden Files</guimenuitem>
 </menuchoice></term>
 <listitem><para><action>Shows all the hidden files and sub-folders within the current
 folder.</action>There is an alternate shortcut <keycombo action="simul">&Ctrl;<keycap>H</keycap></keycombo>
@@ -1857,7 +1871,7 @@ folder.</action></para></listitem>
 <varlistentry>
 <term><menuchoice>
 <guimenu>View</guimenu>
-<guisubmenu>Panels</guisubmenu>
+<guisubmenu>Show Panels</guisubmenu>
 </menuchoice></term>
 <listitem><para><action>Enables and disables</action> the different <link linkend="panels">panels</link>:
 <guimenuitem>Places</guimenuitem> (<keycap>F9</keycap>), <guimenuitem>Information</guimenuitem>
index 1dfbe054dd12a8afe251bfe44d5b72d5896540d0..783abc71fbb59b441fa5c24e7082a6a152ad19f8 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;
@@ -208,32 +207,23 @@ void DolphinContextMenu::openItemContextMenu()
             // Insert 'Open With' entries
             addOpenWithActions(fileItemActions);
 
-            // 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"));
-            }
-
-            addSeparator();
-
             // set up 'Create New' menu
-            DolphinNewFileMenu* newFileMenu = new DolphinNewFileMenu(m_mainWindow->actionCollection(), m_mainWindow);
-            const DolphinView* view = m_mainWindow->activeViewContainer()->view();
-            newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown());
-            newFileMenu->checkUpToDate();
-            newFileMenu->setPopupFiles(m_fileInfo.url());
-            newFileMenu->setEnabled(selectedItemsProps.supportsWriting());
-            connect(newFileMenu, &DolphinNewFileMenu::fileCreated, newFileMenu, &DolphinNewFileMenu::deleteLater);
-            connect(newFileMenu, &DolphinNewFileMenu::directoryCreated, newFileMenu, &DolphinNewFileMenu::deleteLater);
-
-            QMenu* menu = newFileMenu->menu();
-            menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New"));
-            menu->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
-            addMenu(menu);
-
-            addSeparator();
-        } else if (m_baseUrl.scheme().contains(QStringLiteral("search")) || m_baseUrl.scheme().contains(QStringLiteral("timeline"))) {
+             DolphinNewFileMenu* newFileMenu = new DolphinNewFileMenu(m_mainWindow->actionCollection(), m_mainWindow);
+             const DolphinView* view = m_mainWindow->activeViewContainer()->view();
+             newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown());
+             newFileMenu->checkUpToDate();
+             newFileMenu->setPopupFiles(m_fileInfo.url());
+             newFileMenu->setEnabled(selectedItemsProps.supportsWriting());
+             connect(newFileMenu, &DolphinNewFileMenu::fileCreated, newFileMenu, &DolphinNewFileMenu::deleteLater);
+             connect(newFileMenu, &DolphinNewFileMenu::directoryCreated, newFileMenu, &DolphinNewFileMenu::deleteLater);
+
+             QMenu* menu = newFileMenu->menu();
+             menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New"));
+             menu->setIcon(QIcon::fromTheme(QStringLiteral("document-new")));
+             addMenu(menu);
+
+             addSeparator();
+        } else if (m_baseUrl.scheme().contains(QLatin1String("search")) || m_baseUrl.scheme().contains(QLatin1String("timeline"))) {
             addOpenWithActions(fileItemActions);
 
             openParentAction = new QAction(QIcon::fromTheme(QStringLiteral("document-open-folder")),
@@ -254,15 +244,6 @@ void DolphinContextMenu::openItemContextMenu()
                                                    this);
             addAction(openParentInNewTabAction);
 
-            addSeparator();
-        } else if (!DolphinView::openItemAsFolderUrl(m_fileInfo).isEmpty()) {
-            // Insert 'Open With" entries
-            addOpenWithActions(fileItemActions);
-
-            // insert 'Open in new window' and 'Open in new tab' entries
-            addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_window")));
-            addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_tab")));
-
             addSeparator();
         } else {
             // Insert 'Open With" entries
@@ -292,6 +273,15 @@ void DolphinContextMenu::openItemContextMenu()
 
     insertDefaultItemActions(selectedItemsProps);
 
+    // insert 'Add to Places' entry if appropriate
+    if (m_selectedItems.count() == 1) {
+        if (m_fileInfo.isDir()) {
+            if (!placeExists(m_fileInfo.url())) {
+                addAction(m_mainWindow->actionCollection()->action(QStringLiteral("add_to_places")));
+            }
+        }
+    }
+
     addSeparator();
 
     fileItemActions.addServiceActionsTo(this);
@@ -314,14 +304,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;
@@ -333,14 +316,7 @@ void DolphinContextMenu::openItemContextMenu()
 
 void DolphinContextMenu::openViewportContextMenu()
 {
-    // setup 'Create New' menu
-    KNewFileMenu* newFileMenu = m_mainWindow->newFileMenu();
     const DolphinView* view = m_mainWindow->activeViewContainer()->view();
-    newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown());
-    newFileMenu->checkUpToDate();
-    newFileMenu->setPopupFiles(m_baseUrl);
-    addMenu(newFileMenu->menu());
-    addSeparator();
 
     // Insert 'Open With' entries
     KFileItem baseItem = view->rootItem();
@@ -359,22 +335,20 @@ void DolphinContextMenu::openViewportContextMenu()
         addOpenWithActions(fileItemActions);
     }
 
-    // Insert 'New Window' and 'New Tab' entries. Don't use "open_in_new_window" and
-    // "open_in_new_tab" here, as the current selection should get ignored.
-    addAction(m_mainWindow->actionCollection()->action(QStringLiteral("file_new")));
-    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"));
-    }
-
-    addSeparator();
+    // Set up and insert 'Create New' menu
+    KNewFileMenu* newFileMenu = m_mainWindow->newFileMenu();
+    newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown());
+    newFileMenu->checkUpToDate();
+    newFileMenu->setPopupFiles(m_baseUrl);
+    addMenu(newFileMenu->menu());
 
     QAction* pasteAction = createPasteAction();
     addAction(pasteAction);
+
+    // Insert 'Add to Places' entry if it's not already in the places panel
+    if (!placeExists(m_mainWindow->activeViewContainer()->url())) {
+        addAction(m_mainWindow->actionCollection()->action(QStringLiteral("add_to_places")));
+    }
     addSeparator();
 
     // Insert 'Sort By' and 'View Mode'
@@ -391,26 +365,14 @@ void DolphinContextMenu::openViewportContextMenu()
 
     addCustomActions();
 
+    addSeparator();
+
     QAction* propertiesAction = m_mainWindow->actionCollection()->action(QStringLiteral("properties"));
     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);
-        }
-    }
+    exec(m_pos);
 }
 
 void DolphinContextMenu::insertDefaultItemActions(const KFileItemListProperties& properties)
index c9ed9c5cd5045b2d4f58bd8f7e171159d62f03da..ce2013798ddca711f321658ec1f7ab035cd2aafd 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"
@@ -64,6 +65,7 @@
 #include <KStartupInfo>
 #include <KToggleAction>
 #include <KToolBar>
+#include <KToolBarPopupAction>
 #include <KToolInvocation>
 #include <KUrlComboBox>
 #include <KUrlNavigator>
@@ -89,10 +91,12 @@ namespace {
     // Used for GeneralSettings::version() to determine whether
     // an updated version of Dolphin is running.
     const int CurrentDolphinVersion = 200;
+    // The maximum number of entries in the back/forward popup menu
+    const int MaxNumberOfNavigationentries = 12;
 }
 
 DolphinMainWindow::DolphinMainWindow() :
-    KXmlGuiWindow(nullptr, Qt::WindowContextHelpButtonHint),
+    KXmlGuiWindow(nullptr),
     m_newFileMenu(nullptr),
     m_helpMenu(nullptr),
     m_tabWidget(nullptr),
@@ -106,9 +110,14 @@ DolphinMainWindow::DolphinMainWindow() :
     m_lastHandleUrlStatJob(nullptr),
     m_terminalPanel(nullptr),
     m_placesPanel(nullptr),
-    m_tearDownFromPlacesRequested(false)
+    m_tearDownFromPlacesRequested(false),
+    m_backAction(nullptr),
+    m_forwardAction(nullptr)
 {
     Q_INIT_RESOURCE(dolphin);
+#ifndef Q_OS_WIN
+       setWindowFlags(Qt::WindowContextHelpButtonHint);
+#endif
     setComponentName(QStringLiteral("dolphin"), QGuiApplication::applicationDisplayName());
     setObjectName(QStringLiteral("Dolphin#"));
 
@@ -272,7 +281,7 @@ void DolphinMainWindow::changeUrl(const QUrl &url)
     }
 
     m_activeViewContainer->setUrl(url);
-    updateEditActions();
+    updateFileAndEditActions();
     updatePasteAction();
     updateViewActions();
     updateGoActions();
@@ -301,7 +310,7 @@ void DolphinMainWindow::slotEditableStateChanged(bool editable)
 
 void DolphinMainWindow::slotSelectionChanged(const KFileItemList& selection)
 {
-    updateEditActions();
+    updateFileAndEditActions();
 
     const int selectedUrlsCount = m_tabWidget->currentTabPage()->selectedItemsCount();
 
@@ -352,6 +361,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().isEmpty()) {
+        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);
@@ -482,7 +517,7 @@ void DolphinMainWindow::closeEvent(QCloseEvent* event)
         }
     }
 
-    if (m_terminalPanel->hasProgramRunning() && GeneralSettings::confirmClosingTerminalRunningProgram() && closedByUser) {
+    if (m_terminalPanel && m_terminalPanel->hasProgramRunning() && GeneralSettings::confirmClosingTerminalRunningProgram() && closedByUser) {
         // Ask if the user really wants to quit Dolphin with a program that is still running in the Terminal panel
         // Open a confirmation dialog with 3 buttons:
         // QDialogButtonBox::Yes    -> Quit
@@ -500,7 +535,7 @@ void DolphinMainWindow::closeEvent(QCloseEvent* event)
         if (!m_terminalPanel->isVisible()) {
             KGuiItem::assign(
                     buttons->button(QDialogButtonBox::No),
-                    KGuiItem(i18n("Show &Terminal Panel"), QIcon::fromTheme(QStringLiteral("utilities-terminal"))));
+                    KGuiItem(i18n("Show &Terminal Panel"), QIcon::fromTheme(QStringLiteral("dialog-scripts"))));
         }
         KGuiItem::assign(buttons->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
 
@@ -617,6 +652,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));
@@ -643,6 +684,56 @@ void DolphinMainWindow::slotToolBarActionMiddleClicked(QAction *action)
     }
 }
 
+void DolphinMainWindow::slotAboutToShowBackPopupMenu()
+{
+    KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+    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).toString(QUrl::PreferLocalFile), m_backAction->menu());
+        action->setData(i);
+        m_backAction->menu()->addAction(action);
+    }
+}
+
+void DolphinMainWindow::slotGoBack(QAction* action)
+{
+    int gotoIndex = action->data().value<int>();
+    KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+    for (int i = gotoIndex - urlNavigator->historyIndex(); i > 0; --i) {
+        goBack();
+    }
+}
+
+void DolphinMainWindow::slotBackForwardActionMiddleClicked(QAction* action)
+{
+    if (action) {
+        KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigator();
+        openNewTabAfterCurrentTab(urlNavigator->locationUrl(action->data().value<int>()));
+    }
+}
+
+void DolphinMainWindow::slotAboutToShowForwardPopupMenu()
+{
+    KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+    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).toString(QUrl::PreferLocalFile), m_forwardAction->menu());
+        action->setData(i);
+        m_forwardAction->menu()->addAction(action);
+    }
+}
+
+void DolphinMainWindow::slotGoForward(QAction* action)
+{
+    int gotoIndex = action->data().value<int>();
+    KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator();
+    for (int i = urlNavigator->historyIndex() - gotoIndex; i > 0; --i) {
+        goForward();
+    }
+}
+
 void DolphinMainWindow::selectAll()
 {
     clearStatusBar();
@@ -751,7 +842,7 @@ void DolphinMainWindow::togglePanelLockState()
 
 void DolphinMainWindow::slotTerminalPanelVisibilityChanged()
 {
-    if (m_terminalPanel->isHiddenInVisibleWindow()) {
+    if (m_terminalPanel->isHiddenInVisibleWindow() && m_activeViewContainer) {
         m_activeViewContainer->view()->setFocus();
     }
 }
@@ -961,18 +1052,15 @@ void DolphinMainWindow::updateControlMenu()
 
     KActionCollection* ac = actionCollection();
 
-    // Add "Create New" menu
     menu->addMenu(m_newFileMenu->menu());
+    addActionToMenu(ac->action(QStringLiteral("file_new")), menu);
+    addActionToMenu(ac->action(QStringLiteral("new_tab")), menu);
+    addActionToMenu(ac->action(QStringLiteral("closed_tabs")), menu);
 
     menu->addSeparator();
 
-    // Overwrite Find action to Search action
-    QAction *searchAction = ac->action(KStandardAction::name(KStandardAction::Find));
-    searchAction->setText(i18n("Search..."));
-
     // Add "Edit" actions
     bool added = addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Undo)), menu) |
-                 addActionToMenu(searchAction, menu) |
                  addActionToMenu(ac->action(KStandardAction::name(KStandardAction::SelectAll)), menu) |
                  addActionToMenu(ac->action(QStringLiteral("invert_selection")), menu);
 
@@ -983,66 +1071,40 @@ void DolphinMainWindow::updateControlMenu()
     // Add "View" actions
     if (!GeneralSettings::showZoomSlider()) {
         addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomIn)), menu);
+        addActionToMenu(ac->action(QStringLiteral("view_zoom_reset")), menu);
         addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ZoomOut)), menu);
         menu->addSeparator();
     }
 
-    added = addActionToMenu(ac->action(QStringLiteral("sort")), menu) |
-            addActionToMenu(ac->action(QStringLiteral("view_mode")), menu) |
-            addActionToMenu(ac->action(QStringLiteral("additional_info")), menu) |
-            addActionToMenu(ac->action(QStringLiteral("show_preview")), menu) |
+    added = addActionToMenu(ac->action(QStringLiteral("show_preview")), menu) |
             addActionToMenu(ac->action(QStringLiteral("show_in_groups")), menu) |
-            addActionToMenu(ac->action(QStringLiteral("show_hidden_files")), menu);
-
-    if (added) {
-        menu->addSeparator();
-    }
-
-    added = addActionToMenu(ac->action(QStringLiteral("split_view")), menu) |
-            addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Redisplay)), menu) |
+            addActionToMenu(ac->action(QStringLiteral("show_hidden_files")), menu) |
+            addActionToMenu(ac->action(QStringLiteral("additional_info")), menu) |
             addActionToMenu(ac->action(QStringLiteral("view_properties")), menu);
+
     if (added) {
         menu->addSeparator();
     }
 
-    addActionToMenu(ac->action(QStringLiteral("panels")), menu);
-    QMenu* locationBarMenu = new QMenu(i18nc("@action:inmenu", "Location Bar"), menu);
-    locationBarMenu->addAction(ac->action(QStringLiteral("editable_location")));
-    locationBarMenu->addAction(ac->action(QStringLiteral("replace_location")));
-    menu->addMenu(locationBarMenu);
+    // Add a curated assortment of items from the "Tools" menu
+    addActionToMenu(ac->action(QStringLiteral("show_filter_bar")), menu);
+    addActionToMenu(ac->action(QStringLiteral("open_terminal")), menu);
 
     menu->addSeparator();
 
-    // Add "Go" menu
-    QMenu* goMenu = new QMenu(i18nc("@action:inmenu", "Go"), menu);
-    goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Back)));
-    goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Forward)));
-    goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Up)));
-    goMenu->addAction(ac->action(KStandardAction::name(KStandardAction::Home)));
-    goMenu->addAction(ac->action(QStringLiteral("closed_tabs")));
-    KActionMenu *bookmarkMenu = new KActionMenu(i18nc("@title:menu", "&Bookmarks"), goMenu);
-    m_bookmarkHandler->fillControlMenu(bookmarkMenu->menu(), ac);
-    goMenu->addAction(bookmarkMenu);
-    menu->addMenu(goMenu);
-
-    // Add "Tool" menu
-    QMenu* toolsMenu = new QMenu(i18nc("@action:inmenu", "Tools"), menu);
-    toolsMenu->addAction(ac->action(QStringLiteral("show_filter_bar")));
-    toolsMenu->addAction(ac->action(QStringLiteral("compare_files")));
-    toolsMenu->addAction(ac->action(QStringLiteral("open_terminal")));
-    toolsMenu->addAction(ac->action(QStringLiteral("change_remote_encoding")));
-    menu->addMenu(toolsMenu);
+    // Add "Show Panels" menu
+    addActionToMenu(ac->action(QStringLiteral("panels")), menu);
 
     // Add "Settings" menu entries
     addActionToMenu(ac->action(KStandardAction::name(KStandardAction::KeyBindings)), menu);
     addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ConfigureToolbars)), menu);
     addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Preferences)), menu);
+    addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)), menu);
 
     // Add "Help" menu
-    menu->addMenu(m_helpMenu->menu());
-
-    menu->addSeparator();
-    addActionToMenu(ac->action(KStandardAction::name(KStandardAction::ShowMenubar)), menu);
+    auto helpMenu = m_helpMenu->menu();
+    helpMenu->setIcon(QIcon::fromTheme(QStringLiteral("system-help")));
+    menu->addMenu(helpMenu);
 }
 
 void DolphinMainWindow::updateToolBar()
@@ -1084,6 +1146,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 +1165,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);
@@ -1126,7 +1192,7 @@ void DolphinMainWindow::updateWindowTitle()
 
 void DolphinMainWindow::slotStorageTearDownFromPlacesRequested(const QString& mountPath)
 {
-    if (m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) {
+    if (m_terminalPanel && m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) {
         m_tearDownFromPlacesRequested = true;
         m_terminalPanel->goHome();
         // m_placesPanel->proceedWithTearDown() will be called in slotTerminalDirectoryChanged
@@ -1137,7 +1203,7 @@ void DolphinMainWindow::slotStorageTearDownFromPlacesRequested(const QString& mo
 
 void DolphinMainWindow::slotStorageTearDownExternallyRequested(const QString& mountPath)
 {
-    if (m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) {
+    if (m_terminalPanel && m_terminalPanel->currentWorkingDirectory().startsWith(mountPath)) {
         m_tearDownFromPlacesRequested = false;
         m_terminalPanel->goHome();
     }
@@ -1156,6 +1222,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 +1238,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 +1297,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."));
@@ -1287,10 +1371,22 @@ void DolphinMainWindow::setupActions()
     connect(replaceLocation, &QAction::triggered, this, &DolphinMainWindow::replaceLocation);
 
     // setup 'Go' menu
-    QAction* backAction = KStandardAction::back(this, &DolphinMainWindow::goBack, actionCollection());
-    auto backShortcuts = backAction->shortcuts();
+    {
+        QScopedPointer<QAction> backAction(KStandardAction::back(nullptr, nullptr, nullptr));
+        m_backAction = new KToolBarPopupAction(backAction->icon(), backAction->text(), actionCollection());
+        m_backAction->setObjectName(backAction->objectName());
+        m_backAction->setShortcuts(backAction->shortcuts());
+    }
+    m_backAction->setDelayed(true);
+    m_backAction->setStickyMenu(false);
+    connect(m_backAction, &QAction::triggered, this, &DolphinMainWindow::goBack);
+    connect(m_backAction->menu(), &QMenu::aboutToShow, this, &DolphinMainWindow::slotAboutToShowBackPopupMenu);
+    connect(m_backAction->menu(), &QMenu::triggered, this, &DolphinMainWindow::slotGoBack);
+    actionCollection()->addAction(m_backAction->objectName(), m_backAction);
+
+    auto backShortcuts = m_backAction->shortcuts();
     backShortcuts.append(QKeySequence(Qt::Key_Backspace));
-    actionCollection()->setDefaultShortcuts(backAction, backShortcuts);
+    actionCollection()->setDefaultShortcuts(m_backAction, backShortcuts);
 
     DolphinRecentTabsMenu* recentTabsMenu = new DolphinRecentTabsMenu(this);
     actionCollection()->addAction(QStringLiteral("closed_tabs"), recentTabsMenu);
@@ -1319,7 +1415,25 @@ void DolphinMainWindow::setupActions()
         "be undone will ask for your confirmation."));
     undoAction->setEnabled(false); // undo should be disabled by default
 
-    KStandardAction::forward(this, &DolphinMainWindow::goForward, actionCollection());
+    {
+        QScopedPointer<QAction> forwardAction(KStandardAction::forward(nullptr, nullptr, nullptr));
+        m_forwardAction = new KToolBarPopupAction(forwardAction->icon(), forwardAction->text(), actionCollection());
+        m_forwardAction->setObjectName(forwardAction->objectName());
+        m_forwardAction->setShortcuts(forwardAction->shortcuts());
+    }
+    m_forwardAction->setDelayed(true);
+    m_forwardAction->setStickyMenu(false);
+    connect(m_forwardAction, &QAction::triggered, this, &DolphinMainWindow::goForward);
+    connect(m_forwardAction->menu(), &QMenu::aboutToShow, this, &DolphinMainWindow::slotAboutToShowForwardPopupMenu);
+    connect(m_forwardAction->menu(), &QMenu::triggered, this, &DolphinMainWindow::slotGoForward);
+    actionCollection()->addAction(m_forwardAction->objectName(), m_forwardAction);
+    actionCollection()->setDefaultShortcuts(m_forwardAction, m_forwardAction->shortcuts());
+
+    // enable middle-click to open in a new tab
+    auto *middleClickEventFilter = new MiddleClickActionEventFilter(this);
+    connect(middleClickEventFilter, &MiddleClickActionEventFilter::actionMiddleClicked, this, &DolphinMainWindow::slotBackForwardActionMiddleClicked);
+    m_backAction->menu()->installEventFilter(middleClickEventFilter);
+    m_forwardAction->menu()->installEventFilter(middleClickEventFilter);
     KStandardAction::up(this, &DolphinMainWindow::goUp, actionCollection());
     QAction* homeAction = KStandardAction::home(this, &DolphinMainWindow::goHome, actionCollection());
     homeAction->setWhatsThis(xi18nc("@info:whatsthis", "Go to your "
@@ -1351,7 +1465,7 @@ void DolphinMainWindow::setupActions()
         openTerminal->setWhatsThis(xi18nc("@info:whatsthis",
             "<para>This opens a <emphasis>terminal</emphasis> application for the viewed location.</para>"
             "<para>To learn more about terminals use the help in the terminal application.</para>"));
-        openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal")));
+        openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("dialog-scripts")));
         actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT + Qt::Key_F4);
         connect(openTerminal, &QAction::triggered, this, &DolphinMainWindow::openTerminal);
     }
@@ -1538,7 +1652,7 @@ void DolphinMainWindow::setupDockWidgets()
                 this, &DolphinMainWindow::slotTerminalPanelVisibilityChanged);
 
         QAction* terminalAction = terminalDock->toggleViewAction();
-        createPanelAction(QIcon::fromTheme(QStringLiteral("utilities-terminal")), Qt::Key_F4, terminalAction, QStringLiteral("show_terminal_panel"));
+        createPanelAction(QIcon::fromTheme(QStringLiteral("dialog-scripts")), Qt::Key_F4, terminalAction, QStringLiteral("show_terminal_panel"));
 
         addDockWidget(Qt::BottomDockWidgetArea, terminalDock);
         connect(this, &DolphinMainWindow::urlChanged,
@@ -1603,7 +1717,7 @@ void DolphinMainWindow::setupDockWidgets()
             this, &DolphinMainWindow::slotStorageTearDownExternallyRequested);
     m_tabWidget->slotPlacesPanelVisibilityChanged(m_placesPanel->isVisible());
 
-    auto actionShowAllPlaces = new QAction(QIcon::fromTheme(QStringLiteral("hint")), i18nc("@item:inmenu", "Show Hidden Places"), this);
+    auto actionShowAllPlaces = new QAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Show Hidden Places"), this);
     actionShowAllPlaces->setCheckable(true);
     actionShowAllPlaces->setDisabled(true);
     actionShowAllPlaces->setWhatsThis(i18nc("@info:whatsthis", "This displays "
@@ -1611,13 +1725,13 @@ void DolphinMainWindow::setupDockWidgets()
         "appear semi-transparent unless you uncheck their hide property."));
 
     connect(actionShowAllPlaces, &QAction::triggered, this, [actionShowAllPlaces, this](bool checked){
-        actionShowAllPlaces->setIcon(QIcon::fromTheme(checked ? QStringLiteral("visibility") : QStringLiteral("hint")));
+        actionShowAllPlaces->setIcon(QIcon::fromTheme(checked ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
         m_placesPanel->showHiddenEntries(checked);
     });
 
     connect(m_placesPanel, &PlacesPanel::showHiddenEntriesChanged, this, [actionShowAllPlaces] (bool checked){
         actionShowAllPlaces->setChecked(checked);
-        actionShowAllPlaces->setIcon(QIcon::fromTheme(checked ? QStringLiteral("visibility") : QStringLiteral("hint")));
+        actionShowAllPlaces->setIcon(QIcon::fromTheme(checked ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
    });
 
     actionCollection()->action(QStringLiteral("show_places_panel"))
@@ -1640,8 +1754,9 @@ void DolphinMainWindow::setupDockWidgets()
         "</interface> to display it again.</para>") + panelWhatsThis);
 
     // Add actions into the "Panels" menu
-    KActionMenu* panelsMenu = new KActionMenu(i18nc("@action:inmenu View", "Panels"), this);
+    KActionMenu* panelsMenu = new KActionMenu(i18nc("@action:inmenu View", "Show Panels"), this);
     actionCollection()->addAction(QStringLiteral("panels"), panelsMenu);
+    panelsMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-sidetree")));
     panelsMenu->setDelayed(false);
     const KActionCollection* ac = actionCollection();
     panelsMenu->addAction(ac->action(QStringLiteral("show_places_panel")));
@@ -1659,15 +1774,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 +1795,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 +1855,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 +1868,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 +1930,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,
@@ -2089,10 +2219,6 @@ void DolphinMainWindow::UndoUiInterface::jobError(KIO::Job* job)
 
 bool DolphinMainWindow::isUrlOpen(const QString& url)
 {
-    if (m_tabWidget->getIndexByUrl(QUrl::fromUserInput((url))).first >= 0) {
-        return true;
-    } else {
-        return false;
-    }
+    return m_tabWidget->isUrlOpen(QUrl::fromUserInput((url)));
 }
 
index dcfd9bce2dd022414c899616d705bd230c7bdc78..3d86340d6a9ed4b11dcc4d8489a9a04953bd06f2 100644 (file)
@@ -47,6 +47,7 @@ class KFileItemList;
 class KJob;
 class KNewFileMenu;
 class KHelpMenu;
+class KToolBarPopupAction;
 class QToolButton;
 class QIcon;
 class PlacesPanel;
@@ -255,6 +256,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 +385,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.
      */
@@ -501,6 +510,36 @@ private slots:
      */
     void slotToolBarActionMiddleClicked(QAction *action);
 
+    /**
+     * Is called before the Back popup menu is shown. This slot will populate
+     * the menu with history data
+     */
+    void slotAboutToShowBackPopupMenu();
+
+    /**
+      * This slot is used by the Back Popup Menu to go back to a specific
+      * history index. The QAction::data will carry an int with the index
+      * to go to.
+      */
+    void slotGoBack(QAction* action);
+
+    /**
+     * Middle clicking Back/Forward will open the resulting folder in a new tab.
+     */
+    void slotBackForwardActionMiddleClicked(QAction *action);
+
+    /**
+     * Is called before the Forward popup menu is shown. This slot will populate
+     * the menu with history data
+     */
+    void slotAboutToShowForwardPopupMenu();
+
+    /**
+      * This slot is used by the Forward Popup Menu to go forward to a specific
+      * history index. The QAction::data will carry an int with the index
+      * to go to.
+      */
+    void slotGoForward(QAction* action);
 private:
     /**
      * Sets up the various menus and actions and connects them.
@@ -512,7 +551,7 @@ private:
      */
     void setupDockWidgets();
 
-    void updateEditActions();
+    void updateFileAndEditActions();
     void updateViewActions();
     void updateGoActions();
 
@@ -591,6 +630,9 @@ private:
     TerminalPanel* m_terminalPanel;
     PlacesPanel* m_placesPanel;
     bool m_tearDownFromPlacesRequested;
+
+    KToolBarPopupAction* m_backAction;
+    KToolBarPopupAction* m_forwardAction;
 };
 
 inline DolphinViewContainer* DolphinMainWindow::activeViewContainer() const
index a4d7fdf78abcf1806099ff6901e5366c84bcc30a..607917f9a1ca152a87381f1ee2cfbe719242fad3 100644 (file)
@@ -222,7 +222,7 @@ void DolphinPart::createActions()
 #ifndef Q_OS_WIN
     if (KAuthorized::authorize(QStringLiteral("shell_access"))) {
         m_openTerminalAction = actionCollection()->addAction(QStringLiteral("open_terminal"));
-        m_openTerminalAction->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal")));
+        m_openTerminalAction->setIcon(QIcon::fromTheme(QStringLiteral("dialog-scripts")));
         m_openTerminalAction->setText(i18nc("@action:inmenu Tools", "Open &Terminal"));
         connect(m_openTerminalAction, &QAction::triggered, this, &DolphinPart::slotOpenTerminal);
         actionCollection()->setDefaultShortcut(m_openTerminalAction, Qt::Key_F4);
index 19c072a027ac9cf1da6060bae62816503d96fd40..3d53ecbd63694010dc9c6124ff3bcce08b1a7308 100644 (file)
@@ -22,7 +22,7 @@ Name[id]=Tampilan Dolphin
 Name[it]=Vista di Dolphin
 Name[ja]=Dolphin ビュー
 Name[ko]=Dolphin 보기
-Name[lt]=Dolphin žiūryklė
+Name[lt]=Dolphin rodinys
 Name[ml]=ഡോള്‍ഫിന്‍ അവതരണരീതി
 Name[nb]=Dolphin visning
 Name[nl]=Dolphin-weergave
@@ -82,7 +82,7 @@ Name[id]=Ikon
 Name[it]=Icone
 Name[ja]=アイコン
 Name[ko]=아이콘
-Name[lt]=Ženkliukai
+Name[lt]=Piktogramos
 Name[ml]=സൂചനാചിത്രങ്ങള്‍
 Name[nb]=Ikoner
 Name[nl]=Pictogrammen
@@ -183,7 +183,7 @@ Name[id]=Perincian
 Name[it]=Dettagli
 Name[ja]=詳細
 Name[ko]=자세히
-Name[lt]=Informacija
+Name[lt]=Išsamus
 Name[ml]=വിശദമായി
 Name[nb]=Detaljer
 Name[nl]=Details
index 7928c510e2aaa4df15ab281eaf863966baa80422..ec0c783bc34a491426dadda1d5ce4656dbbf4f01 100644 (file)
@@ -130,6 +130,11 @@ void DolphinTabWidget::refreshViews()
     }
 }
 
+bool DolphinTabWidget::isUrlOpen(const QUrl &url) const
+{
+    return indexByUrl(url).first >= 0;
+}
+
 void DolphinTabWidget::openNewActivatedTab()
 {
     const DolphinViewContainer* oldActiveViewContainer = currentTabPage()->activeViewContainer();
@@ -161,6 +166,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);
@@ -170,7 +176,7 @@ void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryU
     if (tabPlacement == AfterCurrentTab) {
         newTabIndex = currentIndex() + 1;
     }
-    insertTab(newTabIndex, tabPage, QIcon::fromTheme(KIO::iconNameForUrl(primaryUrl)), tabName(tabPage));
+    insertTab(newTabIndex, tabPage, QIcon() /* loaded in tabInserted */, tabName(tabPage));
 
     if (focusWidget) {
         // The DolphinViewContainer grabbed the keyboard focus. As the tab is opened
@@ -186,11 +192,13 @@ void DolphinTabWidget::openDirectories(const QList<QUrl>& dirs, bool splitView)
     QList<QUrl>::const_iterator it = dirs.constBegin();
     while (it != dirs.constEnd()) {
         const QUrl& primaryUrl = *(it++);
-        const QPair<int, bool> viewLocation = getIndexByUrl(primaryUrl);
-        if (viewLocation.first >= 0) {
-            setCurrentIndex(viewLocation.first);
-            const auto tabPage = tabPageAt(viewLocation.first);
-            if (viewLocation.second) {
+        const QPair<int, bool> indexInfo = indexByUrl(primaryUrl);
+        const int index = indexInfo.first;
+        const bool isInPrimaryView = indexInfo.second;
+        if (index >= 0) {
+            setCurrentIndex(index);
+            const auto tabPage = tabPageAt(index);
+            if (isInPrimaryView) {
                 tabPage->primaryViewContainer()->setActive(true);
             } else {
                 tabPage->secondaryViewContainer()->setActive(true);
@@ -329,7 +337,12 @@ void DolphinTabWidget::tabUrlChanged(const QUrl& url)
     const int index = indexOf(qobject_cast<QWidget*>(sender()));
     if (index >= 0) {
         tabBar()->setTabText(index, tabName(tabPageAt(index)));
-        tabBar()->setTabIcon(index, QIcon::fromTheme(KIO::iconNameForUrl(url)));
+        if (tabBar()->isVisible()) {
+            tabBar()->setTabIcon(index, QIcon::fromTheme(KIO::iconNameForUrl(url)));
+        } else {
+            // Mark as dirty, actually load once the tab bar actually gets shown
+            tabBar()->setTabIcon(index, QIcon());
+        }
 
         // Emit the currentUrlChanged signal if the url of the current tab has been changed.
         if (index == currentIndex()) {
@@ -357,6 +370,13 @@ void DolphinTabWidget::tabInserted(int index)
     QTabWidget::tabInserted(index);
 
     if (count() > 1) {
+        // Resolve all pending tab icons
+        for (int i = 0; i < count(); ++i) {
+            if (tabBar()->tabIcon(i).isNull()) {
+                tabBar()->setTabIcon(i, QIcon::fromTheme(KIO::iconNameForUrl(tabPageAt(i)->activeViewContainer()->url())));
+            }
+        }
+
         tabBar()->show();
     }
 
@@ -387,7 +407,7 @@ QString DolphinTabWidget::tabName(DolphinTabPage* tabPage) const
     return name.replace('&', QLatin1String("&&"));
 }
 
-QPair<int, bool> DolphinTabWidget::getIndexByUrl(const QUrl& url) const
+QPair<int, bool> DolphinTabWidget::indexByUrl(const QUrl& url) const
 {
     for (int i = 0; i < count(); i++) {
         const auto tabPage = tabPageAt(i);
index 7eb001b21924e6bf9b13ef7cc439dd919be58324..4351a40a837ded13f4e41347dd611f54be93d81f 100644 (file)
@@ -79,14 +79,10 @@ public:
     void refreshViews();
 
     /**
-     * @param url The URL that we would like
-     * @return a QPair with first containing the index of the tab with the
-     * desired URL or -1 if not found. Second says true if URL is in primary
-     * view container, false otherwise. False means the URL is in the secondary
-     * view container, unless first == -1. In that case the value of second
-     * is meaningless.
+     * @return Whether any of the tab pages contains @p url in their primary
+     * or secondary view.
      */
-    QPair<int, bool> getIndexByUrl(const QUrl& url) const;
+    bool isUrlOpen(const QUrl& url) const;
 
 signals:
     /**
@@ -221,6 +217,16 @@ private:
      */
     QString tabName(DolphinTabPage* tabPage) const;
 
+    /**
+     * @param url The URL that we would like
+     * @return a QPair with first containing the index of the tab with the
+     * desired URL or -1 if not found. Second says true if URL is in primary
+     * view container, false otherwise. False means the URL is in the secondary
+     * view container, unless first == -1. In that case the value of second
+     * is meaningless.
+     */
+    QPair<int, bool> indexByUrl(const QUrl& url) const;
+
 private:
     /** Caches the (negated) places panel visibility */
     bool m_placesSelectorVisible;
index b90321d0592e19d6e1beb3d818b8e4fc180336d9..dcacc56c4982877eb1f70ba54ca457579288cd69 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<kpartgui name="dolphin" version="22">
+<kpartgui name="dolphin" version="27">
     <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="invert_selection" />
         </Menu>
         <Menu name="view">
+            <Action name="view_zoom_in"/>
+            <Action name="view_zoom_reset"/>
+            <Action name="view_zoom_out"/>
+            <Separator/>
             <Action name="sort" />
             <Action name="view_mode" />
             <Action name="additional_info" />
@@ -34,7 +40,7 @@
             <Action name="stop" />
             <Separator/>
             <Action name="panels" />
-            <Menu name="location_bar">
+            <Menu name="location_bar" icon="edit-select-text">
                 <text context="@title:menu">Location Bar</text>
                 <Action name="editable_location" />
                 <Action name="replace_location" />
         <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="compact"/>
         <Action priority="0" name="details"/>
         <Action priority="0" name="view_zoom_in"/>
+        <Action priority="0" name="view_zoom_reset"/>
         <Action priority="0" name="view_zoom_out"/>
         <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 536ab0fa80b4af0614e9cb9296cc9d2cab8b0595..41706288cdaede3a42aba4c591693200c882e640 100644 (file)
@@ -414,6 +414,8 @@ void DolphinViewContainer::setSearchModeEnabled(bool enabled)
     }
 
     m_searchModeEnabled = enabled;
+
+    emit searchModeEnabledChanged(enabled);
 }
 
 bool DolphinViewContainer::isSearchModeEnabled() const
@@ -456,7 +458,7 @@ QString DolphinViewContainer::caption() const
     }
 
     KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel();
-    const auto& matchedPlaces = placesModel->match(placesModel->index(0,0), KFilePlacesModel::UrlRole, url(), 1, Qt::MatchExactly);
+    const auto& matchedPlaces = placesModel->match(placesModel->index(0,0), KFilePlacesModel::UrlRole, QUrl(url().adjusted(QUrl::StripTrailingSlash).toString(QUrl::FullyEncoded).append("/?")), 1, Qt::MatchRegExp);
 
     if (!matchedPlaces.isEmpty()) {
         return placesModel->text(matchedPlaces.first());
@@ -699,7 +701,7 @@ void DolphinViewContainer::slotUrlNavigatorLocationChanged(const QUrl& url)
                 app = browser;
                 if (app.startsWith('!')) {
                     // a literal command has been configured, remove the '!' prefix
-                    app = app.mid(1);
+                    app.remove(0, 1);
                 }
             }
         } else {
@@ -787,7 +789,7 @@ void DolphinViewContainer::showErrorMessage(const QString& msg)
 
 bool DolphinViewContainer::isSearchUrl(const QUrl& url) const
 {
-    return url.scheme().contains(QStringLiteral("search"));
+    return url.scheme().contains(QLatin1String("search"));
 }
 
 void DolphinViewContainer::saveViewState()
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..48e78e9eadec06eec42fd9daea27617c09df2652 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 = QLatin1Char('-') + 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..c11aae3d2b960582964125a950d33039aed60554 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();
@@ -1606,7 +1607,7 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item,
     if (m_requestRole[DestinationRole]) {
         QString destination = item.linkDest();
         if (destination.isEmpty()) {
-            destination = QStringLiteral("-");
+            destination = QLatin1Char('-');
         }
         data.insert(sharedValue("destination"), destination);
     }
@@ -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..c963b719664ee3fd85c034dcd965de71a362e334 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);
         }
 
@@ -1463,33 +1463,16 @@ QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, const QStrin
 {
     static const QIcon fallbackIcon = QIcon::fromTheme(QStringLiteral("unknown"));
 
-    int requestedSize = size;
-    if (size <= KIconLoader::SizeSmall) {
-        requestedSize = KIconLoader::SizeSmall;
-    } else if (size <= KIconLoader::SizeSmallMedium) {
-        requestedSize = KIconLoader::SizeSmallMedium;
-    } else if (size <= KIconLoader::SizeMedium) {
-        requestedSize = KIconLoader::SizeMedium;
-    } else if (size <= KIconLoader::SizeLarge) {
-        requestedSize = KIconLoader::SizeLarge;
-    } else if (size <= KIconLoader::SizeHuge) {
-        requestedSize = KIconLoader::SizeHuge;
-    } else if (size <= KIconLoader::SizeEnormous) {
-        requestedSize = KIconLoader::SizeEnormous;
-    } else if (size <= KIconLoader::SizeEnormous * 2) {
-        requestedSize = KIconLoader::SizeEnormous * 2;
-    }
     size *= qApp->devicePixelRatio();
-    requestedSize *= qApp->devicePixelRatio();
 
-    const QString key = "KStandardItemListWidget:" % name % ":" % overlays.join(QStringLiteral(":")) % ":" % QString::number(size) % ":" % QString::number(mode);
+    const QString key = "KStandardItemListWidget:" % name % ":" % overlays.join(QLatin1Char(':')) % ":" % QString::number(size) % ":" % QString::number(mode);
     QPixmap pixmap;
 
     if (!QPixmapCache::find(key, pixmap)) {
         const QIcon icon = QIcon::fromTheme(name, fallbackIcon);
 
-        pixmap = icon.pixmap(requestedSize / qApp->devicePixelRatio(), requestedSize / qApp->devicePixelRatio(), mode);
-        if (requestedSize != size) {
+        pixmap = icon.pixmap(size / qApp->devicePixelRatio(), size / qApp->devicePixelRatio(), mode);
+        if (pixmap.width() != size || pixmap.height() != size) {
             KPixmapModifier::scale(pixmap, QSize(size, size));
         }
 
index f3671540dd89c4e6d49fbfdfe18404d978d44c4b..8a2a64b31d5fdce3044cb7f193787fb6c03e09fd 100644 (file)
@@ -155,5 +155,5 @@ QString KBalooRolesProvider::tagsFromValues(const QStringList& values) const
     QCollator coll;
     coll.setNumericMode(true);
     std::sort(alphabeticalOrderTags.begin(), alphabeticalOrderTags.end(), [&](const QString& s1, const QString& s2){ return coll.compare(s1, s2) < 0; });
-    return alphabeticalOrderTags.join(QStringLiteral(", "));
+    return alphabeticalOrderTags.join(QLatin1String(", "));
 }
index a3f3f521fa4063beb9504a5fbd06893889e72d69..93d1389aa13f5438022575786d8df5ab20a75f9f 100644 (file)
@@ -93,7 +93,6 @@ void KItemListHeaderWidget::setColumns(const QList<QByteArray>& roles)
 {
     foreach (const QByteArray& role, roles) {
         if (!m_columnWidths.contains(role)) {
-            m_columnWidths.remove(role);
             m_preferredColumnWidths.remove(role);
         }
     }
index ffa92a1cf0bd19cb578484a6076f4871333d6a06..8f18b92bf1694a838f1925709993bd2f73341284 100644 (file)
@@ -46,7 +46,7 @@ void KItemListKeyboardSearchManager::addKeys(const QString& keys)
 
     // Do not start a new search if the user pressed Space. Only add
     // it to the search string if a search is in progress already.
-    if (newSearch && keys == QLatin1String(" ")) {
+    if (newSearch && keys == QLatin1Char(' ')) {
         return;
     }
 
index e0917850a0ea36e754b4e2c8235c36f234c643e5..293e16e0caf7cc0c5d6a25076f96388a1c9763cb 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <QAction>
 #include <QEvent>
+#include <QMenu>
 #include <QMouseEvent>
 #include <QToolBar>
 
@@ -39,16 +40,32 @@ bool MiddleClickActionEventFilter::eventFilter(QObject *watched, QEvent *event)
 
         if (me->button() == Qt::MiddleButton) {
             QToolBar *toolBar = qobject_cast<QToolBar *>(watched);
-
-            QAction *action = toolBar->actionAt(me->pos());
-            if (action) {
-                if (event->type() == QEvent::MouseButtonPress) {
-                    m_lastMiddlePressedAction = action;
-                } else if (event->type() == QEvent::MouseButtonRelease) {
-                    if (m_lastMiddlePressedAction == action) {
-                        emit actionMiddleClicked(action);
+            if (toolBar) {
+                QAction *action = toolBar->actionAt(me->pos());
+                if (action) {
+                    if (event->type() == QEvent::MouseButtonPress) {
+                        m_lastMiddlePressedAction = action;
+                    } else if (event->type() == QEvent::MouseButtonRelease) {
+                        if (m_lastMiddlePressedAction == action) {
+                            emit actionMiddleClicked(action);
+                        }
+                        m_lastMiddlePressedAction = nullptr;
+                    }
+                }
+            }
+            QMenu *menu = qobject_cast<QMenu *>(watched);
+            if (menu) {
+                QAction *action = menu->actionAt(me->pos());
+                if (action) {
+                    if (event->type() == QEvent::MouseButtonPress) {
+                        m_lastMiddlePressedAction = action;
+                    } else if (event->type() == QEvent::MouseButtonRelease) {
+                        if (m_lastMiddlePressedAction == action) {
+                            emit actionMiddleClicked(action);
+                            return true;
+                        }
+                        m_lastMiddlePressedAction = nullptr;
                     }
-                    m_lastMiddlePressedAction = nullptr;
                 }
             }
         }
index e75eeab997fefa306ce3e6e66625c3bb1f0bb8f0..3e71051efecb4caccec457e00b405895bae261c0 100755 (executable)
@@ -72,7 +72,7 @@ GenericName[id]=Pengelola File
 GenericName[it]=Gestore dei file
 GenericName[ja]=ファイルマネージャ
 GenericName[ko]=파일 관리자
-GenericName[lt]=Failų tvarkyklė
+GenericName[lt]=Failų tvarkytuvė
 GenericName[ml]=ഫയല്‍ മാനേജര്‍
 GenericName[nb]=Filbehandler
 GenericName[nl]=Bestandsbeheerder
index 020c41e552a263e5b1b97a8082bf74a775b3fbfa..01f338461f0d8990651ed615612cab5d239fa589 100644 (file)
@@ -111,7 +111,7 @@ void FoldersPanel::rename(const KFileItem& item)
 
 bool FoldersPanel::urlChanged()
 {
-    if (!url().isValid() || url().scheme().contains(QStringLiteral("search"))) {
+    if (!url().isValid() || url().scheme().contains(QLatin1String("search"))) {
         // Skip results shown by a search, as possible identical
         // directory names are useless without parent-path information.
         return false;
@@ -258,7 +258,7 @@ void FoldersPanel::slotRoleEditingFinished(int index, const QByteArray& role, co
     if (role == "text") {
         const KFileItem item = m_model->fileItem(index);
         const QString newName = value.toString();
-        if (!newName.isEmpty() && newName != item.text() && newName != QLatin1String(".") && newName != QLatin1String("..")) {
+        if (!newName.isEmpty() && newName != item.text() && newName != QLatin1Char('.') && newName != QLatin1String("..")) {
             const QUrl oldUrl = item.url();
             QUrl newUrl = oldUrl.adjusted(QUrl::RemoveFilename);
             newUrl.setPath(newUrl.path() + KIO::encodeFileName(newName));
index 363ad818d3dcbc1c027cfa7d935987d41427757e..2a8682a127e9eb5818e86fa0c518bf14b7b529fb 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);
 
@@ -161,11 +169,47 @@ void InformationPanelContent::showItem(const KFileItem& item)
     if (item != m_item) {
         m_item = item;
 
+        m_preview->stopAnimatedImage();
         refreshMetaData();
     }
     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,11 +218,13 @@ void InformationPanelContent::refreshPreview()
         m_previewJob->kill();
     }
 
+    m_preview->setCursor(Qt::ArrowCursor);
+    bool usePhonon = false;
     setNameLabelText(m_item.text());
     if (InformationPanelSettings::previewsShown()) {
 
         const QUrl itemUrl = m_item.url();
-        const bool isSearchUrl = itemUrl.scheme().contains(QStringLiteral("search")) && m_item.localPath().isEmpty();
+        const bool isSearchUrl = itemUrl.scheme().contains(QLatin1String("search")) && m_item.localPath().isEmpty();
         if (isSearchUrl) {
             m_preview->show();
 
@@ -188,56 +234,54 @@ 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;
+            const bool isAnimatedImage = m_preview->isAnimatedImage(itemUrl.toLocalFile());
+            m_isVideo = !isAnimatedImage && 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 {
+                if (isAnimatedImage) {
+                    m_preview->setAnimatedImageFileName(itemUrl.toLocalFile());
+                }
                 // 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 {
+        m_preview->stopAnimatedImage();
         m_preview->hide();
         m_phononWidget->hide();
     }
@@ -265,6 +309,8 @@ void InformationPanelContent::showItems(const KFileItemList& items)
         m_previewJob->kill();
     }
 
+    m_preview->stopAnimatedImage();
+
     m_preview->setPixmap(
         QIcon::fromTheme(QStringLiteral("dialog-information")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous)
     );
@@ -319,10 +365,45 @@ void InformationPanelContent::showPreview(const KFileItem& item,
                                           const QPixmap& pixmap)
 {
     m_outdatedPreviewTimer->stop();
-    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 +424,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 311995ec2f81250e2b99f7947cb3b06fceda1b85..2601e82ae50aba1915ada813f6f4453d3adbbc4f 100644 (file)
 
 #include <KIconLoader>
 
+#include <QImageReader>
+#include <QMovie>
 #include <QPainter>
 #include <QStyle>
 
 PixmapViewer::PixmapViewer(QWidget* parent, Transition transition) :
     QWidget(parent),
+    m_animatedImage(nullptr),
     m_transition(transition),
     m_animationStep(0),
-    m_sizeHint()
+    m_sizeHint(),
+    m_hasAnimatedImage(false)
 {
     setMinimumWidth(KIconLoader::SizeEnormous);
     setMinimumHeight(KIconLoader::SizeEnormous);
@@ -52,6 +56,11 @@ void PixmapViewer::setPixmap(const QPixmap& pixmap)
         return;
     }
 
+    // Avoid flicker with static pixmap if an animated image is running
+    if (m_animatedImage && m_animatedImage->state() == QMovie::Running) {
+        return;
+    }
+
     if ((m_transition != NoTransition) && (m_animation.state() == QTimeLine::Running)) {
         m_pendingPixmaps.enqueue(pixmap);
         if (m_pendingPixmaps.count() > 5) {
@@ -65,15 +74,26 @@ void PixmapViewer::setPixmap(const QPixmap& pixmap)
     m_pixmap = pixmap;
     update();
 
-    const bool animate = (m_transition != NoTransition) &&
-                         (m_pixmap.size() != m_oldPixmap.size());
-    if (animate) {
+    const bool animateTransition = (m_transition != NoTransition) &&
+                                   (m_pixmap.size() != m_oldPixmap.size());
+    if (animateTransition) {
         m_animation.start();
+    } else if (m_hasAnimatedImage) {
+        // If there is no transition animation but an animatedImage
+        // and it is not already running, start animating now
+        if (m_animatedImage->state() != QMovie::Running) {
+            m_animatedImage->setScaledSize(m_pixmap.size());
+            m_animatedImage->start();
+        }
     }
 }
 
 void PixmapViewer::setSizeHint(const QSize& size)
 {
+    if (m_animatedImage && size != m_sizeHint) {
+        m_animatedImage->stop();
+    }
+
     m_sizeHint = size;
     updateGeometry();
 }
@@ -83,13 +103,37 @@ QSize PixmapViewer::sizeHint() const
     return m_sizeHint;
 }
 
+void PixmapViewer::setAnimatedImageFileName(const QString &fileName)
+{
+    if (!m_animatedImage) {
+        m_animatedImage = new QMovie(this);
+        connect(m_animatedImage, &QMovie::frameChanged, this, &PixmapViewer::updateAnimatedImageFrame);
+    }
+
+    if (m_animatedImage->fileName() != fileName) {
+        m_animatedImage->stop();
+        m_animatedImage->setFileName(fileName);
+    }
+
+    m_hasAnimatedImage = m_animatedImage->isValid() && (m_animatedImage->frameCount() > 1);
+}
+
+
+QString PixmapViewer::animatedImageFileName() const
+{
+    if (!m_hasAnimatedImage) {
+        return QString();
+    }
+    return m_animatedImage->fileName();
+}
+
 void PixmapViewer::paintEvent(QPaintEvent* event)
 {
     QWidget::paintEvent(event);
 
     QPainter painter(this);
 
-    if (m_transition != NoTransition) {
+    if (m_transition != NoTransition || (m_hasAnimatedImage && m_animatedImage->state() != QMovie::Running)) {
         const float value = m_animation.currentValue();
         const int scaledWidth  = static_cast<int>((m_oldPixmap.width()  * (1.0 - value)) + (m_pixmap.width()  * value));
         const int scaledHeight = static_cast<int>((m_oldPixmap.height() * (1.0 - value)) + (m_pixmap.height() * value));
@@ -118,8 +162,32 @@ void PixmapViewer::checkPendingPixmaps()
         m_pixmap = pixmap;
         update();
         m_animation.start();
+    } else if (m_hasAnimatedImage) {
+        m_animatedImage->setScaledSize(m_pixmap.size());
+        m_animatedImage->start();
     } else {
         m_oldPixmap = m_pixmap;
     }
 }
 
+void PixmapViewer::updateAnimatedImageFrame()
+{
+    Q_ASSERT (m_animatedImage);
+
+    m_pixmap = m_animatedImage->currentPixmap();
+    update();
+}
+
+void PixmapViewer::stopAnimatedImage()
+{
+    if (m_hasAnimatedImage) {
+        m_animatedImage->stop();
+        m_hasAnimatedImage = false;
+    }
+}
+
+bool PixmapViewer::isAnimatedImage(const QString &fileName)
+{
+    const QByteArray imageFormat = QImageReader::imageFormat(fileName);
+    return !imageFormat.isEmpty() && QMovie::supportedFormats().contains(imageFormat);
+}
index 46e5cf5fc7e5d3a08b574e2014e9e0bd6316ac79..37071045fb167359e734357cb82f1f9f384190eb 100644 (file)
@@ -26,6 +26,7 @@
 #include <QWidget>
 
 class QPaintEvent;
+class QMovie;
 
 /**
  * @brief Widget which shows a pixmap centered inside the boundaries.
@@ -73,20 +74,33 @@ public:
     void setSizeHint(const QSize& size);
     QSize sizeHint() const override;
 
+    void setAnimatedImageFileName(const QString& fileName);
+    QString animatedImageFileName() const;
+
+    void stopAnimatedImage();
+
+    /**
+     * Checks if \a fileName contains an animated image supported by QMovie.
+     */
+    static bool isAnimatedImage(const QString &fileName);
+
 protected:
     void paintEvent(QPaintEvent* event) override;
 
 private Q_SLOTS:
     void checkPendingPixmaps();
+    void updateAnimatedImageFrame();
 
 private:
     QPixmap m_pixmap;
     QPixmap m_oldPixmap;
+    QMovie* m_animatedImage;
     QQueue<QPixmap> m_pendingPixmaps;
     QTimeLine m_animation;
     Transition m_transition;
     int m_animationStep;
     QSize m_sizeHint;
+    bool m_hasAnimatedImage;
 };
 
 inline QPixmap PixmapViewer::pixmap() const
index a2f0e06556769d122afad8176843dffefc2d28af..8469399a7ff98bcca3cd7f7c467d22be3f525c91 100644 (file)
@@ -77,7 +77,7 @@ void PlacesPanel::proceedWithTearDown()
 
 bool PlacesPanel::urlChanged()
 {
-    if (!url().isValid() || url().scheme().contains(QStringLiteral("search"))) {
+    if (!url().isValid() || url().scheme().contains(QLatin1String("search"))) {
         // Skip results shown by a search, as possible identical
         // directory names are useless without parent-path information.
         return false;
@@ -232,7 +232,7 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos)
         removeAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18nc("@item:inmenu", "Remove"));
     }
 
-    QAction* hideAction = menu.addAction(QIcon::fromTheme(QStringLiteral("hint")), i18nc("@item:inmenu", "Hide"));
+    QAction* hideAction = menu.addAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Hide"));
     hideAction->setCheckable(true);
     hideAction->setChecked(item->isHidden());
 
@@ -293,7 +293,7 @@ void PlacesPanel::slotViewContextMenuRequested(const QPointF& pos)
     QAction* showAllAction = menu.addAction(i18nc("@item:inmenu", "Show Hidden Places"));
     showAllAction->setCheckable(true);
     showAllAction->setChecked(m_model->hiddenItemsShown());
-    showAllAction->setIcon(QIcon::fromTheme(m_model->hiddenItemsShown() ? QStringLiteral("visibility") : QStringLiteral("hint")));
+    showAllAction->setIcon(QIcon::fromTheme(m_model->hiddenItemsShown() ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
     showAllAction->setEnabled(m_model->hiddenCount());
 
     buildGroupContextMenu(&menu, m_controller->indexCloseToMousePressedPosition());
@@ -358,7 +358,7 @@ QAction *PlacesPanel::buildGroupContextMenu(QMenu *menu, int index)
     }
 
     KFilePlacesModel::GroupType groupType = m_model->groupType(index);
-    QAction *hideGroupAction = menu->addAction(QIcon::fromTheme(QStringLiteral("hint")), i18nc("@item:inmenu", "Hide Section '%1'", m_model->item(index)->group()));
+    QAction *hideGroupAction = menu->addAction(QIcon::fromTheme(QStringLiteral("view-hidden")), i18nc("@item:inmenu", "Hide Section '%1'", m_model->item(index)->group()));
     hideGroupAction->setCheckable(true);
     hideGroupAction->setChecked(m_model->isGroupHidden(groupType));
 
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 7c0e97f86ca4f4f12a7e65fa6d0f267487094fe2..e4388f2e7a9ea20044be0582a3af81d89f24b3cd 100644 (file)
@@ -150,7 +150,7 @@ QString DolphinFacetsWidget::ratingTerm() const
         terms << QStringLiteral("modified>=%1").arg(date.toString(Qt::ISODate));
     }
 
-    return terms.join(QStringLiteral(" AND "));
+    return terms.join(QLatin1String(" AND "));
 }
 
 QString DolphinFacetsWidget::facetType() const
index d846e5b6c44a7ef8487b26aa62ee6d54dc19f671..f3dd204626a77cd54f99ca34a2e41b3a19f7e0aa 100644 (file)
@@ -505,7 +505,7 @@ QUrl DolphinSearchBox::balooUrlForSearching() const
         query.setIncludeFolder(m_searchPath.toLocalFile());
     }
 
-    query.setSearchString(queryStrings.join(QStringLiteral(" ")));
+    query.setSearchString(queryStrings.join(QLatin1Char(' ')));
 
     return query.toSearchUrl(i18nc("@title UDS_DISPLAY_NAME for a KIO directory listing. %1 is the query the user entered.",
                                    "Query Results from '%1'", text));
index b274bb8fbf52013697e73e83a843be161d320777..183c85225822af51e25644620c5845f46da98a01 100644 (file)
@@ -54,7 +54,7 @@ void ApplyViewPropsJob::slotEntries(KIO::Job*, const KIO::UDSEntryList& list)
 {
     foreach (const KIO::UDSEntry& entry, list) {
         const QString name = entry.stringValue(KIO::UDSEntry::UDS_NAME);
-        if (name != QLatin1String(".") && name != QLatin1String("..") && entry.isDir()) {
+        if (name != QLatin1Char('.') && name != QLatin1String("..") && entry.isDir()) {
             ++m_progress;
 
             QUrl url(m_dir);
index f4da53c9df65095151eb2a73e06abb2724479c91..01cfd9f86a1ed2c1bbf7238bb3bd3fbf44f8828a 100644 (file)
@@ -61,35 +61,35 @@ DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent) :
     GeneralSettingsPage* generalSettingsPage = new GeneralSettingsPage(url, this);
     KPageWidgetItem* generalSettingsFrame = addPage(generalSettingsPage,
                                                     i18nc("@title:group General settings", "General"));
-    generalSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("view-preview")));
+    generalSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("system-file-manager")));
     connect(generalSettingsPage, &GeneralSettingsPage::changed, this, &DolphinSettingsDialog::enableApply);
 
     // Startup
     StartupSettingsPage* startupSettingsPage = new StartupSettingsPage(url, this);
     KPageWidgetItem* startupSettingsFrame = addPage(startupSettingsPage,
                                                     i18nc("@title:group", "Startup"));
-    startupSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("go-home")));
+    startupSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-launch-feedback")));
     connect(startupSettingsPage, &StartupSettingsPage::changed, this, &DolphinSettingsDialog::enableApply);
 
     // View Modes
     ViewSettingsPage* viewSettingsPage = new ViewSettingsPage(this);
     KPageWidgetItem* viewSettingsFrame = addPage(viewSettingsPage,
                                                  i18nc("@title:group", "View Modes"));
-    viewSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("view-choose")));
+    viewSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-icons")));
     connect(viewSettingsPage, &ViewSettingsPage::changed, this, &DolphinSettingsDialog::enableApply);
 
     // Navigation
     NavigationSettingsPage* navigationSettingsPage = new NavigationSettingsPage(this);
     KPageWidgetItem* navigationSettingsFrame = addPage(navigationSettingsPage,
                                                        i18nc("@title:group", "Navigation"));
-    navigationSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("edit-select")));
+    navigationSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-navigation")));
     connect(navigationSettingsPage, &NavigationSettingsPage::changed, this, &DolphinSettingsDialog::enableApply);
 
     // Services
     ServicesSettingsPage* servicesSettingsPage = new ServicesSettingsPage(this);
     KPageWidgetItem* servicesSettingsFrame = addPage(servicesSettingsPage,
                                                        i18nc("@title:group", "Services"));
-    servicesSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("flag")));
+    servicesSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("preferences-system-services")));
     connect(servicesSettingsPage, &ServicesSettingsPage::changed, this, &DolphinSettingsDialog::enableApply);
 
     // Trash
@@ -97,7 +97,7 @@ DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent) :
     if (trashSettingsPage) {
         KPageWidgetItem* trashSettingsFrame = addPage(trashSettingsPage,
                                                      i18nc("@title:group", "Trash"));
-        trashSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("trash-empty")));
+        trashSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("user-trash")));
         connect(trashSettingsPage, &TrashSettingsPage::changed, this, &DolphinSettingsDialog::enableApply);
     }
 
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 1d0eebdd36f1cdbdc2eeb60c7a0eeab636c887e1..dd4d60f3b10fe24526098b8544fc6179867afdb7 100644 (file)
 #include <KLocalizedString>
 
 #include <QCheckBox>
+#include <QComboBox>
 #include <QLabel>
+#include <QHBoxLayout>
 #include <QVBoxLayout>
 
 namespace {
+    enum ScriptExecution
+    {
+        AlwaysAsk = 0,
+        Open = 1,
+        Execute = 2
+    };
+
     const bool ConfirmEmptyTrash = true;
     const bool ConfirmTrash = false;
     const bool ConfirmDelete = true;
-    const bool ConfirmScriptExecution = true;
+    const int  ConfirmScriptExecution = ScriptExecution::AlwaysAsk;
 }
 
 ConfirmationsSettingsPage::ConfirmationsSettingsPage(QWidget* parent) :
@@ -58,8 +67,6 @@ ConfirmationsSettingsPage::ConfirmationsSettingsPage(QWidget* parent) :
                                               "Emptying trash"), this);
     m_confirmDelete = new QCheckBox(i18nc("@option:check Ask for confirmation when",
                                           "Deleting files or folders"), this);
-    m_confirmScriptExecution = new QCheckBox(i18nc("@option:check Ask for confirmation when",
-                                                   "Executing scripts or desktop files"), this);
 
     QLabel* confirmLabelDolphin = new QLabel(i18nc("@title:group", "Ask for confirmation in Dolphin when:"), this);
     confirmLabelDolphin->setWordWrap(true);
@@ -72,11 +79,19 @@ ConfirmationsSettingsPage::ConfirmationsSettingsPage(QWidget* parent) :
                                                        "Closing windows with a program running in the Terminal panel"), this);
 #endif
 
+    QHBoxLayout* executableScriptLayout = new QHBoxLayout();
+    QLabel* executableScriptLabel = new QLabel(i18nc("@title:group", "When opening an executable file:"), this);
+    confirmLabelKde->setWordWrap(true);
+    executableScriptLayout->addWidget(executableScriptLabel);
+
+    m_confirmScriptExecution = new QComboBox(this);
+    m_confirmScriptExecution->addItems({i18n("Always ask"), i18n("Open in application"), i18n("Run script")});
+    executableScriptLayout->addWidget(m_confirmScriptExecution);
+
     topLayout->addWidget(confirmLabelKde);
     topLayout->addWidget(m_confirmMoveToTrash);
     topLayout->addWidget(m_confirmEmptyTrash);
     topLayout->addWidget(m_confirmDelete);
-    topLayout->addWidget(m_confirmScriptExecution);
     topLayout->addSpacing(Dolphin::VERTICAL_SPACER_HEIGHT);
     topLayout->addWidget(confirmLabelDolphin);
     topLayout->addWidget(m_confirmClosingMultipleTabs);
@@ -85,6 +100,9 @@ ConfirmationsSettingsPage::ConfirmationsSettingsPage(QWidget* parent) :
     topLayout->addWidget(m_confirmClosingTerminalRunningProgram);
 #endif
 
+    topLayout->addSpacing(Dolphin::VERTICAL_SPACER_HEIGHT);
+    topLayout->addLayout(executableScriptLayout);
+
     topLayout->addStretch();
 
     loadSettings();
@@ -92,7 +110,7 @@ ConfirmationsSettingsPage::ConfirmationsSettingsPage(QWidget* parent) :
     connect(m_confirmMoveToTrash, &QCheckBox::toggled, this, &ConfirmationsSettingsPage::changed);
     connect(m_confirmEmptyTrash, &QCheckBox::toggled, this, &ConfirmationsSettingsPage::changed);
     connect(m_confirmDelete, &QCheckBox::toggled, this, &ConfirmationsSettingsPage::changed);
-    connect(m_confirmScriptExecution, &QCheckBox::toggled, this, &ConfirmationsSettingsPage::changed);
+    connect(m_confirmScriptExecution, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ConfirmationsSettingsPage::changed);
     connect(m_confirmClosingMultipleTabs, &QCheckBox::toggled, this, &ConfirmationsSettingsPage::changed);
 
 #ifdef HAVE_TERMINAL
@@ -113,10 +131,17 @@ void ConfirmationsSettingsPage::applySettings()
     confirmationGroup.writeEntry("ConfirmDelete", m_confirmDelete->isChecked());
 
     KConfigGroup scriptExecutionGroup(kioConfig, "Executable scripts");
-    if (m_confirmScriptExecution->isChecked()) {
+    const int index = m_confirmScriptExecution->currentIndex();
+    switch (index) {
+    case ScriptExecution::AlwaysAsk:
         scriptExecutionGroup.writeEntry("behaviourOnLaunch", "alwaysAsk");
-    } else {
+        break;
+    case ScriptExecution::Open:
         scriptExecutionGroup.writeEntry("behaviourOnLaunch", "dontAsk");
+        break;
+    case ScriptExecution::Execute:
+        scriptExecutionGroup.writeEntry("behaviourOnLaunch", "execute");
+        break;
     }
     kioConfig->sync();
 
@@ -140,7 +165,7 @@ void ConfirmationsSettingsPage::restoreDefaults()
     m_confirmMoveToTrash->setChecked(ConfirmTrash);
     m_confirmEmptyTrash->setChecked(ConfirmEmptyTrash);
     m_confirmDelete->setChecked(ConfirmDelete);
-    m_confirmScriptExecution->setChecked(ConfirmScriptExecution);
+    m_confirmScriptExecution->setCurrentIndex(ConfirmScriptExecution);
 }
 
 void ConfirmationsSettingsPage::loadSettings()
@@ -153,7 +178,13 @@ void ConfirmationsSettingsPage::loadSettings()
 
     const KConfigGroup scriptExecutionGroup(KSharedConfig::openConfig(QStringLiteral("kiorc")), "Executable scripts");
     const QString value = scriptExecutionGroup.readEntry("behaviourOnLaunch", "alwaysAsk");
-    m_confirmScriptExecution->setChecked(value == QLatin1String("alwaysAsk"));
+    if (value == QLatin1String("dontAsk")) {
+        m_confirmScriptExecution->setCurrentIndex(ScriptExecution::Open);
+    } else if (value == QLatin1String("execute")) {
+        m_confirmScriptExecution->setCurrentIndex(ScriptExecution::Execute);
+    } else /* if (value == QLatin1String("alwaysAsk"))*/ {
+        m_confirmScriptExecution->setCurrentIndex(ScriptExecution::AlwaysAsk);
+    }
 
     m_confirmClosingMultipleTabs->setChecked(GeneralSettings::confirmClosingMultipleTabs());
 
index 52b101b2a228216e0881dea5e7ca31000a8865ca..c15afdc382854064d4f233f8a4e4d2fe2d9f14e1 100644 (file)
@@ -23,6 +23,7 @@
 #include "settings/settingspagebase.h"
 
 class QCheckBox;
+class QComboBox;
 
 /**
  * @brief Page for the enabling or disabling confirmation dialogs.
@@ -54,7 +55,7 @@ private:
 #endif
 
     QCheckBox* m_confirmClosingMultipleTabs;
-    QCheckBox* m_confirmScriptExecution;
+    QComboBox* m_confirmScriptExecution;
 };
 
 #endif
index ac3956144efca2bd479ca19375b6ca1906ba3abe..75a5aaf0cd39af2b84baba4bbdd8a0998398e07c 100644 (file)
@@ -20,7 +20,7 @@ Name[id]=Dolphin Umum
 Name[it]=Impostazioni generali di Dolphin
 Name[ja]=Dolphin 全般
 Name[ko]=Dolphin 일반
-Name[lt]=Dolphin bendrieji
+Name[lt]=Dolphin bendrosios
 Name[ml]=പൊതു സജ്ജീകരണങ്ങള്‍
 Name[nb]=Dolphin generelt
 Name[nl]=Dolphin algemeen
@@ -65,7 +65,7 @@ Comment[id]=Layanan ini memungkinkan konfigurasi pengaturan umum Dolphin.
 Comment[it]=Questo servizio permette di configurare le impostazioni generali di Dolphin.
 Comment[ja]=Dolphin の全般的な設定を行います
 Comment[ko]=이 서비스는 일반 Dolphin 설정을 담당합니다.
-Comment[lt]=Ši tarnyba leidžia konfigūruoti Dolphin bendrąsias nuostatas.
+Comment[lt]=Ši paslauga leidžia bendrųjų Dolphin nuostatų konfigūravimą.
 Comment[ml]=പൊതുവായ ഡോള്‍ഫിന്‍ സജ്ജീകരണങ്ങള്‍ ക്രമീകരിയ്ക്കാന്‍ ഈ സേവനം അനുവദിക്കുന്നു.
 Comment[nb]=Med denne tjenesten kan du sette opp generelle innstillinger for Dolphin.
 Comment[nl]=Met deze dienst kunt u algemene Dolphin-instellingen configureren.
@@ -89,7 +89,7 @@ Comment[zh_CN]=此服务允许您配置 Dolphin 的常规设置。
 Comment[zh_TW]=此服務允許設定 Dolphin 的一般設定。
 
 [Desktop Entry]
-Icon=system-run
+Icon=system-file-manager
 Type=Service
 X-KDE-ServiceTypes=KCModule
 Exec=kcmshell5 kcmdolphingeneral
@@ -122,7 +122,7 @@ Name[id]=Umum
 Name[it]=Generale
 Name[ja]=全般
 Name[ko]=일반
-Name[lt]=Bendra
+Name[lt]=Bendrosios
 Name[ml]=പൊതുവായതു്
 Name[nb]=Generelt
 Name[nl]=Algemeen
@@ -166,7 +166,7 @@ Comment[id]=Konfigurasikan pengaturan pengelola file umum
 Comment[it]=Configura le impostazioni generali del gestore dei file
 Comment[ja]=ファイルマネージャの全般的な設定を行います
 Comment[ko]=일반 파일 관리자 설정
-Comment[lt]=Bendrųjų failų tvarkyklės nuostatų konfigūravimas
+Comment[lt]=Konfigūruoti bendras failų tvarkytuvės nuostatas
 Comment[ml]=ഫയൽ മാനേജറിന്റെ പൊതുവായ സജ്ജീകരണങ്ങള്‍ ക്രമീകരിയ്ക്കുക
 Comment[nb]=Sett opp generelle innstillinger for filbehandleren
 Comment[nl]=Algemene bestandsbeheerderinstellingen configureren
@@ -211,7 +211,7 @@ X-KDE-Keywords[id]=pengelola file
 X-KDE-Keywords[it]=gestore dei file
 X-KDE-Keywords[ja]=ファイルマネージャ
 X-KDE-Keywords[ko]=파일 관리자
-X-KDE-Keywords[lt]=Failų tvarkyklė
+X-KDE-Keywords[lt]=failų tvarkytuvė
 X-KDE-Keywords[ml]=ഫയൽ മാനേജർ 
 X-KDE-Keywords[nb]=filbehandler
 X-KDE-Keywords[nl]=bestandsbeheerder
index f6686fbc8c2eb7d109bcadcf01da1f20a88f8694..24bf0dff53197a096d34a451e6273141b6322b49 100644 (file)
@@ -20,7 +20,7 @@ Name[id]=Navigasi Dolphin
 Name[it]=Navigazione di Dolphin
 Name[ja]=Dolphin ナビゲーション
 Name[ko]=Dolphin 탐색
-Name[lt]=Dolphin navigacija
+Name[lt]=Dolphin naršymas
 Name[ml]=ഡോള്‍ഫിന്‍ നാവിഗേഷന്‍
 Name[nb]=Navigasjon i Dolphin
 Name[nl]=Dolphin-navigatie
@@ -65,7 +65,7 @@ Comment[id]=Layanan ini memungkinkan konfigurasi navigasi Dolphin.
 Comment[it]=Questo servizio permette di configurare la navigazione con Dolphin.
 Comment[ja]=Dolphin でのナビゲーションを設定します
 Comment[ko]=이 서비스는 Dolphin 탐색을 설정합니다.
-Comment[lt]=Ši tarnyba leidžia konfigūruoti Dolphin navigaciją.
+Comment[lt]=Ši paslauga leidžia Dolphin naršymo konfigūravimą.
 Comment[ml]=ഡോള്‍ഫിന്‍ നാവിഗേഷൻ ക്രമീകരിയ്ക്കാന്‍ ഈ സേവനം അനുവദിയ്ക്കുന്നു.
 Comment[nb]=Med denne tjenesten kan du sette opp navigasjon for Dolphin.
 Comment[nl]=Met deze dienst kunt u Dolphin-navigatie configureren.
@@ -89,7 +89,7 @@ Comment[zh_CN]=此服务允许您配置 Dolphin 的导航。
 Comment[zh_TW]=此服務允許設定 Dolphin 的導覽。
 
 [Desktop Entry]
-Icon=input-mouse
+Icon=preferences-desktop-navigation
 Type=Service
 X-KDE-ServiceTypes=KCModule
 Exec=kcmshell5 kcmdolphinnavigation
@@ -121,7 +121,7 @@ Name[id]=Navigasi
 Name[it]=Navigazione
 Name[ja]=ナビゲーション
 Name[ko]=탐색
-Name[lt]=Navigacija
+Name[lt]=Naršymas
 Name[ml]=നാവിഗേഷന്‍
 Name[nb]=Navigasjon
 Name[nl]=Navigatie
@@ -166,7 +166,7 @@ Comment[id]=Konfigurasikan navigasi pengelola file
 Comment[it]=Configura la navigazione col gestore dei file
 Comment[ja]=ファイルマネージャでのナビゲーションを設定します
 Comment[ko]=파일 관리자 탐색 설정
-Comment[lt]=Konfigūruokite failų tvarkyklės navigaciją
+Comment[lt]=Konfigūruoti failų tvarkytuvės naršymą
 Comment[ml]=ഫയല്‍ മാനേജർ നാവിഗേഷൻ ക്രമീകരിയ്ക്കുക
 Comment[nb]=Sett opp navigasjon i filbehandleren
 Comment[nl]=Bestandsbeheerdernavigatie configureren
@@ -212,7 +212,7 @@ X-KDE-Keywords[id]=pengelola file
 X-KDE-Keywords[it]=gestore dei file
 X-KDE-Keywords[ja]=ファイルマネージャ
 X-KDE-Keywords[ko]=파일 관리자
-X-KDE-Keywords[lt]=Failų tvarkyklė
+X-KDE-Keywords[lt]=failų tvarkytuvė
 X-KDE-Keywords[ml]=ഫയൽ മാനേജർ 
 X-KDE-Keywords[nb]=filbehandler
 X-KDE-Keywords[nl]=bestandsbeheerder
index 07ac89c526fbac71edecf404804876ffc9de0001..e3330af5dfdd2ec3551907e5a2f2947b8a06ffad 100644 (file)
@@ -20,7 +20,7 @@ Name[id]=Layanan Dolphin
 Name[it]=Servizi di Dolphin
 Name[ja]=Dolphin サービス
 Name[ko]=Dolphin 서비스
-Name[lt]=Dolphin tarnybos
+Name[lt]=Dolphin paslaugos
 Name[ml]=ഡോള്‍ഫിന്‍ സേവനങ്ങള്‍
 Name[nb]=Dolphin-tjenester
 Name[nl]=Dolphin-services
@@ -44,7 +44,7 @@ Name[zh_CN]=Dolphin 服务
 Name[zh_TW]=Dolphin 服務
 
 [Desktop Entry]
-Icon=services
+Icon=preferences-system-services
 Type=Service
 X-KDE-ServiceTypes=KCModule
 Exec=kcmshell5 kcmdolphinservices
@@ -120,7 +120,7 @@ Comment[id]=Konfigurasikan layanan pengelola file
 Comment[it]=Configura i servizi del gestore dei file
 Comment[ja]=ファイルマネージャのサービスを設定します
 Comment[ko]=파일 관리자 서비스 설정
-Comment[lt]=Konfigūruokite failų tvarkyklės tarnybas
+Comment[lt]=Konfigūruoti failų tvarkytuvės paslaugas
 Comment[ml]=ഫയല്‍ മാനേജർ സേവനങ്ങള്‍ ക്രമീകരിയ്ക്കുക
 Comment[nb]=Sett opp tjenester i filbehandleren
 Comment[nl]=Bestandsbeheerderservices configureren
@@ -165,7 +165,7 @@ X-KDE-Keywords[id]=pengelola file
 X-KDE-Keywords[it]=gestore dei file
 X-KDE-Keywords[ja]=ファイルマネージャ
 X-KDE-Keywords[ko]=파일 관리자
-X-KDE-Keywords[lt]=Failų tvarkyklė
+X-KDE-Keywords[lt]=failų tvarkytuvė
 X-KDE-Keywords[ml]=ഫയൽ മാനേജർ 
 X-KDE-Keywords[nb]=filbehandler
 X-KDE-Keywords[nl]=bestandsbeheerder
index c50fa3800ab879bf4470591abea1f4d7aa795fc9..f093f49a14eae866056a52c8e49e2d8df32bfb19 100644 (file)
@@ -20,7 +20,7 @@ Name[id]=Mode Tampilan Dolphin
 Name[it]=Viste di Dolphin
 Name[ja]=Dolphin 表示モード
 Name[ko]=Dolphin 보기 모드
-Name[lt]=Dolphin rodymo būdai
+Name[lt]=Dolphin rodinio veiksenos
 Name[ml]=ഡോള്‍ഫിന്‍ അവതരണദശകള്‍
 Name[nb]=Dolphin visningsmåter
 Name[nl]=Dolphin-weergavemodussen
@@ -65,7 +65,7 @@ Comment[id]=Layanan ini memungkinkan konfigurasi mode tampilan Dolphin.
 Comment[it]=Questo servizio permette di configurare le viste di Dolphin.
 Comment[ja]=Dolphin の表示モードを設定します
 Comment[ko]=이 서비스는 Dolphin 보기 모드를 설정합니다.
-Comment[lt]=Ši tarnyba leidžia konfigūruoti Dolphin rodymo būdus.
+Comment[lt]=Ši paslauga leidžia Dolphin rodinio veiksenų konfigūravimą.
 Comment[ml]=ഡോള്‍ഫിന്‍ അവതരണദശകള്‍ ക്രമീകരിയ്ക്കാന്‍ ഈ സേവനം അനുവദിയ്ക്കുന്നു.
 Comment[nb]=Med denne tjenesten kan du sette opp Dolphins visningsmåter.
 Comment[nl]=Met deze dienst kunt u Dolphin-weergavemodussen configureren.
@@ -89,7 +89,7 @@ Comment[zh_CN]=此服务允许您配置 Dolphin 的视图模式。
 Comment[zh_TW]=此服務允許設定 Dolphin 的檢視模式。
 
 [Desktop Entry]
-Icon=view-choose
+Icon=preferences-desktop-icons
 Type=Service
 X-KDE-ServiceTypes=KCModule
 Exec=kcmshell5 kcmdolphinviewmodes
@@ -120,7 +120,7 @@ Name[id]=Mode Tampilan
 Name[it]=Viste
 Name[ja]=表示モード
 Name[ko]=보기 모드
-Name[lt]=Rodymo būdai
+Name[lt]=Rodinio veiksenos
 Name[ml]=അവതരണ ദശകള്‍
 Name[nb]=Visningsmåter
 Name[nl]=Weergavemodi
@@ -165,7 +165,7 @@ Comment[id]=Konfigurasikan mode tampilan pengelola file
 Comment[it]=Configura le viste del gestore dei file
 Comment[ja]=ファイルマネージャの表示モードを設定します
 Comment[ko]=파일 관리자 보기 모드 설정
-Comment[lt]=Failų tvarkyklės rodymo būdų konfigūravimas
+Comment[lt]=Konfigūruoti failų tvarkytuvės rodinio veiksenas
 Comment[ml]=ഫയല്‍ മാനേജറിന്റെ അവതരണ ദശകള്‍ ക്രമീകരിയ്ക്കുക
 Comment[nb]=Tilpass filbehandlerens visningsmåter
 Comment[nl]=Bestandsbeheerderweergavemodussen configureren
@@ -211,7 +211,7 @@ X-KDE-Keywords[id]=pengelola file
 X-KDE-Keywords[it]=gestore dei file
 X-KDE-Keywords[ja]=ファイルマネージャ
 X-KDE-Keywords[ko]=파일 관리자
-X-KDE-Keywords[lt]=Failų tvarkyklė
+X-KDE-Keywords[lt]=failų tvarkytuvė
 X-KDE-Keywords[ml]=ഫയൽ മാനേജർ 
 X-KDE-Keywords[nb]=filbehandler
 X-KDE-Keywords[nl]=bestandsbeheerder
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 ff00ca1774d33a8fc3b4e489285882bfb5f5557d..83672b556d5302e4c68b923205fe731e19e05c99 100644 (file)
@@ -222,7 +222,7 @@ void ServicesSettingsPage::loadServices()
 
     // Load JSON-based plugins that implement the KFileItemActionPlugin interface
     const auto jsonPlugins = KPluginLoader::findPlugins(QStringLiteral("kf5/kfileitemaction"), [](const KPluginMetaData& metaData) {
-        return metaData.serviceTypes().contains(QStringLiteral("KFileItemAction/Plugin"));
+        return metaData.serviceTypes().contains(QLatin1String("KFileItemAction/Plugin"));
     });
 
     foreach (const auto& jsonMetadata, jsonPlugins) {
index 44a413bd934655e363c1ec5c1f02c5f57e91c724..6ecac1f1e8b431e15abc4aef8e354df448a21006 100644 (file)
@@ -71,7 +71,7 @@ LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
 ecm_add_test(draganddrophelpertest.cpp LINK_LIBRARIES dolphinprivate Qt5::Test)
 
 # PlacesItemModelTest
-if (KF5_VERSION VERSION_GREATER_EQUAL "5.60.0")
+if (KF5_VERSION VERSION_GREATER_EQUAL 5.63.0)
     ecm_add_test(placesitemmodeltest.cpp
     TEST_NAME placesitemmodeltest
     LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
index 3d09699fee3b2308be4f7bdf1f2d7de188ec93a5..e57c79b02c6c98b0a291b6020a1126f4e1164149 100644 (file)
@@ -44,6 +44,9 @@ private slots:
     void testOpenInNewTabTitle();
     void testNewFileMenuEnabled_data();
     void testNewFileMenuEnabled();
+    void testWindowTitle_data();
+    void testWindowTitle();
+
 
 
 private:
@@ -250,6 +253,29 @@ void DolphinMainWindowTest::testNewFileMenuEnabled()
     QTRY_COMPARE(newFileMenu->isEnabled(), expectedEnabled);
 }
 
+void DolphinMainWindowTest::testWindowTitle_data()
+{
+    QTest::addColumn<QUrl>("activeViewUrl");
+    QTest::addColumn<QString>("expectedWindowTitle");
+
+    // TODO: this test should enforce the english locale.
+    QTest::newRow("home") << QUrl::fromLocalFile(QDir::homePath()) << QStringLiteral("Home");
+    QTest::newRow("home with trailing slash") << QUrl::fromLocalFile(QStringLiteral("%1/").arg(QDir::homePath())) << QStringLiteral("Home");
+    QTest::newRow("trash") << QUrl::fromUserInput(QStringLiteral("trash:/")) << QStringLiteral("Trash");
+}
+
+void DolphinMainWindowTest::testWindowTitle()
+{
+    QFETCH(QUrl, activeViewUrl);
+    m_mainWindow->openDirectories({ activeViewUrl }, false);
+    m_mainWindow->show();
+    QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data()));
+    QVERIFY(m_mainWindow->isVisible());
+
+    QFETCH(QString, expectedWindowTitle);
+    QCOMPARE(m_mainWindow->windowTitle(), expectedWindowTitle);
+}
+
 QTEST_MAIN(DolphinMainWindowTest)
 
 #include "dolphinmainwindowtest.moc"
index c539799707ae1b8870f5f19c15f436399b858d49..f081eba86032f57e3a6a8d7f8b9919df7445f7c9 100644 (file)
@@ -460,7 +460,7 @@ void KFileItemModelTest::testModelConsistencyWhenInsertingItems()
         }
 
         m_model->m_dirLister->updateDirectory(m_testDir->url());
-        if (itemsInsertedSpy.count() == 0) {
+        if (itemsInsertedSpy.isEmpty()) {
             QVERIFY(itemsInsertedSpy.wait());
         }
 
index 27f8413a75b273700f44ff7833f4049e752b8aa4..ca2c16b27ba2070ada88efcbbc59e6e0c698431d 100644 (file)
@@ -203,7 +203,7 @@ void KItemSetTest::testIterators()
     QVERIFY(itemSet.isValid());
     QVERIFY(itemSet.count() == itemsQVector.count());
 
-    if (itemSet.count() == 0) {
+    if (itemSet.isEmpty()) {
         QVERIFY(itemSet.isEmpty());
         QVERIFY(itemSet.begin() == itemSet.end());
         QVERIFY(itemSet.constBegin() == itemSet.constEnd());
@@ -342,7 +342,7 @@ void KItemSetTest::testFind()
     int min;
     int max;
 
-    if (itemSet.count() == 0) {
+    if (itemSet.isEmpty()) {
         // Use some arbitrary values for the upcoming tests.
         min = 0;
         max = 5;
@@ -401,7 +401,7 @@ void KItemSetTest::testChangingOneItem()
     int min;
     int max;
 
-    if (itemSet.count() == 0) {
+    if (itemSet.isEmpty()) {
         // Use some arbitrary values for the upcoming tests.
         min = 0;
         max = 5;
index cc66c5aa0de2087f24fad6c682fa0a7d9dd04d35..d066b2ec907ffda80f6a02b2cece3c461954f889 100644 (file)
@@ -28,6 +28,7 @@
 #include <KConfigGroup>
 #include <KAboutData>
 #include <KFilePlacesModel>
+#include <KProtocolInfo>
 
 #include "dolphin_generalsettings.h"
 #include "panels/places/placesitemmodel.h"
@@ -79,7 +80,7 @@ private:
     PlacesItemModel* m_model;
     QSet<int> m_tobeRemoved;
     QMap<QString, QDBusInterface *> m_interfacesMap;
-    int m_expectedModelCount = 14;
+    int m_expectedModelCount = qEnvironmentVariableIsSet("KDE_FULL_SESSION") && KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused")) ? 16 : 14;
     bool m_hasDesktopFolder = false;
     bool m_hasDocumentsFolder = false;
     bool m_hasDownloadsFolder = false;
@@ -175,8 +176,14 @@ QStringList PlacesItemModelTest::initialUrls() const
 
         urls << QStringLiteral("trash:/")
              << QStringLiteral("remote:/")
-             << QStringLiteral("/media/nfs")
-             << QStringLiteral("timeline:/today") << QStringLiteral("timeline:/yesterday")
+             << QStringLiteral("/media/nfs");
+
+        if (qEnvironmentVariableIsSet("KDE_FULL_SESSION") && KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused"))) {
+            urls << QStringLiteral("recentlyused:/files");
+            urls << QStringLiteral("recentlyused:/locations");
+        }
+
+        urls << QStringLiteral("timeline:/today") << QStringLiteral("timeline:/yesterday")
              << QStringLiteral("search:/documents") << QStringLiteral("search:/images") << QStringLiteral("search:/audio") << QStringLiteral("search:/videos")
              << QStringLiteral("/foreign")
              << QStringLiteral("/media/floppy0") << QStringLiteral("/media/XO-Y4") << QStringLiteral("/media/cdrom");
@@ -315,7 +322,11 @@ void PlacesItemModelTest::testGroups()
     QCOMPARE(groups.at(1).second.toString(), QStringLiteral("Remote"));
 
     QCOMPARE(groups.at(2).first, expectedRemoteIndex + 2);
-    QCOMPARE(groups.at(2).second.toString(), QStringLiteral("Recently Saved"));
+    QCOMPARE(groups.at(2).second.toString(), QStringLiteral("Recent"));
+
+    if (qEnvironmentVariableIsSet("KDE_FULL_SESSION") && KProtocolInfo::isKnownProtocol(QStringLiteral("recentlyused"))) {
+        expectedRemoteIndex += 2;
+    }
 
     QCOMPARE(groups.at(3).first, expectedRemoteIndex + 4);
     QCOMPARE(groups.at(3).second.toString(), QStringLiteral("Search For"));
@@ -342,7 +353,7 @@ void PlacesItemModelTest::testPlaceItem_data()
     QTest::newRow("Baloo - Documents") << QUrl("search:/documents") << false << true << QStringLiteral("Search For") << false;
 
     // baloo - timeline
-    QTest::newRow("Baloo - Today") << QUrl("timeline:/today") << false << true << QStringLiteral("Recently Saved") << false;
+    QTest::newRow("Baloo - Today") << QUrl("timeline:/today") << false << true << QStringLiteral("Recent") << false;
 
     // devices
     QTest::newRow("Devices - Floppy") << QUrl("file:///media/floppy0") << false << false << QStringLiteral("Removable Devices") << false;
index 5b00fa36dcceefb6ca1b35f350e16512d1281f77..3597a2aa4422b22b47ca90f883e5c3f2d2daa82c 100644 (file)
@@ -66,6 +66,7 @@
 #include <QPixmapCache>
 #include <QPointer>
 #include <QScrollBar>
+#include <QSize>
 #include <QTimer>
 #include <QVBoxLayout>
 
@@ -128,8 +129,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 +745,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) {
@@ -1337,6 +1339,20 @@ QUrl DolphinView::openItemAsFolderUrl(const KFileItem& item, const bool browseTh
     return QUrl();
 }
 
+void DolphinView::resetZoomLevel()
+{
+    ViewModeSettings::ViewMode mode;
+
+    switch (m_mode) {
+    case IconsView:     mode = ViewModeSettings::IconsMode;   break;
+    case CompactView:   mode = ViewModeSettings::CompactMode; break;
+    case DetailsView:   mode = ViewModeSettings::DetailsMode; break;
+    }
+    const ViewModeSettings settings(mode);
+    const QSize iconSize = QSize(settings.iconSize(), settings.iconSize());
+    setZoomLevel(ZoomLevelInfo::zoomLevelForIconSize(iconSize));
+}
+
 void DolphinView::observeCreatedItem(const QUrl& url)
 {
     if (m_active) {
@@ -1414,11 +1430,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..ba38d323479a57c54c7b8f9fc31c674d3422e5e7 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "dolphintabwidget.h"
 #include "dolphin_export.h"
+#include "tooltips/tooltipmanager.h"
 
 #include <KFileItem>
 #include <KIO/Job>
@@ -195,6 +196,11 @@ public:
     void setZoomLevel(int level);
     int zoomLevel() const;
 
+    /**
+     * Resets the view's icon size to the default value
+     */
+    void resetZoomLevel();
+
     void setSortRole(const QByteArray& role);
     QByteArray sortRole() const;
 
@@ -697,8 +703,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 +737,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 a79dacb1f8cac6bbfbd513a8c9b8b7f27eaa448d..25b7f82cb69e6b7efb3cb0e2e011544b431d1a3f 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 "
@@ -188,13 +188,21 @@ void DolphinViewActionHandler::createActions()
                             m_actionCollection);
     zoomInAction->setWhatsThis(i18nc("@info:whatsthis zoom in", "This increases the icon size."));
 
+    QAction* zoomResetAction = m_actionCollection->addAction(QStringLiteral("view_zoom_reset"));
+    zoomResetAction->setText(i18nc("@action:inmenu View", "Reset Zoom Level"));
+    zoomResetAction->setToolTip(i18n("Zoom To Default"));
+    zoomResetAction->setWhatsThis(i18nc("@info:whatsthis zoom reset", "This resets the icon size to default."));
+    zoomResetAction->setIcon(QIcon::fromTheme(QStringLiteral("zoom-original")));
+    m_actionCollection->setDefaultShortcuts(zoomResetAction, {Qt::CTRL + Qt::Key_0});
+    connect(zoomResetAction, &QAction::triggered, this, &DolphinViewActionHandler::zoomReset);
+
     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"));
+    showPreview->setText(i18nc("@action:intoolbar", "Show Previews"));
     showPreview->setToolTip(i18nc("@info", "Show preview of files and folders"));
     showPreview->setWhatsThis(xi18nc("@info:whatsthis", "When this is "
         "enabled, the icons are based on the actual file or folder "
@@ -245,7 +253,8 @@ void DolphinViewActionHandler::createActions()
     QActionGroup* visibleRolesGroup = createFileItemRolesActionGroup(QStringLiteral("show_"));
 
     KActionMenu* visibleRolesMenu = m_actionCollection->add<KActionMenu>(QStringLiteral("additional_info"));
-    visibleRolesMenu->setText(i18nc("@action:inmenu View", "Additional Information"));
+    visibleRolesMenu->setText(i18nc("@action:inmenu View", "Show Additional Information"));
+    visibleRolesMenu->setIcon(QIcon::fromTheme(QStringLiteral("documentinfo")));
     visibleRolesMenu->setDelayed(false);
 
     foreach (QAction* action, visibleRolesGroup->actions()) {
@@ -259,7 +268,7 @@ void DolphinViewActionHandler::createActions()
     connect(showInGroups, &KToggleAction::triggered, this, &DolphinViewActionHandler::toggleGroupedSorting);
 
     KToggleAction* showHiddenFiles = m_actionCollection->add<KToggleAction>(QStringLiteral("show_hidden_files"));
-    showHiddenFiles->setText(i18nc("@action:inmenu View", "Hidden Files"));
+    showHiddenFiles->setText(i18nc("@action:inmenu View", "Show Hidden Files"));
     showHiddenFiles->setToolTip(i18nc("@info", "Visibility of hidden files and folders"));
     showHiddenFiles->setWhatsThis(xi18nc("@info:whatsthis", "<para>When "
         "this is enabled <emphasis>hidden</emphasis> files and folders "
@@ -272,6 +281,7 @@ void DolphinViewActionHandler::createActions()
 
     QAction* adjustViewProps = m_actionCollection->addAction(QStringLiteral("view_properties"));
     adjustViewProps->setText(i18nc("@action:inmenu View", "Adjust View Properties..."));
+    adjustViewProps->setIcon(QIcon::fromTheme(QStringLiteral("view-choose")));
     adjustViewProps->setWhatsThis(i18nc("@info:whatsthis", "This opens a window "
         "in which all folder view properties can be adjusted."));
     connect(adjustViewProps, &QAction::triggered, this, &DolphinViewActionHandler::slotAdjustViewProperties);
@@ -280,7 +290,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);
@@ -391,7 +401,7 @@ void DolphinViewActionHandler::slotPreviewsShownChanged(bool shown)
 {
     Q_UNUSED(shown);
     // It is not enough to update the 'Show Preview' action, also
-    // the 'Zoom In' and 'Zoom Out' actions must be adapted.
+    // the 'Zoom In', 'Zoom Out' and 'Zoom Reset' actions must be adapted.
     updateViewActions();
 }
 
@@ -454,6 +464,12 @@ void DolphinViewActionHandler::zoomOut()
     updateViewActions();
 }
 
+void DolphinViewActionHandler::zoomReset()
+{
+    m_currentView->resetZoomLevel();
+    updateViewActions();
+}
+
 void DolphinViewActionHandler::toggleSortFoldersFirst()
 {
     const bool sortFirst = m_currentView->sortFoldersFirst();
@@ -535,11 +551,11 @@ void DolphinViewActionHandler::slotHiddenFilesShownChanged(bool shown)
 
     // #374508: don't overwrite custom icons.
     const QString iconName = showHiddenFilesAction->icon().name();
-    if (!iconName.isEmpty() && iconName != QLatin1String("visibility") && iconName != QLatin1String("hint")) {
+    if (!iconName.isEmpty() && iconName != QLatin1String("view-visible") && iconName != QLatin1String("view-hidden")) {
         return;
     }
 
-    showHiddenFilesAction->setIcon(QIcon::fromTheme(shown ? QStringLiteral("visibility") : QStringLiteral("hint")));
+    showHiddenFilesAction->setIcon(QIcon::fromTheme(shown ? QStringLiteral("view-visible") : QStringLiteral("view-hidden")));
 }
 
 void DolphinViewActionHandler::slotWriteStateChanged(bool isFolderWritable)
@@ -639,7 +655,6 @@ void DolphinViewActionHandler::slotSortTriggered(QAction* action)
     // actions and the sub-menu-actions. If an action gets checked, it must
     // be assured that all other actions get unchecked, except the ascending/
     // descending actions
-    QAction* sortByMenu =  m_actionCollection->action(QStringLiteral("sort"));
     for (QAction *groupAction : qAsConst(m_sortByActions)) {
         KActionMenu* actionMenu = qobject_cast<KActionMenu*>(groupAction);
         if (actionMenu) {
index 7d675b7d493960cea39aa770173be2169f535957..f931b3b9c5556efd38fcba2b034611f4d4718dd5 100644 (file)
@@ -131,6 +131,9 @@ private Q_SLOTS:
 
     /** Decreases the size of the current set view mode. */
     void zoomOut();
+    
+    /** Resets the size of the current set view mode to default. */
+    void zoomReset();
 
     /** Switches between a separate sorting and a mixed sorting of files and folders. */
     void toggleSortFoldersFirst();
index 5d329c3ce57a9545631f878ddce8dbdbe2dafc5c..96068564d16dab31659d3c96507a24ef695aed53 100644 (file)
@@ -188,7 +188,7 @@ void RenameDialog::slotAccepted()
 
 void RenameDialog::slotTextChanged(const QString& newName)
 {
-    bool enable = !newName.isEmpty() && (newName != QLatin1String("..")) && (newName != QLatin1String("."));
+    bool enable = !newName.isEmpty() && (newName != QLatin1String("..")) && (newName != QLatin1Char('.'));
     if (enable && !m_renameOneItem) {
         const int count = newName.count(QLatin1Char('#'));
         if (count == 0) {
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 72c02b73583e9c6d92522922dbd1b22ebbbefed4..a3b45fc42415d62989957d9d05d67f01e98bc092 100644 (file)
@@ -23,7 +23,7 @@ Comment[id]=Plugin Kendali Versi untuk Tampilan File
 Comment[it]=Estensione di controllo delle versioni per le viste dei file
 Comment[ja]=ファイルビューのためのバージョン管理プラグイン
 Comment[ko]=파일 보기를 위한 버전 관리 플러그인
-Comment[lt]=Versijų kontrolės papildinys failų tvarkyklėms
+Comment[lt]=Failo rodinių versijų tvarkymo papildinys
 Comment[ml]=ഫയല്‍ അവതരണദിശകൾക്കുള്ള പതിപ്പ് നിയന്ത്രണ സംയോജകം
 Comment[nb]=Versjonskontrollmodul for filvisninger
 Comment[nl]=Plugin voor versiecontrole op bestandoverzichten
index eddc7225d09e86459b52c95de232789983fecea0..e5f3a82c47172f548263655c384b43ec6689aa89 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <QCryptographicHash>
 
+#include <KFileItem>
+
 namespace {
     const int AdditionalInfoViewPropertiesVersion = 1;
     const int NameRolePropertiesVersion = 2;
@@ -57,7 +59,7 @@ ViewProperties::ViewProperties(const QUrl& url) :
     // we store the properties information in a local file.
     if (useGlobalViewProps) {
         m_filePath = destinationDir(QStringLiteral("global"));
-    } else if (url.scheme().contains(QStringLiteral("search"))) {
+    } else if (url.scheme().contains(QLatin1String("search"))) {
         m_filePath = destinationDir(QStringLiteral("search/")) + directoryHashForUrl(url);
         useDetailsViewWithPath = true;
     } else if (url.scheme() == QLatin1String("trash")) {
@@ -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);