]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Merge branch 'release/20.12'
authorNate Graham <pointedstick@zoho.com>
Mon, 25 Jan 2021 17:25:51 +0000 (10:25 -0700)
committerNate Graham <pointedstick@zoho.com>
Mon, 25 Jan 2021 17:25:51 +0000 (10:25 -0700)
81 files changed:
.gitlab-ci.yml [new file with mode: 0644]
CMakeLists.txt
doc/baloo-search-more-options.png [moved from doc/nepomuk-search-more-options.png with 100% similarity]
doc/baloo-search.png [moved from doc/nepomuk-search.png with 100% similarity]
doc/index.docbook
doc/preferences-context-menu.png [moved from doc/preferences-services.png with 100% similarity]
dolphin.categories [deleted file]
org.kde.dolphin.FileManager1.service.in [deleted file]
plasma-dolphin.service.in [new file with mode: 0644]
src/CMakeLists.txt
src/dolphinbookmarkhandler.cpp
src/dolphincontextmenu.cpp
src/dolphincontextmenu.h
src/dolphinmainwindow.cpp
src/dolphinmainwindow.h
src/dolphinnavigatorswidgetaction.cpp
src/dolphinnavigatorswidgetaction.h
src/dolphinpart.cpp
src/dolphinpart.desktop.in [moved from src/dolphinpart.desktop with 96% similarity]
src/dolphinpart.h
src/dolphinpart.rc
src/dolphintabpage.cpp
src/dolphintabpage.h
src/dolphintabwidget.cpp
src/dolphintabwidget.h
src/dolphinui.rc
src/dolphinurlnavigator.cpp
src/dolphinurlnavigator.h
src/global.cpp
src/global.h
src/kitemviews/kfileitemlistwidget.cpp
src/kitemviews/kfileitemmodelrolesupdater.cpp
src/kitemviews/kitemlistcontroller.cpp
src/kitemviews/kitemlistview.cpp
src/kitemviews/kitemlistview.h
src/kitemviews/private/kbaloorolesprovider.cpp
src/kitemviews/private/kbaloorolesprovider.h
src/kitemviews/private/kdirectorycontentscounterworker.cpp
src/org.kde.dolphin.appdata.xml
src/search/dolphinsearchbox.cpp
src/settings/contextmenu/contextmenusettingspage.cpp [moved from src/settings/services/servicessettingspage.cpp with 76% similarity]
src/settings/contextmenu/contextmenusettingspage.h [moved from src/settings/services/servicessettingspage.h with 66% similarity]
src/settings/contextmenu/servicemenu.knsrc [moved from src/settings/services/servicemenu.knsrc with 100% similarity]
src/settings/contextmenu/servicemenuinstaller/CMakeLists.txt [moved from src/settings/services/servicemenuinstaller/CMakeLists.txt with 100% similarity]
src/settings/contextmenu/servicemenuinstaller/Messages.sh [moved from src/settings/services/servicemenuinstaller/Messages.sh with 100% similarity]
src/settings/contextmenu/servicemenuinstaller/servicemenuinstaller.cpp [moved from src/settings/services/servicemenuinstaller/servicemenuinstaller.cpp with 100% similarity]
src/settings/contextmenu/test/service_menu_deinstallation_test.rb [moved from src/settings/services/test/service_menu_deinstallation_test.rb with 100% similarity]
src/settings/contextmenu/test/service_menu_installation_test.rb [moved from src/settings/services/test/service_menu_installation_test.rb with 100% similarity]
src/settings/contextmenu/test/test_helper.rb [moved from src/settings/services/test/test_helper.rb with 100% similarity]
src/settings/contextmenu/test/test_run.rb [moved from src/settings/services/test/test_run.rb with 100% similarity]
src/settings/dolphin_contextmenusettings.kcfg [new file with mode: 0644]
src/settings/dolphin_contextmenusettings.kcfgc [new file with mode: 0644]
src/settings/dolphin_detailsmodesettings.kcfg
src/settings/dolphin_generalsettings.kcfg
src/settings/dolphinsettingsdialog.cpp
src/settings/dolphinsettingsdialog.h
src/settings/general/configurepreviewplugindialog.cpp
src/settings/kcm/kcmdolphingeneral.cpp
src/settings/kcm/kcmdolphinnavigation.cpp
src/settings/kcm/kcmdolphinservices.cpp [deleted file]
src/settings/kcm/kcmdolphinservices.desktop [deleted file]
src/settings/kcm/kcmdolphinservices.h [deleted file]
src/settings/kcm/kcmdolphinviewmodes.cpp
src/settings/navigation/navigationsettingspage.cpp
src/settings/navigation/navigationsettingspage.h
src/settings/startup/startupsettingspage.cpp
src/settings/startup/startupsettingspage.h
src/settings/viewmodes/viewsettingstab.cpp
src/settings/viewmodes/viewsettingstab.h
src/settings/viewpropertiesdialog.cpp
src/settings/viewpropsprogressinfo.cpp
src/statusbar/dolphinstatusbar.cpp
src/statusbar/dolphinstatusbar.h
src/tests/CMakeLists.txt
src/views/dolphinview.cpp
src/views/dolphinview.h
src/views/dolphinviewactionhandler.cpp
src/views/versioncontrol/kversioncontrolplugin.cpp
src/views/versioncontrol/kversioncontrolplugin.h
src/views/versioncontrol/versioncontrolobserver.cpp
src/views/versioncontrol/versioncontrolobserver.h

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..5dd9a93
--- /dev/null
@@ -0,0 +1,3 @@
+include:
+  - https://invent.kde.org/sysadmin/ci-tooling/raw/master/invent/ci-before.yml
+  - https://invent.kde.org/sysadmin/ci-tooling/raw/master/invent/ci-applications-linux.yml
index 2dd959ffb463349b1baaf497c6f945ef6b33b100..cb6397f76ae5abd9da756f4cd7627277c1cd90f8 100644 (file)
@@ -1,14 +1,14 @@
 cmake_minimum_required(VERSION 3.0)
 
 # KDE Application Version, managed by release script
-set (RELEASE_SERVICE_VERSION_MAJOR "20")
-set (RELEASE_SERVICE_VERSION_MINOR "12")
-set (RELEASE_SERVICE_VERSION_MICRO "1")
+set (RELEASE_SERVICE_VERSION_MAJOR "21")
+set (RELEASE_SERVICE_VERSION_MINOR "03")
+set (RELEASE_SERVICE_VERSION_MICRO "70")
 set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
 project(Dolphin VERSION ${RELEASE_SERVICE_VERSION})
 
 set(QT_MIN_VERSION "5.14.0")
-set(KF5_MIN_VERSION "5.73.0")
+set(KF5_MIN_VERSION "5.77.0")
 
 # ECM setup
 find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED)
@@ -16,6 +16,8 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
 
 include(ECMSetupVersion)
 include(ECMGenerateHeaders)
+include(ECMGenerateDBusServiceFile)
+include(ECMConfiguredInstall)
 include(CMakePackageConfigHelpers)
 include(GenerateExportHeader)
 include(FeatureSummary)
@@ -166,11 +168,20 @@ install(FILES
     COMPONENT Devel
 )
 
-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 ${KDE_INSTALL_DBUSSERVICEDIR})
-install(FILES dolphin.categories  DESTINATION  ${KDE_INSTALL_LOGGINGCATEGORIESDIR})
+ecm_generate_dbus_service_file(
+   NAME org.freedesktop.FileManager1
+   EXECUTABLE "${KDE_INSTALL_FULL_BINDIR}/dolphin --daemon"
+   SYSTEMD_SERVICE plasma-dolphin.service
+   DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}
+   RENAME org.kde.dolphin.FileManager1.service
+)
+
+ecm_install_configured_files(INPUT plasma-dolphin.service.in DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR})
 
+ecm_qt_install_logging_categories(
+        EXPORT DOLPHIN
+        FILE dolphin.categories
+        DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
+        )
 feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
 
similarity index 100%
rename from doc/nepomuk-search.png
rename to doc/baloo-search.png
index 50fc37d91182d68c84b86765bf1540c682b27c4a..a278d76730ecadc573e45182612e34c87cda986f 100644 (file)
@@ -70,8 +70,8 @@
 
 <legalnotice>&FDLNotice;</legalnotice>
 
-<date>2020-06-10</date>
-<releaseinfo>Applications 20.08</releaseinfo>
+<date>2020-12-29</date>
+<releaseinfo>Applications 21.04</releaseinfo>
 
 <abstract>
 <para>
@@ -238,9 +238,9 @@ can be accessed or manipulated in different ways:
 
 <listitem><para>
 A file or folder can be opened by clicking it with the &LMB; (or
-double-clicking, if <guilabel>Double-click to open files and folders</guilabel>
-is enabled in the &systemsettings; in the <menuchoice><guimenu>Input Devices</guimenu>
-<guimenuitem>Mouse</guimenuitem></menuchoice> module.
+double-clicking, if <guilabel>Open by double-clicking instead</guilabel>
+is enabled in the &systemsettings; in the <menuchoice><guimenu>Workspace</guimenu>
+<guimenuitem>General Behavior</guimenuitem></menuchoice> module).
 </para></listitem>
 
 <listitem><para>
@@ -773,6 +773,33 @@ current folder, &RMB; click in the work space and click
 <menuchoice><guimenuitem>Add to Places</guimenuitem></menuchoice> in the context menu.
 </para>
 
+<note>
+    <para>
+        The corresponding menu item visibility can be toggled via the
+        <link linkend="preferences-dialog-context-menu">&dolphin; context menu settings</link>.
+    </para>
+</note>
+
+</sect2>
+
+<sect2 id="filter-files">
+<title>Filtering Files</title>
+
+<para>
+&dolphin; is capable of filtering files, &ie; showing only those items in the
+view whose name contains a given text. For example, if you wish to show
+only the <acronym>MP3</acronym> files within a folder, you could filter for <quote>.mp3</quote>.
+This would then filter out all files whose name does not contain <quote>.mp3</quote>.
+</para>
+
+<para>
+To filter files, first enable the filter bar, either by pressing <keycombo action="simul">&Ctrl;<keycap>I</keycap></keycombo>
+or via the menu: <menuchoice> <guimenu>Edit</guimenu> <guimenuitem>Filter...</guimenuitem> </menuchoice>.
+You can then enter the text to be filtered for in the filter bar. The filter bar can
+be disabled either by pressing &Esc;, or with a &LMB; click on the 
+<guiicon>Hide Filter Bar</guiicon> icon.
+</para>
+
 </sect2>
 
 <sect2 id="finding-searching-in-file">
@@ -789,7 +816,7 @@ Start to type into the find input box and the search starts immediately.
 <screeninfo>Search files and for content in files</screeninfo>
 <mediaobject>
 <imageobject>
-<imagedata fileref="nepomuk-search.png" format="PNG"/>
+<imagedata fileref="baloo-search.png" format="PNG"/>
 </imageobject>
 <textobject>
 <phrase>Search files and for content in files</phrase>
@@ -811,7 +838,7 @@ starts the search from the user's <replaceable>Home</replaceable> folder.</para>
 <screeninfo>Search with More Options</screeninfo>
 <mediaobject>
 <imageobject>
-<imagedata fileref="nepomuk-search-more-options.png" format="PNG"/>
+<imagedata fileref="baloo-search-more-options.png" format="PNG"/>
 </imageobject>
 <textobject>
 <phrase>Search with More Options</phrase>
@@ -912,26 +939,6 @@ via the Tools menu: <menuchoice> <guimenu>Tools</guimenu> <guimenuitem>Compare F
 
 </sect2>
 
-<sect2 id="filter-files">
-<title>Filtering Files</title>
-
-<para>
-&dolphin; is capable of filtering files, &ie; showing only those items in the
-view whose name contains a given text. For example, if you wish to show
-only the <acronym>MP3</acronym> files within a folder, you could filter for <quote>.mp3</quote>.
-This would then filter out all files whose name does not contain <quote>.mp3</quote>.
-</para>
-
-<para>
-To filter files, first enable the filter bar, either by pressing <keycombo action="simul">&Ctrl;<keycap>I</keycap></keycombo>
-or via the menu: <menuchoice> <guimenu>Tools</guimenu> <guimenuitem>Show Filter Bar</guimenuitem> </menuchoice>.
-You can then enter the text to be filtered for in the filter bar. The filter bar can
-be disabled either by pressing &Esc;, or with a &LMB; click on the 
-<guiicon>Hide Filter Bar</guiicon> icon.
-</para>
-
-</sect2>
-
 </sect1>
 
 </chapter>
@@ -1296,6 +1303,9 @@ are displayed in a tree view, where the sub items can be expanded by &LMB; click
 <para>
 <guilabel>Folder size displays</guilabel> allows defining the property to use then sorting folders by their size. It is possible to sort folders by <guilabel>Number of items</guilabel> or <guilabel>Size of contents</guilabel> and choose a limit to the recursive level (can be useful to constrain unneeded iterations in the deep folder structures or on the slow file systems).
 </para>
+<para>
+The <guilabel>Date style</guilabel> option can be used to configure the mode to display dates in &dolphin;. It is possible to choose between <guilabel>Relative</guilabel> (&eg;, <quote>Yesterday, 3:00pm</quote>) or <guilabel>Absolute</guilabel> (&eg;, <quote>2020-12-23 15:00</quote>).
+</para>
 </listitem>
 </itemizedlist>
 </para>
@@ -1327,8 +1337,8 @@ structure and in archives works.
 
 <listitem><para>
 The option to open items with a single or double mouse click is a system wide setting and can be
-changed in the &systemsettings; in the <menuchoice><guimenu>Input Devices</guimenu>
-<guimenuitem>Mouse</guimenuitem></menuchoice> module.</para>
+changed in the &systemsettings; in the <menuchoice><guimenu>Workspace</guimenu>
+<guimenuitem>General Behavior</guimenuitem></menuchoice> module.</para>
 </listitem>
 
 <listitem><para>
@@ -1349,8 +1359,8 @@ several levels deeper in the folder hierarchy.
 
 </sect2>
 
-<sect2 id="preferences-dialog-services">
-<title>Services</title>
+<sect2 id="preferences-dialog-context-menu">
+<title>Context Menu</title>
 
 <para>
 This group offers a selection of services that can be shown in the
@@ -1359,15 +1369,15 @@ appears when clicking a file or folder with the &RMB;.
 </para>
 
 <screenshot>
-<screeninfo>Screenshot of the Services settings in &dolphin;'s preferences dialog</screeninfo>
+<screeninfo>Screenshot of the Context Menu settings in &dolphin;'s preferences dialog</screeninfo>
 <mediaobject>
 <imageobject>
-<imagedata fileref="preferences-services.png" format="PNG"/>
+<imagedata fileref="preferences-context-menu.png" format="PNG"/>
 </imageobject>
 <textobject>
-<phrase>Services Settings.</phrase>
+<phrase>Context Menu Settings.</phrase>
 </textobject>
-<caption><para>Services Settings in &dolphin;'s Preferences Dialog.</para></caption>
+<caption><para>Context Menu Settings in &dolphin;'s Preferences Dialog.</para></caption>
 </mediaobject>
 </screenshot>
 
@@ -1385,13 +1395,15 @@ and you have additional entries in the
 context menu like commit, update, add, remove &etc;
 </para>
 <para>
-In the service list you can also choose if the <guimenuitem>Delete</guimenuitem>,
-<guimenuitem>Copy To</guimenuitem>, and <guimenuitem>Move To</guimenuitem>
+In the service list you can also choose if the <guimenuitem>Copy To</guimenuitem>,
+<guimenuitem>Move To</guimenuitem>, <guimenuitem>Add to Places</guimenuitem>,
+<guimenuitem>Sort By</guimenuitem>, <guimenuitem>View Mode</guimenuitem>,
+<guimenuitem>Open in New Tab</guimenuitem>, <guimenuitem>Open in New Window</guimenuitem>,
+<guimenuitem>Copy Location</guimenuitem>, and <guimenuitem>Duplicate Here</guimenuitem>
 commands are shown in the context menu.
 </para>
 <para>
 &dolphin; has to be restarted to activate the changes for some of these settings.
-<!--FIXME wrong for Copy To + Move To + Delete, what about the other items?-->
 </para>
 
 </sect2>
@@ -1752,6 +1764,19 @@ The name of this file has to be entered in a dialog.
 Is disabled if the current user does not have write permission on the selected item(s).</action></para></listitem>
 </varlistentry>
 
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>I</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Filter...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Enables and disables the <link linkend="filter-files">filter bar</link>.</action>
+You can also use the alternate shortcut <keycombo action="simul">&Shift;<keycap>/</keycap></keycombo>
+for this action.</para></listitem>
+</varlistentry>
+
 <varlistentry>
 <term><menuchoice>
 <shortcut>
@@ -2052,19 +2077,6 @@ be reopened.</action></para></listitem>
 <para>
 
 <variablelist>
-<varlistentry>
-<term><menuchoice>
-<shortcut>
-<keycombo action="simul">&Ctrl;<keycap>I</keycap></keycombo>
-</shortcut>
-<guimenu>Tools</guimenu>
-<guimenuitem>Show Filter Bar</guimenuitem>
-</menuchoice></term>
-<listitem><para><action>Enables and disables the <link linkend="filter-files">filter bar</link>.</action>
-You can also use the alternate shortcut <keycombo action="simul">&Shift;<keycap>/</keycap></keycombo>
-for this action.</para></listitem>
-</varlistentry>
-
 <varlistentry>
 <term><menuchoice>
 <shortcut>
diff --git a/dolphin.categories b/dolphin.categories
deleted file mode 100644 (file)
index 8faeb20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-org.kde.dolphin dolphin IDENTIFIER [DolphinDebug]
diff --git a/org.kde.dolphin.FileManager1.service.in b/org.kde.dolphin.FileManager1.service.in
deleted file mode 100644 (file)
index c1258bb..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[D-BUS Service]
-Name=org.freedesktop.FileManager1
-Exec=@CMAKE_INSTALL_PREFIX@/bin/dolphin --daemon
diff --git a/plasma-dolphin.service.in b/plasma-dolphin.service.in
new file mode 100644 (file)
index 0000000..d4cdd69
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Dolphin file manager
+PartOf=graphical-session.target
+
+[Service]
+ExecStart=@KDE_INSTALL_FULL_BINDIR@/dolphin --daemon
+BusName=org.freedesktop.FileManager1
+Slice=background.slice
index 1955ce5581275443b0d2c7bf8bec6961d79030a7..fd3e771b7ae9a9ccfbe405781f922ae7c00daca3 100644 (file)
@@ -117,7 +117,8 @@ set(dolphinprivate_LIB_SRCS
     dolphinnewfilemenu.cpp
 )
 
-ecm_qt_declare_logging_category(dolphinprivate_LIB_SRCS HEADER dolphindebug.h IDENTIFIER DolphinDebug CATEGORY_NAME org.kde.dolphin)
+ecm_qt_declare_logging_category(dolphinprivate_LIB_SRCS HEADER dolphindebug.h IDENTIFIER DolphinDebug CATEGORY_NAME org.kde.dolphin
+    DESCRIPTION "dolphin" EXPORT DOLPHIN)
 
 if(HAVE_BALOO)
     set(dolphinprivate_LIB_SRCS
@@ -134,6 +135,7 @@ kconfig_add_kcfg_files(dolphinprivate_LIB_SRCS GENERATE_MOC
     settings/dolphin_detailsmodesettings.kcfgc
     settings/dolphin_iconsmodesettings.kcfgc
     settings/dolphin_generalsettings.kcfgc
+    settings/dolphin_contextmenusettings.kcfgc
     settings/dolphin_versioncontrolsettings.kcfgc
 )
 
@@ -176,6 +178,7 @@ install(TARGETS dolphinprivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMEL
 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dolphin_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR} COMPONENT Devel)
 
 ##########################################
+configure_file(dolphinpart.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/dolphinpart.desktop @ONLY)
 
 set(dolphinpart_SRCS
    dolphinpart.cpp
@@ -186,14 +189,15 @@ set(dolphinpart_SRCS
 qt5_add_resources(dolphinpart_SRCS dolphinpart.qrc)
 
 add_library(dolphinpart MODULE ${dolphinpart_SRCS})
+kcoreaddons_desktop_to_json(dolphinpart ${CMAKE_CURRENT_BINARY_DIR}/dolphinpart.desktop)
 
 target_link_libraries(dolphinpart
     dolphinprivate
 )
 
-install(TARGETS dolphinpart DESTINATION ${KDE_INSTALL_PLUGINDIR})
+install(TARGETS dolphinpart DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/parts)
 
-install(FILES dolphinpart.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dolphinpart.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
 
 ##########################################
 
@@ -236,7 +240,7 @@ set(dolphinstatic_SRCS
     settings/general/statusbarsettingspage.cpp
     settings/dolphinsettingsdialog.cpp
     settings/navigation/navigationsettingspage.cpp
-    settings/services/servicessettingspage.cpp
+    settings/contextmenu/contextmenusettingspage.cpp
     settings/settingspagebase.cpp
     settings/serviceitemdelegate.cpp
     settings/servicemodel.cpp
@@ -283,6 +287,7 @@ kconfig_add_kcfg_files(dolphinstatic_SRCS GENERATE_MOC
     settings/dolphin_compactmodesettings.kcfgc
     settings/dolphin_detailsmodesettings.kcfgc
     settings/dolphin_generalsettings.kcfgc
+    settings/dolphin_contextmenusettings.kcfgc
     settings/dolphin_iconsmodesettings.kcfgc
     search/dolphin_searchsettings.kcfgc
     settings/dolphin_versioncontrolsettings.kcfgc
@@ -367,13 +372,6 @@ set(kcm_dolphinnavigation_PART_SRCS
     settings/navigation/navigationsettingspage.cpp
     settings/settingspagebase.cpp)
 
-set(kcm_dolphinservices_PART_SRCS
-    settings/kcm/kcmdolphinservices.cpp
-    settings/services/servicessettingspage.cpp
-    settings/settingspagebase.cpp
-    settings/serviceitemdelegate.cpp
-    settings/servicemodel.cpp)
-
 set(kcm_dolphingeneral_PART_SRCS
     settings/kcm/kcmdolphingeneral.cpp
     settings/general/behaviorsettingspage.cpp
@@ -396,10 +394,6 @@ kconfig_add_kcfg_files(kcm_dolphinviewmodes_PART_SRCS
 kconfig_add_kcfg_files(kcm_dolphinnavigation_PART_SRCS
     settings/dolphin_generalsettings.kcfgc)
 
-kconfig_add_kcfg_files(kcm_dolphinservices_PART_SRCS
-    settings/dolphin_generalsettings.kcfgc
-    settings/dolphin_versioncontrolsettings.kcfgc)
-
 kconfig_add_kcfg_files(kcm_dolphingeneral_PART_SRCS
     settings/dolphin_generalsettings.kcfgc)
 
@@ -408,29 +402,25 @@ if(NOT WIN32)
     # The settings are still accessible from the hamburger menu
     add_library(kcm_dolphinviewmodes MODULE ${kcm_dolphinviewmodes_PART_SRCS})
     add_library(kcm_dolphinnavigation MODULE ${kcm_dolphinnavigation_PART_SRCS})
-    add_library(kcm_dolphinservices MODULE ${kcm_dolphinservices_PART_SRCS})
     add_library(kcm_dolphingeneral MODULE ${kcm_dolphingeneral_PART_SRCS})
 
     target_link_libraries(kcm_dolphinviewmodes dolphinprivate)
     target_link_libraries(kcm_dolphinnavigation dolphinprivate)
-    target_link_libraries(kcm_dolphinservices dolphinprivate)
     target_link_libraries(kcm_dolphingeneral dolphinprivate)
 
     install( FILES org.kde.dolphin.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} )
     install( FILES settings/kcm/kcmdolphinviewmodes.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} )
     install( FILES settings/kcm/kcmdolphinnavigation.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} )
-    install( FILES settings/kcm/kcmdolphinservices.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} )
     install( FILES settings/kcm/kcmdolphingeneral.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} )
 
     install(TARGETS kcm_dolphinviewmodes DESTINATION ${KDE_INSTALL_PLUGINDIR} )
     install(TARGETS kcm_dolphinnavigation DESTINATION ${KDE_INSTALL_PLUGINDIR} )
-    install(TARGETS kcm_dolphinservices DESTINATION ${KDE_INSTALL_PLUGINDIR} )
     install(TARGETS kcm_dolphingeneral DESTINATION ${KDE_INSTALL_PLUGINDIR} )
 endif()
 
 if(NOT WIN32)
-    add_subdirectory(settings/services/servicemenuinstaller)
-    install( FILES settings/services/servicemenu.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR} )
+    add_subdirectory(settings/contextmenu/servicemenuinstaller)
+    install( FILES settings/contextmenu/servicemenu.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR} )
 endif()
 
 ########### install files ###############
@@ -445,6 +435,7 @@ install(
 
 install( FILES settings/dolphin_directoryviewpropertysettings.kcfg
                settings/dolphin_generalsettings.kcfg
+               settings/dolphin_contextmenusettings.kcfg
                settings/dolphin_compactmodesettings.kcfg
                settings/dolphin_iconsmodesettings.kcfg
                settings/dolphin_detailsmodesettings.kcfg
index be4f447d86a77935a47328fa68d39413115671c5..bb3bf08fb0af47f7ebf1ce20700e8ec0e445025b 100644 (file)
@@ -98,7 +98,7 @@ void DolphinBookmarkHandler::openFolderinTabs(const KBookmarkGroup& bookmarkGrou
 
 void DolphinBookmarkHandler::openInNewTab(const KBookmark& bookmark)
 {
-    m_mainWindow->openNewTabAfterCurrentTab(bookmark.url());
+    m_mainWindow->openNewTab(bookmark.url());
 }
 
 void DolphinBookmarkHandler::openInNewWindow(const KBookmark& bookmark)
index 91e9d8238d5c7834f80ce09f77b99cf729c3f228..eb3f641e5ae6ffe78e237c30e07d5b9cfbf67feb 100644 (file)
@@ -7,6 +7,7 @@
 #include "dolphincontextmenu.h"
 
 #include "dolphin_generalsettings.h"
+#include "dolphin_contextmenusettings.h"
 #include "dolphinmainwindow.h"
 #include "dolphinnewfilemenu.h"
 #include "dolphinplacesmodelsingleton.h"
@@ -61,6 +62,8 @@ DolphinContextMenu::DolphinContextMenu(DolphinMainWindow* parent,
     // or the items itself. To increase the performance both lists are cached.
     const DolphinView* view = m_mainWindow->activeViewContainer()->view();
     m_selectedItems = view->selectedItems();
+
+    installEventFilter(this);
 }
 
 DolphinContextMenu::~DolphinContextMenu()
@@ -109,20 +112,28 @@ DolphinContextMenu::Command DolphinContextMenu::open()
     return m_command;
 }
 
-void DolphinContextMenu::keyPressEvent(QKeyEvent *ev)
+void DolphinContextMenu::childEvent(QChildEvent* event)
 {
-    if (m_removeAction && ev->key() == Qt::Key_Shift) {
-        m_removeAction->update(DolphinRemoveAction::ShiftState::Pressed);
+    if(event->added()) {
+        event->child()->installEventFilter(this);
     }
-    QMenu::keyPressEvent(ev);
+    QMenu::childEvent(event);
 }
 
-void DolphinContextMenu::keyReleaseEvent(QKeyEvent *ev)
+bool DolphinContextMenu::eventFilter(QObject* dest, QEvent* event)
 {
-    if (m_removeAction && ev->key() == Qt::Key_Shift) {
-        m_removeAction->update(DolphinRemoveAction::ShiftState::Released);
+    if(event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
+        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
+        if(m_removeAction && keyEvent->key() == Qt::Key_Shift) {
+            if(event->type() == QEvent::KeyPress) {
+                m_removeAction->update(DolphinRemoveAction::ShiftState::Pressed);
+            } else {
+                m_removeAction->update(DolphinRemoveAction::ShiftState::Released);
+            }
+            return true;
+        }
     }
-    QMenu::keyReleaseEvent(ev);
+    return QMenu::eventFilter(dest, event);
 }
 
 void DolphinContextMenu::openTrashContextMenu()
@@ -175,31 +186,33 @@ void DolphinContextMenu::openTrashItemContextMenu()
 void DolphinContextMenu::addDirectoryItemContextMenu(KFileItemActions &fileItemActions)
 {
     // insert 'Open in new window' and 'Open in new tab' entries
-
     const KFileItemListProperties& selectedItemsProps = selectedItemsProperties();
-
-    addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_tab")));
-    addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_window")));
+    if (ContextMenuSettings::showOpenInNewTab()) {
+        addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_tab")));
+    }
+    if (ContextMenuSettings::showOpenInNewWindow()) {
+        addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_window")));
+    }
 
     // Insert 'Open With' entries
     addOpenWithActions(fileItemActions);
 
     // 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(QList<QUrl>() << 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();
+    DolphinNewFileMenu* newFileMenu = new DolphinNewFileMenu(m_mainWindow->actionCollection(), m_mainWindow);
+    const DolphinView* view = m_mainWindow->activeViewContainer()->view();
+    newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown());
+    newFileMenu->checkUpToDate();
+    newFileMenu->setPopupFiles(QList<QUrl>() << 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();
 }
 
 void DolphinContextMenu::openItemContextMenu()
@@ -260,7 +273,7 @@ void DolphinContextMenu::openItemContextMenu()
             }
         }
 
-        if (selectionHasOnlyDirs) {
+        if (selectionHasOnlyDirs && ContextMenuSettings::showOpenInNewTab()) {
             // insert 'Open in new tab' entry
             addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_tabs")));
         }
@@ -270,24 +283,10 @@ 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);
-    fileItemActions.addPluginActionsTo(this);
-
-    addVersionControlPluginActions();
+    addAdditionalActions(fileItemActions, selectedItemsProps);
 
     // insert 'Copy To' and 'Move To' sub menus
-    if (GeneralSettings::showCopyMoveMenu()) {
+    if (ContextMenuSettings::showCopyMoveMenu()) {
         m_copyToMenu.setUrls(m_selectedItems.urlList());
         m_copyToMenu.setReadOnly(!selectedItemsProps.supportsWriting());
         m_copyToMenu.setAutoErrorHandlingEnabled(true);
@@ -337,23 +336,24 @@ void DolphinContextMenu::openViewportContextMenu()
     }
 
     // Insert 'Add to Places' entry if it's not already in the places panel
-    if (!placeExists(m_mainWindow->activeViewContainer()->url())) {
+    if (ContextMenuSettings::showAddToPlaces() &&
+            !placeExists(m_mainWindow->activeViewContainer()->url())) {
         addAction(m_mainWindow->actionCollection()->action(QStringLiteral("add_to_places")));
     }
     addSeparator();
 
     // Insert 'Sort By' and 'View Mode'
-    addAction(m_mainWindow->actionCollection()->action(QStringLiteral("sort")));
-    addAction(m_mainWindow->actionCollection()->action(QStringLiteral("view_mode")));
-
-    addSeparator();
-
-    // Insert service actions
-    fileItemActions.addServiceActionsTo(this);
-    fileItemActions.addPluginActionsTo(this);
-
-    addVersionControlPluginActions();
+    if (ContextMenuSettings::showSortBy()) {
+        addAction(m_mainWindow->actionCollection()->action(QStringLiteral("sort")));
+    }
+    if (ContextMenuSettings::showViewMode()) {
+        addAction(m_mainWindow->actionCollection()->action(QStringLiteral("view_mode")));
+    }
+    if (ContextMenuSettings::showSortBy() || ContextMenuSettings::showViewMode()) {
+        addSeparator();
+    }
 
+    addAdditionalActions(fileItemActions, baseUrlProperties);
     addCustomActions();
 
     addSeparator();
@@ -373,20 +373,34 @@ void DolphinContextMenu::insertDefaultItemActions(const KFileItemListProperties&
     // Insert 'Cut', 'Copy', 'Copy Location' and 'Paste'
     addAction(collection->action(KStandardAction::name(KStandardAction::Cut)));
     addAction(collection->action(KStandardAction::name(KStandardAction::Copy)));
-    QAction* copyPathAction = collection->action(QString("copy_location"));
-    copyPathAction->setEnabled(m_selectedItems.size() == 1);
-    addAction(copyPathAction);
+    if (ContextMenuSettings::showCopyLocation()) {
+        QAction* copyPathAction = collection->action(QString("copy_location"));
+        copyPathAction->setEnabled(m_selectedItems.size() == 1);
+        addAction(copyPathAction);
+    }
     QAction* pasteAction = createPasteAction();
     if (pasteAction) {
         addAction(pasteAction);
     }
-    addAction(m_mainWindow->actionCollection()->action(QStringLiteral("duplicate")));
 
-    addSeparator();
+    // Insert 'Duplicate Here'
+    if (ContextMenuSettings::showDuplicateHere()) {
+        addAction(m_mainWindow->actionCollection()->action(QStringLiteral("duplicate")));
+    }
 
     // Insert 'Rename'
     addAction(collection->action(KStandardAction::name(KStandardAction::RenameFile)));
 
+    // Insert 'Add to Places' entry if appropriate
+    if (ContextMenuSettings::showAddToPlaces() &&
+            m_selectedItems.count() == 1 &&
+            m_fileInfo.isDir() &&
+            !placeExists(m_fileInfo.url())) {
+        addAction(m_mainWindow->actionCollection()->action(QStringLiteral("add_to_places")));
+    }
+
+    addSeparator();
+
     // Insert 'Move to Trash' and/or 'Delete'
     const bool showDeleteAction = (KSharedConfig::openConfig()->group("KDE").readEntry("ShowDeleteCommand", false) ||
                                     !properties.isLocal());
@@ -484,8 +498,21 @@ void DolphinContextMenu::addOpenWithActions(KFileItemActions& fileItemActions)
     fileItemActions.addOpenWithActionsTo(this, QStringLiteral("DesktopEntryName != '%1'").arg(qApp->desktopFileName()));
 }
 
-void DolphinContextMenu::addVersionControlPluginActions()
+void DolphinContextMenu::addCustomActions()
+{
+    addActions(m_customActions);
+}
+
+void DolphinContextMenu::addAdditionalActions(KFileItemActions &fileItemActions, const KFileItemListProperties &props)
 {
+    addSeparator();
+
+    QList<QAction *> additionalActions;
+    if (props.isDirectory() && props.isLocal()) {
+        additionalActions << m_mainWindow->actionCollection()->action(QStringLiteral("open_terminal"));
+    }
+    fileItemActions.addActionsTo(this, KFileItemActions::MenuActionSource::All, additionalActions);
+
     const DolphinView* view = m_mainWindow->activeViewContainer()->view();
     const QList<QAction*> versionControlActions = view->versionControlActions(m_selectedItems);
     if (!versionControlActions.isEmpty()) {
@@ -494,8 +521,3 @@ void DolphinContextMenu::addVersionControlPluginActions()
     }
 }
 
-void DolphinContextMenu::addCustomActions()
-{
-    addActions(m_customActions);
-}
-
index b93df2b612db8bacd4b95b4bb4b165a5a38ac45d..7f0b6988a682e25a265f0e3ef40621a440f48e41 100644 (file)
@@ -74,8 +74,8 @@ public:
     Command open();
 
 protected:
-    void keyPressEvent(QKeyEvent *ev) override;
-    void keyReleaseEvent(QKeyEvent *ev) override;
+    void childEvent(QChildEvent* event) override;
+    bool eventFilter(QObject* dest, QEvent* event) override;
 
 private:
     void openTrashContextMenu();
@@ -107,11 +107,6 @@ private:
      */
     void addOpenWithActions(KFileItemActions& fileItemActions);
 
-    /**
-     * Adds actions that are provided by a KVersionControlPlugin.
-     */
-    void addVersionControlPluginActions();
-
     /**
      * Adds custom actions e.g. like the "[x] Expandable Folders"-action
      * provided in the details view.
@@ -119,6 +114,11 @@ private:
     void addCustomActions();
 
 private:
+    /**
+     * Add services, custom actions, plugins and version control items to the menu
+     */
+    void addAdditionalActions(KFileItemActions &fileItemActions, const KFileItemListProperties &props);
+
     struct Entry
     {
         int type;
index 71d3ca03339f405c9b874d684c0e0d5aa2263576..bbb809cceca42072ada8c8d830f508a3aceb672c 100644 (file)
@@ -134,10 +134,9 @@ DolphinMainWindow::DolphinMainWindow() :
     connect(undoManager, &KIO::FileUndoManager::jobRecordingFinished,
             this, &DolphinMainWindow::showCommand);
 
-    GeneralSettings* generalSettings = GeneralSettings::self();
-    const bool firstRun = (generalSettings->version() < 200);
+    const bool firstRun = (GeneralSettings::version() < 200);
     if (firstRun) {
-        generalSettings->setViewPropsTimestamp(QDateTime::currentDateTime());
+        GeneralSettings::setViewPropsTimestamp(QDateTime::currentDateTime());
     }
 
     setAcceptDrops(true);
@@ -173,8 +172,8 @@ DolphinMainWindow::DolphinMainWindow() :
     connect(clipboard, &QClipboard::dataChanged,
             this, &DolphinMainWindow::updatePasteAction);
 
-    QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar"));
-    showFilterBarAction->setChecked(generalSettings->filterBar());
+    QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter"));
+    toggleFilterBarAction->setChecked(GeneralSettings::filterBar());
 
     if (firstRun) {
         menuBar()->setVisible(false);
@@ -387,8 +386,8 @@ void DolphinMainWindow::updateHistory()
 
 void DolphinMainWindow::updateFilterBarAction(bool show)
 {
-    QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar"));
-    showFilterBarAction->setChecked(show);
+    QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter"));
+    toggleFilterBarAction->setChecked(show);
 }
 
 void DolphinMainWindow::openNewMainWindow()
@@ -398,7 +397,11 @@ void DolphinMainWindow::openNewMainWindow()
 
 void DolphinMainWindow::openNewActivatedTab()
 {
+    // keep browsers compatibility, new tab is always after last one
+    auto openNewTabAfterLastTabConfigured = GeneralSettings::openNewTabAfterLastTab();
+    GeneralSettings::setOpenNewTabAfterLastTab(true);
     m_tabWidget->openNewActivatedTab();
+    GeneralSettings::setOpenNewTabAfterLastTab(openNewTabAfterLastTabConfigured);
 }
 
 void DolphinMainWindow::addToPlaces()
@@ -427,19 +430,9 @@ void DolphinMainWindow::addToPlaces()
     }
 }
 
-void DolphinMainWindow::openNewTab(const QUrl& url, DolphinTabWidget::TabPlacement tabPlacement)
+void DolphinMainWindow::openNewTab(const QUrl& url)
 {
-    m_tabWidget->openNewTab(url, QUrl(), tabPlacement);
-}
-
-void DolphinMainWindow::openNewTabAfterCurrentTab(const QUrl& url)
-{
-    m_tabWidget->openNewTab(url, QUrl(), DolphinTabWidget::AfterCurrentTab);
-}
-
-void DolphinMainWindow::openNewTabAfterLastTab(const QUrl& url)
-{
-    m_tabWidget->openNewTab(url, QUrl(), DolphinTabWidget::AfterLastTab);
+    m_tabWidget->openNewTab(url, QUrl());
 }
 
 void DolphinMainWindow::openInNewTab()
@@ -450,7 +443,7 @@ void DolphinMainWindow::openInNewTab()
     for (const KFileItem& item : list) {
         const QUrl& url = DolphinView::openItemAsFolderUrl(item);
         if (!url.isEmpty()) {
-            openNewTabAfterCurrentTab(url);
+            openNewTab(url);
             tabCreated = true;
         }
     }
@@ -458,7 +451,7 @@ void DolphinMainWindow::openInNewTab()
     // if no new tab has been created from the selection
     // open the current directory in a new tab
     if (!tabCreated) {
-        openNewTabAfterCurrentTab(m_activeViewContainer->url());
+        openNewTab(m_activeViewContainer->url());
     }
 }
 
@@ -760,7 +753,7 @@ void DolphinMainWindow::slotBackForwardActionMiddleClicked(QAction* action)
 {
     if (action) {
         const KUrlNavigator *urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory();
-        openNewTabAfterCurrentTab(urlNavigator->locationUrl(action->data().value<int>()));
+        openNewTab(urlNavigator->locationUrl(action->data().value<int>()));
     }
 }
 
@@ -812,7 +805,7 @@ void DolphinMainWindow::invertSelection()
 void DolphinMainWindow::toggleSplitView()
 {
     DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
-    tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled());
+    tabPage->setSplitViewEnabled(!tabPage->splitViewEnabled(), WithAnimation);
 
     updateViewActions();
 }
@@ -820,8 +813,8 @@ void DolphinMainWindow::toggleSplitView()
 void DolphinMainWindow::toggleSplitStash()
 {
     DolphinTabPage* tabPage = m_tabWidget->currentTabPage();
-    tabPage->setSplitViewEnabled(false);
-    tabPage->setSplitViewEnabled(true, QUrl("stash:/"));
+    tabPage->setSplitViewEnabled(false, WithAnimation);
+    tabPage->setSplitViewEnabled(true, WithAnimation, QUrl("stash:/"));
 }
 
 void DolphinMainWindow::reloadView()
@@ -851,6 +844,15 @@ void DolphinMainWindow::showFilterBar()
     m_activeViewContainer->setFilterBarVisible(true);
 }
 
+void DolphinMainWindow::toggleFilterBar()
+{
+    const bool checked = !m_activeViewContainer->isFilterBarVisible();
+    m_activeViewContainer->setFilterBarVisible(checked);
+
+    QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter"));
+    toggleFilterBarAction->setChecked(checked);
+}
+
 void DolphinMainWindow::toggleEditLocation()
 {
     clearStatusBar();
@@ -930,25 +932,25 @@ void DolphinMainWindow::goBackInNewTab()
 {
     const KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory();
     const int index = urlNavigator->historyIndex() + 1;
-    openNewTabAfterCurrentTab(urlNavigator->locationUrl(index));
+    openNewTab(urlNavigator->locationUrl(index));
 }
 
 void DolphinMainWindow::goForwardInNewTab()
 {
     const KUrlNavigator* urlNavigator = activeViewContainer()->urlNavigatorInternalWithHistory();
     const int index = urlNavigator->historyIndex() - 1;
-    openNewTabAfterCurrentTab(urlNavigator->locationUrl(index));
+    openNewTab(urlNavigator->locationUrl(index));
 }
 
 void DolphinMainWindow::goUpInNewTab()
 {
     const QUrl currentUrl = activeViewContainer()->urlNavigator()->locationUrl();
-    openNewTabAfterCurrentTab(KIO::upUrl(currentUrl));
+    openNewTab(KIO::upUrl(currentUrl));
 }
 
 void DolphinMainWindow::goHomeInNewTab()
 {
-    openNewTabAfterCurrentTab(Dolphin::homeUrl());
+    openNewTab(Dolphin::homeUrl());
 }
 
 void DolphinMainWindow::compareFiles()
@@ -1065,7 +1067,7 @@ void DolphinMainWindow::editSettings()
         container->view()->writeSettings();
 
         const QUrl url = container->url();
-        DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(url, this);
+        DolphinSettingsDialog* settingsDialog = new DolphinSettingsDialog(url, this, actionCollection());
         connect(settingsDialog, &DolphinSettingsDialog::settingsChanged, this, &DolphinMainWindow::refreshViews);
         connect(settingsDialog, &DolphinSettingsDialog::settingsChanged,
                 &DolphinUrlNavigatorsController::slotReadSettings);
@@ -1135,7 +1137,7 @@ void DolphinMainWindow::openContextMenu(const QPoint& pos,
         break;
 
     case DolphinContextMenu::OpenParentFolderInNewTab:
-        openNewTabAfterLastTab(KIO::upUrl(item.url()));
+        openNewTab(KIO::upUrl(item.url()));
         break;
 
     case DolphinContextMenu::None:
@@ -1375,7 +1377,7 @@ void DolphinMainWindow::setupActions()
         "<emphasis>Tab</emphasis> with the current location and view.<nl/>"
         "A tab is an additional view within this window. "
         "You can drag and drop items between tabs."));
-    actionCollection()->setDefaultShortcuts(newTab, {Qt::CTRL + Qt::Key_T, Qt::CTRL + Qt::SHIFT + Qt::Key_N});
+    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"));
@@ -1434,7 +1436,7 @@ void DolphinMainWindow::setupActions()
         "the <emphasis>active</emphasis> view to the inactive split view."));
     copyToOtherViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
     copyToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Copy to Inactive Split View"));
-    actionCollection()->setDefaultShortcut(copyToOtherViewAction, Qt::SHIFT + Qt::Key_F5 );
+    actionCollection()->setDefaultShortcut(copyToOtherViewAction, Qt::SHIFT | Qt::Key_F5 );
     connect(copyToOtherViewAction, &QAction::triggered, m_tabWidget, &DolphinTabWidget::copyToInactiveSplitView);
 
     QAction* moveToOtherViewAction = actionCollection()->addAction(QStringLiteral("move_to_inactive_split_view"));
@@ -1443,9 +1445,32 @@ void DolphinMainWindow::setupActions()
         "the <emphasis>active</emphasis> view to the inactive split view."));
     moveToOtherViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-cut")));
     moveToOtherViewAction->setIconText(i18nc("@action:inmenu Edit", "Move to Inactive Split View"));
-    actionCollection()->setDefaultShortcut(moveToOtherViewAction, Qt::SHIFT + Qt::Key_F6 );
+    actionCollection()->setDefaultShortcut(moveToOtherViewAction, Qt::SHIFT | Qt::Key_F6 );
     connect(moveToOtherViewAction, &QAction::triggered, m_tabWidget, &DolphinTabWidget::moveToInactiveSplitView);
 
+    QAction* showFilterBar = actionCollection()->addAction(QStringLiteral("show_filter_bar"));
+    showFilterBar->setText(i18nc("@action:inmenu Tools", "Filter..."));
+    showFilterBar->setToolTip(i18nc("@info:tooltip", "Toggle Filter Bar"));
+    showFilterBar->setWhatsThis(xi18nc("@info:whatsthis", "This opens the "
+        "<emphasis>Filter Bar</emphasis> at the bottom of the window.<nl/> "
+        "There you can enter a text to filter the files and folders currently displayed. "
+        "Only those that contain the text in their name will be kept in view."));
+    showFilterBar->setIcon(QIcon::fromTheme(QStringLiteral("view-filter")));
+    actionCollection()->setDefaultShortcuts(showFilterBar, {Qt::CTRL | Qt::Key_I, Qt::Key_Slash});
+    connect(showFilterBar, &QAction::triggered, this, &DolphinMainWindow::showFilterBar);
+
+    // toggle_filter acts as a copy of the main showFilterBar to be used mainly
+    // in the toolbar, with no default shortcut attached, to avoid messing with
+    // existing workflows (filter bar always open and Ctrl-I to focus)
+    QAction *toggleFilter = actionCollection()->addAction(QStringLiteral("toggle_filter"));
+    toggleFilter->setText(i18nc("@action:inmenu", "Toggle Filter Bar"));
+    toggleFilter->setIconText(i18nc("@action:intoolbar", "Filter"));
+    toggleFilter->setIcon(showFilterBar->icon());
+    toggleFilter->setToolTip(showFilterBar->toolTip());
+    toggleFilter->setWhatsThis(showFilterBar->whatsThis());
+    toggleFilter->setCheckable(true);
+    connect(toggleFilter, &QAction::triggered, this, &DolphinMainWindow::toggleFilterBar);
+
     QAction *searchAction = KStandardAction::find(this, &DolphinMainWindow::find, actionCollection());
     searchAction->setText(i18n("Search..."));
     searchAction->setToolTip(i18nc("@info:tooltip", "Search for files and folders"));
@@ -1476,7 +1501,7 @@ void DolphinMainWindow::setupActions()
     invertSelection->setWhatsThis(xi18nc("@info:whatsthis invert", "This selects all "
         "objects that you have currently <emphasis>not</emphasis> selected instead."));
     invertSelection->setIcon(QIcon::fromTheme(QStringLiteral("edit-select-invert")));
-    actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL + Qt::SHIFT + Qt::Key_A);
+    actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL | Qt::SHIFT | Qt::Key_A);
     connect(invertSelection, &QAction::triggered, this, &DolphinMainWindow::invertSelection);
 
     // setup 'View' menu
@@ -1491,12 +1516,12 @@ void DolphinMainWindow::setupActions()
     connect(split, &QAction::triggered, this, &DolphinMainWindow::toggleSplitView);
 
     QAction* stashSplit = actionCollection()->addAction(QStringLiteral("split_stash"));
-    actionCollection()->setDefaultShortcut(stashSplit, Qt::CTRL + Qt::Key_S);
+    actionCollection()->setDefaultShortcut(stashSplit, Qt::CTRL | Qt::Key_S);
     stashSplit->setText(i18nc("@action:intoolbar Stash", "Stash"));
     stashSplit->setToolTip(i18nc("@info", "Opens the stash virtual directory in a split window"));
     stashSplit->setIcon(QIcon::fromTheme(QStringLiteral("folder-stash")));
     stashSplit->setCheckable(false);
-    stashSplit->setVisible(KProtocolInfo::isKnownProtocol("stash"));
+    stashSplit->setVisible(QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.kio.StashNotifier")));
     connect(stashSplit, &QAction::triggered, this, &DolphinMainWindow::toggleSplitStash);
 
     KStandardAction::redisplay(this, &DolphinMainWindow::reloadView, actionCollection());
@@ -1526,7 +1551,7 @@ void DolphinMainWindow::setupActions()
     replaceLocation->setWhatsThis(xi18nc("@info:whatsthis",
         "This switches to editing the location and selects it "
         "so you can quickly enter a different location."));
-    actionCollection()->setDefaultShortcut(replaceLocation, Qt::CTRL + Qt::Key_L);
+    actionCollection()->setDefaultShortcut(replaceLocation, Qt::CTRL | Qt::Key_L);
     connect(replaceLocation, &QAction::triggered, this, &DolphinMainWindow::replaceLocation);
 
     // setup 'Go' menu
@@ -1560,7 +1585,7 @@ void DolphinMainWindow::setupActions()
     undoCloseTab->setText(i18nc("@action:inmenu File", "Undo close tab"));
     undoCloseTab->setWhatsThis(i18nc("@info:whatsthis undo close tab",
         "This returns you to the previously closed tab."));
-    actionCollection()->setDefaultShortcut(undoCloseTab, Qt::CTRL + Qt::SHIFT + Qt::Key_T);
+    actionCollection()->setDefaultShortcut(undoCloseTab, Qt::CTRL | Qt::SHIFT | Qt::Key_T);
     undoCloseTab->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo")));
     undoCloseTab->setEnabled(false);
     connect(undoCloseTab, &QAction::triggered, recentTabsMenu, &DolphinRecentTabsMenu::undoCloseTab);
@@ -1601,16 +1626,6 @@ void DolphinMainWindow::setupActions()
         "including folders that contain personal application data."));
 
     // setup 'Tools' menu
-    QAction* showFilterBar = actionCollection()->addAction(QStringLiteral("show_filter_bar"));
-    showFilterBar->setText(i18nc("@action:inmenu Tools", "Show Filter Bar"));
-    showFilterBar->setWhatsThis(xi18nc("@info:whatsthis", "This opens the "
-        "<emphasis>Filter Bar</emphasis> at the bottom of the window.<nl/> "
-        "There you can enter a text to filter the files and folders currently displayed. "
-        "Only those that contain the text in their name will be kept in view."));
-    showFilterBar->setIcon(QIcon::fromTheme(QStringLiteral("view-filter")));
-    actionCollection()->setDefaultShortcuts(showFilterBar, {Qt::CTRL + Qt::Key_I, Qt::Key_Slash});
-    connect(showFilterBar, &QAction::triggered, this, &DolphinMainWindow::showFilterBar);
-
     QAction* compareFiles = actionCollection()->addAction(QStringLiteral("compare_files"));
     compareFiles->setText(i18nc("@action:inmenu Tools", "Compare Files"));
     compareFiles->setIcon(QIcon::fromTheme(QStringLiteral("kompare")));
@@ -1623,7 +1638,7 @@ void DolphinMainWindow::setupActions()
         "<para>This opens a preferred search tool for the viewed location.</para>"
         "<para>Use <emphasis>More Search Tools</emphasis> menu to configure it.</para>"));
     openPreferredSearchTool->setIcon(QIcon::fromTheme(QStringLiteral("search")));
-    actionCollection()->setDefaultShortcut(openPreferredSearchTool, Qt::CTRL + Qt::SHIFT + Qt::Key_F);
+    actionCollection()->setDefaultShortcut(openPreferredSearchTool, Qt::CTRL | Qt::SHIFT | Qt::Key_F);
     connect(openPreferredSearchTool, &QAction::triggered, this, &DolphinMainWindow::openPreferredSearchTool);
 
     if (KAuthorized::authorize(QStringLiteral("shell_access"))) {
@@ -1632,15 +1647,15 @@ 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("dialog-scripts")));
-        actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT + Qt::Key_F4);
+        openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal")));
+        actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT | Qt::Key_F4);
         connect(openTerminal, &QAction::triggered, this, &DolphinMainWindow::openTerminal);
 
 #ifdef HAVE_TERMINAL
         QAction* focusTerminalPanel = actionCollection()->addAction(QStringLiteral("focus_terminal_panel"));
         focusTerminalPanel->setText(i18nc("@action:inmenu Tools", "Focus Terminal Panel"));
         focusTerminalPanel->setIcon(QIcon::fromTheme(QStringLiteral("swap-panels")));
-        actionCollection()->setDefaultShortcut(focusTerminalPanel, Qt::CTRL + Qt::SHIFT + Qt::Key_F4);
+        actionCollection()->setDefaultShortcut(focusTerminalPanel, Qt::CTRL | Qt::SHIFT | Qt::Key_F4);
         connect(focusTerminalPanel, &QAction::triggered, this, &DolphinMainWindow::focusTerminalPanel);
 #endif
     }
@@ -1672,10 +1687,10 @@ void DolphinMainWindow::setupActions()
 
     // not in menu actions
     QList<QKeySequence> nextTabKeys = KStandardShortcut::tabNext();
-    nextTabKeys.append(QKeySequence(Qt::CTRL + Qt::Key_Tab));
+    nextTabKeys.append(QKeySequence(Qt::CTRL | Qt::Key_Tab));
 
     QList<QKeySequence> prevTabKeys = KStandardShortcut::tabPrev();
-    prevTabKeys.append(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab));
+    prevTabKeys.append(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Tab));
 
     for (int i = 0; i < MaxActivateTabShortcuts; ++i) {
         QAction* activateTab = actionCollection()->addAction(QStringLiteral("activate_tab_%1").arg(i));
@@ -1693,7 +1708,7 @@ void DolphinMainWindow::setupActions()
     activateLastTab->setText(i18nc("@action:inmenu", "Activate Last Tab"));
     activateLastTab->setEnabled(false);
     connect(activateLastTab, &QAction::triggered, m_tabWidget, &DolphinTabWidget::activateLastTab);
-    actionCollection()->setDefaultShortcut(activateLastTab, Qt::ALT + Qt::Key_0);
+    actionCollection()->setDefaultShortcut(activateLastTab, Qt::ALT | Qt::Key_0);
 
     QAction* activateNextTab = actionCollection()->addAction(QStringLiteral("activate_next_tab"));
     activateNextTab->setIconText(i18nc("@action:inmenu", "Next Tab"));
@@ -1811,7 +1826,7 @@ void DolphinMainWindow::setupDockWidgets()
     connect(foldersPanel, &FoldersPanel::folderActivated,
             this, &DolphinMainWindow::changeUrl);
     connect(foldersPanel, &FoldersPanel::folderMiddleClicked,
-            this, &DolphinMainWindow::openNewTabAfterCurrentTab);
+            this, &DolphinMainWindow::openNewTab);
     connect(foldersPanel, &FoldersPanel::errorMessage,
             this, &DolphinMainWindow::showErrorMessage);
 
@@ -1888,13 +1903,13 @@ void DolphinMainWindow::setupDockWidgets()
     placesDock->setWidget(m_placesPanel);
 
     QAction *placesAction = placesDock->toggleViewAction();
-    createPanelAction(QIcon::fromTheme(QStringLiteral("bookmarks")), Qt::Key_F9, placesAction, QStringLiteral("show_places_panel"));
+    createPanelAction(QIcon::fromTheme(QStringLiteral("compass")), Qt::Key_F9, placesAction, QStringLiteral("show_places_panel"));
 
     addDockWidget(Qt::LeftDockWidgetArea, placesDock);
     connect(m_placesPanel, &PlacesPanel::placeActivated,
             this, &DolphinMainWindow::slotPlaceActivated);
     connect(m_placesPanel, &PlacesPanel::placeMiddleClicked,
-            this, &DolphinMainWindow::openNewTabAfterCurrentTab);
+            this, &DolphinMainWindow::openNewTab);
     connect(m_placesPanel, &PlacesPanel::errorMessage,
             this, &DolphinMainWindow::showErrorMessage);
     connect(this, &DolphinMainWindow::urlChanged,
@@ -2036,8 +2051,8 @@ void DolphinMainWindow::updateViewActions()
 {
     m_actionHandler->updateViewActions();
 
-    QAction* showFilterBarAction = actionCollection()->action(QStringLiteral("show_filter_bar"));
-    showFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible());
+    QAction* toggleFilterBarAction = actionCollection()->action(QStringLiteral("toggle_filter"));
+    toggleFilterBarAction->setChecked(m_activeViewContainer->isFilterBarVisible());
 
     updateSplitAction();
 }
@@ -2126,7 +2141,7 @@ void DolphinMainWindow::refreshViews()
         // The startup settings have been changed by the user (see bug #254947).
         // Synchronize the split-view setting with the active view:
         const bool splitView = GeneralSettings::splitView();
-        m_tabWidget->currentTabPage()->setSplitViewEnabled(splitView);
+        m_tabWidget->currentTabPage()->setSplitViewEnabled(splitView, WithAnimation);
         updateSplitAction();
         updateWindowTitle();
     }
@@ -2189,7 +2204,7 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container)
     connect(navigator, &KUrlNavigator::editableStateChanged,
             this, &DolphinMainWindow::slotEditableStateChanged);
     connect(navigator, &KUrlNavigator::tabRequested,
-            this, &DolphinMainWindow::openNewTabAfterLastTab);
+            this, &DolphinMainWindow::openNewTab);
 
     disconnect(m_updateHistoryConnection);
     m_updateHistoryConnection = connect(
index 8d5eae344c63da5c21f9ac96f8aa5e3a3699cf48..883d92b699327d7463ef4424c5efdb28138abee5 100644 (file)
@@ -170,14 +170,9 @@ public slots:
     void quit();
 
     /**
-     * Opens a new tab and places it after the current tab
-     */
-    void openNewTabAfterCurrentTab(const QUrl& url);
-
-    /**
-     * Opens a new tab and places it as the last tab
+     * Opens a new tab in the background showing the URL \a url.
      */
-    void openNewTabAfterLastTab(const QUrl& url);
+    void openNewTab(const QUrl& url);
 
 signals:
     /**
@@ -312,6 +307,7 @@ private slots:
     void disableStopAction();
 
     void showFilterBar();
+    void toggleFilterBar();
 
     /**
      * Toggles between edit and browse mode of the navigation bar.
@@ -416,11 +412,6 @@ private slots:
      */
     void addToPlaces();
 
-    /**
-     * Opens a new tab in the background showing the URL \a url.
-     */
-    void openNewTab(const QUrl& url, DolphinTabWidget::TabPlacement tabPlacement);
-
     /**
      * Opens the selected folder in a new tab.
      */
index b25c60d0c0b3a23f6f0138454f18fb552e7b8306..be88b61af4328ec8511df24bea5dc636e65a9498 100644 (file)
@@ -30,11 +30,7 @@ DolphinNavigatorsWidgetAction::DolphinNavigatorsWidgetAction(QWidget *parent) :
     QWidgetAction{parent},
     m_splitter{new QSplitter(Qt::Horizontal)},
     m_adjustSpacingTimer{new QTimer(this)},
-    m_globalXOfSplitter{INT_MIN},
-    m_globalXOfPrimary{INT_MIN},
-    m_widthOfPrimary{INT_MIN},
-    m_globalXOfSecondary{INT_MIN},
-    m_widthOfSecondary{INT_MIN}
+    m_viewGeometriesHelper{m_splitter.get(), this}
 {
     updateText();
     setIcon(QIcon::fromTheme(QStringLiteral("dialog-scripts")));
@@ -49,6 +45,67 @@ DolphinNavigatorsWidgetAction::DolphinNavigatorsWidgetAction(QWidget *parent) :
             this, &DolphinNavigatorsWidgetAction::adjustSpacing);
 }
 
+void DolphinNavigatorsWidgetAction::adjustSpacing()
+{
+    auto viewGeometries = m_viewGeometriesHelper.viewGeometries();
+    const int widthOfSplitterPrimary = viewGeometries.globalXOfPrimary + viewGeometries.widthOfPrimary - viewGeometries.globalXOfNavigatorsWidget;
+    const QList<int> splitterSizes = {widthOfSplitterPrimary,
+                                      m_splitter->width() - widthOfSplitterPrimary};
+    m_splitter->setSizes(splitterSizes);
+
+    // primary side of m_splitter
+    int leadingSpacing = viewGeometries.globalXOfPrimary - viewGeometries.globalXOfNavigatorsWidget;
+    if (leadingSpacing < 0) {
+        leadingSpacing = 0;
+    }
+    int trailingSpacing = (viewGeometries.globalXOfNavigatorsWidget + m_splitter->width())
+                          - (viewGeometries.globalXOfPrimary + viewGeometries.widthOfPrimary);
+    if (trailingSpacing < 0 || emptyTrashButton(Primary)->isVisible()
+                            || networkFolderButton(Primary)->isVisible()
+    ) {
+        trailingSpacing = 0;
+    }
+    const int widthLeftForUrlNavigator = m_splitter->widget(0)->width() - leadingSpacing - trailingSpacing;
+    const int widthNeededForUrlNavigator = primaryUrlNavigator()->sizeHint().width() - widthLeftForUrlNavigator;
+    if (widthNeededForUrlNavigator > 0) {
+        trailingSpacing -= widthNeededForUrlNavigator;
+        if (trailingSpacing < 0) {
+            leadingSpacing += trailingSpacing;
+            trailingSpacing = 0;
+        }
+        if (leadingSpacing < 0) {
+            leadingSpacing = 0;
+        }
+    }
+    spacing(Primary, Leading)->setMinimumWidth(leadingSpacing);
+    spacing(Primary, Trailing)->setFixedWidth(trailingSpacing);
+
+    // secondary side of m_splitter
+    if (viewGeometries.globalXOfSecondary == INT_MIN) {
+        Q_ASSERT(viewGeometries.widthOfSecondary == INT_MIN);
+        return;
+    }
+    spacing(Primary, Trailing)->setFixedWidth(0);
+
+    trailingSpacing = (viewGeometries.globalXOfNavigatorsWidget + m_splitter->width())
+                      - (viewGeometries.globalXOfSecondary + viewGeometries.widthOfSecondary);
+    if (trailingSpacing < 0 || emptyTrashButton(Secondary)->isVisible()
+                            || networkFolderButton(Secondary)->isVisible()
+    ) {
+        trailingSpacing = 0;
+    } else {
+        const int widthLeftForUrlNavigator2 = m_splitter->widget(1)->width() - trailingSpacing;
+        const int widthNeededForUrlNavigator2 = secondaryUrlNavigator()->sizeHint().width() - widthLeftForUrlNavigator2;
+        if (widthNeededForUrlNavigator2 > 0) {
+            trailingSpacing -= widthNeededForUrlNavigator2;
+            if (trailingSpacing < 0) {
+                trailingSpacing = 0;
+            }
+        }
+    }
+    spacing(Secondary, Trailing)->setMinimumWidth(trailingSpacing);
+}
+
 void DolphinNavigatorsWidgetAction::createSecondaryUrlNavigator()
 {
     Q_ASSERT(m_splitter->count() == 1);
@@ -57,31 +114,10 @@ void DolphinNavigatorsWidgetAction::createSecondaryUrlNavigator()
     updateText();
 }
 
-void DolphinNavigatorsWidgetAction::followViewContainerGeometry(
-                                    int globalXOfPrimary,   int widthOfPrimary)
+void DolphinNavigatorsWidgetAction::followViewContainersGeometry(QWidget *primaryViewContainer,
+                                                                 QWidget *secondaryViewContainer)
 {
-    followViewContainersGeometry(globalXOfPrimary, widthOfPrimary, INT_MIN, INT_MIN);
-}
-
-void DolphinNavigatorsWidgetAction::followViewContainersGeometry(
-                                    int globalXOfPrimary,   int widthOfPrimary,
-                                    int globalXOfSecondary, int widthOfSecondary)
-{
-    if (QApplication::layoutDirection() == Qt::LeftToRight) {
-        m_globalXOfSplitter = m_splitter->mapToGlobal(QPoint(0,0)).x();
-        m_globalXOfPrimary = globalXOfPrimary;
-        m_globalXOfSecondary = globalXOfSecondary;
-    } else {
-        // When the direction is reversed, globalX does not change.
-        // For the adjustSpacing() code to work we need globalX to measure from right to left
-        // and to measure up to the rightmost point of a widget instead of the leftmost.
-        m_globalXOfSplitter = (-1) * (m_splitter->mapToGlobal(QPoint(0,0)).x() + m_splitter->width());
-        m_globalXOfPrimary = (-1) * (globalXOfPrimary + widthOfPrimary);
-        m_globalXOfSecondary = (globalXOfSecondary == INT_MIN) ? INT_MIN :
-                               (-1) * (globalXOfSecondary + widthOfSecondary);
-    }
-    m_widthOfPrimary = widthOfPrimary;
-    m_widthOfSecondary = widthOfSecondary;
+    m_viewGeometriesHelper.setViewContainers(primaryViewContainer, secondaryViewContainer);
     adjustSpacing();
 }
 
@@ -141,77 +177,6 @@ void DolphinNavigatorsWidgetAction::deleteWidget(QWidget *widget)
     m_splitter->setParent(nullptr);
 }
 
-void DolphinNavigatorsWidgetAction::adjustSpacing()
-{
-    Q_ASSERT(m_globalXOfSplitter != INT_MIN);
-    Q_ASSERT(m_globalXOfPrimary  != INT_MIN);
-    Q_ASSERT(m_widthOfPrimary    != INT_MIN);
-    const int widthOfSplitterPrimary = m_globalXOfPrimary + m_widthOfPrimary - m_globalXOfSplitter;
-    const QList<int> splitterSizes = {widthOfSplitterPrimary,
-                                      m_splitter->width() - widthOfSplitterPrimary};
-    m_splitter->setSizes(splitterSizes);
-
-    // primary side of m_splitter
-    int leadingSpacing = m_globalXOfPrimary - m_globalXOfSplitter;
-    if (leadingSpacing < 0) {
-        leadingSpacing = 0;
-    }
-    int trailingSpacing = (m_globalXOfSplitter + m_splitter->width())
-                          - (m_globalXOfPrimary + m_widthOfPrimary);
-#if KIO_VERSION < QT_VERSION_CHECK(5, 78, 0)
-    if (trailingSpacing < 0 || emptyTrashButton(Primary)->isVisible()) {
-#else
-    if (trailingSpacing < 0 || emptyTrashButton(Primary)->isVisible()
-                            || networkFolderButton(Primary)->isVisible()
-    ) {
-#endif
-        trailingSpacing = 0;
-    }
-    const int widthLeftForUrlNavigator = m_splitter->widget(0)->width() - leadingSpacing - trailingSpacing;
-    const int widthNeededForUrlNavigator = primaryUrlNavigator()->sizeHint().width() - widthLeftForUrlNavigator;
-    if (widthNeededForUrlNavigator > 0) {
-        trailingSpacing -= widthNeededForUrlNavigator;
-        if (trailingSpacing < 0) {
-            leadingSpacing += trailingSpacing;
-            trailingSpacing = 0;
-        }
-        if (leadingSpacing < 0) {
-            leadingSpacing = 0;
-        }
-    }
-    spacing(Primary, Leading)->setMinimumWidth(leadingSpacing);
-    spacing(Primary, Trailing)->setFixedWidth(trailingSpacing);
-
-    // secondary side of m_splitter
-    if (m_globalXOfSecondary == INT_MIN) {
-        Q_ASSERT(m_widthOfSecondary == INT_MIN);
-        return;
-    }
-    spacing(Primary, Trailing)->setFixedWidth(0);
-
-    trailingSpacing = (m_globalXOfSplitter + m_splitter->width())
-                      - (m_globalXOfSecondary + m_widthOfSecondary);
-#if KIO_VERSION < QT_VERSION_CHECK(5, 78, 0)
-    if (trailingSpacing < 0 || emptyTrashButton(Secondary)->isVisible()) {
-#else
-    if (trailingSpacing < 0 || emptyTrashButton(Secondary)->isVisible()
-                            || networkFolderButton(Secondary)->isVisible()
-    ) {
-#endif
-        trailingSpacing = 0;
-    } else {
-        const int widthLeftForUrlNavigator2 = m_splitter->widget(1)->width() - trailingSpacing;
-        const int widthNeededForUrlNavigator2 = secondaryUrlNavigator()->sizeHint().width() - widthLeftForUrlNavigator2;
-        if (widthNeededForUrlNavigator2 > 0) {
-            trailingSpacing -= widthNeededForUrlNavigator2;
-            if (trailingSpacing < 0) {
-                trailingSpacing = 0;
-            }
-        }
-    }
-    spacing(Secondary, Trailing)->setMinimumWidth(trailingSpacing);
-}
-
 QWidget *DolphinNavigatorsWidgetAction::createNavigatorWidget(Side side) const
 {
     auto navigatorWidget = new QWidget(m_splitter.get());
@@ -228,16 +193,27 @@ QWidget *DolphinNavigatorsWidgetAction::createNavigatorWidget(Side side) const
     auto emptyTrashButton = newEmptyTrashButton(urlNavigator, navigatorWidget);
     layout->addWidget(emptyTrashButton);
 
-#if !(KIO_VERSION < QT_VERSION_CHECK(5, 78, 0))
     auto networkFolderButton = newNetworkFolderButton(urlNavigator, navigatorWidget);
     layout->addWidget(networkFolderButton);
-#endif
 
-    connect(urlNavigator, &KUrlNavigator::urlChanged, this, [this]() {
+    connect(urlNavigator, &KUrlNavigator::urlChanged, this, [urlNavigator, this]() {
+        // Update URL navigator to show a server URL entry placeholder text if we
+        // just loaded the remote:/ page, to make it easier for users to figure out
+        // that they can enter arbitrary remote URLs. See bug 414670
+        if (urlNavigator->locationUrl().scheme() == QLatin1String("remote")) {
+            if (!urlNavigator->isUrlEditable()) {
+                urlNavigator->setUrlEditable(true);
+            }
+            urlNavigator->clearText();
+            urlNavigator->setPlaceholderText(i18n("Enter server URL (e.g. smb://[ip address])"));
+        } else {
+            urlNavigator->setPlaceholderText(QString());
+        }
+
         // We have to wait for DolphinUrlNavigator::sizeHint() to update which
         // happens a little bit later than when urlChanged is emitted.
         this->m_adjustSpacingTimer->start();
-    });
+    }, Qt::QueuedConnection);
 
     auto trailingSpacing = new QWidget{navigatorWidget};
     layout->addWidget(trailingSpacing);
@@ -270,7 +246,6 @@ QPushButton *DolphinNavigatorsWidgetAction::newEmptyTrashButton(const DolphinUrl
     return emptyTrashButton;
 }
 
-#if !(KIO_VERSION < QT_VERSION_CHECK(5, 78, 0))
 QPushButton *DolphinNavigatorsWidgetAction::networkFolderButton(DolphinNavigatorsWidgetAction::Side side)
 {
     int sideIndex = (side == Primary ? 0 : 1);
@@ -285,9 +260,9 @@ QPushButton *DolphinNavigatorsWidgetAction::newNetworkFolderButton(const Dolphin
     auto networkFolderButton = new QPushButton(QIcon::fromTheme(QStringLiteral("folder-add")),
                                         i18nc("@action:button", "Add Network Folder"), parent);
     networkFolderButton->setFlat(true);
+    KService::Ptr service = KService::serviceByDesktopName(QStringLiteral("org.kde.knetattach"));
     connect(networkFolderButton, &QPushButton::clicked,
-            this, [networkFolderButton]() {
-                KService::Ptr service = KService::serviceByDesktopName(QStringLiteral("org.kde.knetattach"));
+            this, [networkFolderButton, service]() {
                 auto *job = new KIO::ApplicationLauncherJob(service, networkFolderButton);
                 auto *delegate = new KNotificationJobUiDelegate;
                 delegate->setAutoErrorHandlingEnabled(true);
@@ -295,12 +270,11 @@ QPushButton *DolphinNavigatorsWidgetAction::newNetworkFolderButton(const Dolphin
                 job->start();
             });
     networkFolderButton->hide();
-    connect(urlNavigator, &KUrlNavigator::urlChanged, this, [networkFolderButton, urlNavigator]() {
-        networkFolderButton->setVisible(urlNavigator->locationUrl().scheme() == QLatin1String("remote"));
+    connect(urlNavigator, &KUrlNavigator::urlChanged, this, [networkFolderButton, urlNavigator, service]() {
+        networkFolderButton->setVisible(service && urlNavigator->locationUrl().scheme() == QLatin1String("remote"));
     });
     return networkFolderButton;
 }
-#endif
 
 QWidget *DolphinNavigatorsWidgetAction::spacing(Side side, Position position) const
 {
@@ -310,22 +284,81 @@ QWidget *DolphinNavigatorsWidgetAction::spacing(Side side, Position position) co
         return m_splitter->widget(sideIndex)->layout()->itemAt(0)->widget();
     }
     if (side == Primary) {
-#if KIO_VERSION < QT_VERSION_CHECK(5, 78, 0)
-        return m_splitter->widget(sideIndex)->layout()->itemAt(3)->widget();
-#else
         return m_splitter->widget(sideIndex)->layout()->itemAt(4)->widget();
-#endif
     }
-#if KIO_VERSION < QT_VERSION_CHECK(5, 78, 0)
-    return m_splitter->widget(sideIndex)->layout()->itemAt(2)->widget();
-#else
     return m_splitter->widget(sideIndex)->layout()->itemAt(3)->widget();
-#endif
 }
 
 void DolphinNavigatorsWidgetAction::updateText()
 {
     const int urlNavigatorsAmount = m_splitter->count() > 1 && m_splitter->widget(1)->isVisible() ?
                                     2 : 1;
-    setText(i18ncp("@action:inmenu", "Url Navigator", "Url Navigators", urlNavigatorsAmount));
+    setText(i18ncp("@action:inmenu", "Location Bar", "Location Bars", urlNavigatorsAmount));
+}
+
+DolphinNavigatorsWidgetAction::ViewGeometriesHelper::ViewGeometriesHelper
+    (QWidget *navigatorsWidget, DolphinNavigatorsWidgetAction *navigatorsWidgetAction) :
+    m_navigatorsWidget{navigatorsWidget},
+    m_navigatorsWidgetAction{navigatorsWidgetAction}
+{
+    Q_CHECK_PTR(navigatorsWidget);
+    Q_CHECK_PTR(navigatorsWidgetAction);
+}
+
+bool DolphinNavigatorsWidgetAction::ViewGeometriesHelper::eventFilter(QObject *watched, QEvent *event)
+{
+    if (event->type() == QEvent::Resize) {
+        m_navigatorsWidgetAction->adjustSpacing();
+        return false;
+    }
+    return QObject::eventFilter(watched, event);
+}
+
+void DolphinNavigatorsWidgetAction::ViewGeometriesHelper::setViewContainers(QWidget *primaryViewContainer,
+                                                                            QWidget *secondaryViewContainer)
+{
+    Q_CHECK_PTR(primaryViewContainer);
+    if (m_primaryViewContainer) {
+        m_primaryViewContainer->removeEventFilter(this);
+    }
+    primaryViewContainer->installEventFilter(this);
+    m_primaryViewContainer = primaryViewContainer;
+
+    // It is not possible to resize the secondaryViewContainer without simultaneously
+    // resizing the primaryViewContainer so we don't have to installEventFilter() here.
+    m_secondaryViewContainer = secondaryViewContainer;
+}
+
+DolphinNavigatorsWidgetAction::ViewGeometriesHelper::Geometries
+        DolphinNavigatorsWidgetAction::ViewGeometriesHelper::viewGeometries()
+{
+    Q_ASSERT(m_primaryViewContainer);
+    Geometries geometries;
+
+    // width
+    geometries.widthOfPrimary = m_primaryViewContainer->width();
+    if (m_secondaryViewContainer) {
+        geometries.widthOfSecondary = m_secondaryViewContainer->width();
+    } else {
+        geometries.widthOfSecondary = INT_MIN;
+    }
+
+    // globalX
+    if (QApplication::layoutDirection() == Qt::LeftToRight) {
+        geometries.globalXOfNavigatorsWidget = m_navigatorsWidget->mapToGlobal(QPoint(0,0)).x();
+        geometries.globalXOfPrimary = m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x();
+        geometries.globalXOfSecondary = !m_secondaryViewContainer ? INT_MIN :
+                m_secondaryViewContainer->mapToGlobal(QPoint(0,0)).x();
+    } else {
+        // When the direction is reversed, globalX does not change.
+        // For the adjustSpacing() code to work we need globalX to measure from right to left
+        // and to measure up to the rightmost point of a widget instead of the leftmost.
+        geometries.globalXOfNavigatorsWidget =
+                (-1) * (m_navigatorsWidget->mapToGlobal(QPoint(0,0)).x() + m_navigatorsWidget->width());
+        geometries.globalXOfPrimary =
+                (-1) * (m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x() + geometries.widthOfPrimary);
+        geometries.globalXOfSecondary = !m_secondaryViewContainer ? INT_MIN :
+                (-1) * (m_secondaryViewContainer->mapToGlobal(QPoint(0,0)).x() + geometries.widthOfSecondary);
+    }
+    return geometries;
 }
index ce199b3f07a2f0003b2513659a6ba3607e8c0bec..6f5f8e7af671c2bd566e17170284ba15b6b46845 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "dolphinurlnavigator.h"
 
-#include <kio_version.h>
+#include <QPointer>
 #include <QSplitter>
 #include <QTimer>
 #include <QWidgetAction>
@@ -32,7 +32,7 @@ class QPushButton;
  *      createSecondaryUrlNavigator() when necessary.
  * - Each side is a QWidget which I call NavigatorWidget with a QHBoxLayout.
  * - Each NavigatorWidget consists an UrlNavigator, an emptyTrashButton, a
- *   networkFolderButton (for frameworks >= 5.78), and spacing.
+ *   networkFolderButton, and spacing.
  * - Only the primary navigatorWidget has leading spacing. Both have trailing spacing.
  *      The spacing is there to align the UrlNavigator with its DolphinViewContainer.
  */
@@ -43,6 +43,13 @@ class DolphinNavigatorsWidgetAction : public QWidgetAction
 public:
     DolphinNavigatorsWidgetAction(QWidget *parent = nullptr);
 
+    /**
+     * Adjusts the width of the spacings used to align the UrlNavigators with ViewContainers.
+     * This can only work nicely if up-to-date geometry of ViewContainers is cached so
+     * followViewContainersGeometry() has to have been called at least once before.
+     */
+    void adjustSpacing();
+
     /**
      * The secondary UrlNavigator is only created on-demand. Such an action is not necessary
      * for the primary UrlNavigator which is created preemptively.
@@ -54,17 +61,12 @@ public:
      */
     void createSecondaryUrlNavigator();
 
-    /**
-     * Notify the primary UrlNavigator of changes in geometry of the ViewContainer it tries to be
-     * aligned with. Only call this method if there is no secondary UrlNavigator.
-     */
-    void followViewContainerGeometry(int globalXOfPrimary,   int widthOfPrimary);
     /**
      * Notify this widget of changes in geometry of the ViewContainers it tries to be
      * aligned with.
      */
-    void followViewContainersGeometry(int globalXOfPrimary,   int widthOfPrimary,
-                                      int globalXOfSecondary, int widthOfSecondary);
+    void followViewContainersGeometry(QWidget *primaryViewContainer,
+                                      QWidget *secondaryViewContainer = nullptr);
 
     bool isInToolbar() const;
 
@@ -99,13 +101,6 @@ protected:
     void deleteWidget(QWidget *widget) override;
 
 private:
-    /**
-     * Adjusts the width of the spacings used to align the UrlNavigators with ViewContainers.
-     * This can only work nicely if up-to-date geometry of ViewContainers is cached so
-     * followViewContainersGeometry() has to have been called at least once before.
-     */
-    void adjustSpacing();
-
     /**
      * In Left-to-right languages the Primary side will be the left one.
      */
@@ -126,14 +121,13 @@ private:
     /**
      * Creates a new empty trash button.
      * @param urlNavigator Only when this UrlNavigator shows the trash directory
-     *                     will the the button be visible.
+     *                     will the button be visible.
      * @param parent       Aside from the usual QObject deletion mechanisms,
      *                     this parameter influences the positioning of dialog windows
      *                     pertaining to this trash button.
      */
     QPushButton *newEmptyTrashButton(const DolphinUrlNavigator *urlNavigator, QWidget *parent) const;
 
-#if !(KIO_VERSION < QT_VERSION_CHECK(5, 78, 0))
     /**
      * Used to retrieve the networkFolderButtons for the navigatorWidgets on
      * both sides.
@@ -147,7 +141,6 @@ private:
      * @param parent       The object that should be the button's parent.
      */
     QPushButton *newNetworkFolderButton(const DolphinUrlNavigator *urlNavigator, QWidget *parent) const;
-#endif
 
     enum Position {
         Leading,
@@ -175,12 +168,54 @@ private:
      */
     std::unique_ptr<QTimer> m_adjustSpacingTimer;
 
-    // cached values
-    int m_globalXOfSplitter;
-    int m_globalXOfPrimary;
-    int m_widthOfPrimary;
-    int m_globalXOfSecondary;
-    int m_widthOfSecondary;
+    /**
+     * Extracts the geometry information needed by adjustSpacing() from
+     * ViewContainers. They are also monitored for size changes which
+     * will lead to adjustSpacing() calls.
+     */
+    class ViewGeometriesHelper : public QObject
+    {
+    public:
+        /**
+         * @param navigatorsWidget       The QWidget of the navigatorsWidgetAction.
+         * @param navigatorsWidgetAction is only used to call adjustSpacing() whenever that is
+         *                               deemed necessary.
+         */
+        ViewGeometriesHelper(QWidget *navigatorsWidget, DolphinNavigatorsWidgetAction *navigatorsWidgetAction);
+
+        /**
+         * Calls m_navigatorsWidgetAction::adjustSpacing() when a watched object is resized.
+         */
+        bool eventFilter(QObject *watched, QEvent *event) override;
+
+        /**
+         * Sets the ViewContainers whose geometry is obtained when viewGeometries() is called.
+         */
+        void setViewContainers(QWidget *primaryViewContainer,
+                               QWidget *secondaryViewContainer = nullptr);
+
+        struct Geometries {
+            int globalXOfNavigatorsWidget;
+            int globalXOfPrimary;
+            int widthOfPrimary;
+            int globalXOfSecondary;
+            int widthOfSecondary;
+        };
+        /**
+         * @return a Geometries struct that contains values adjustSpacing() requires.
+         */
+        Geometries viewGeometries();
+
+    private:
+        QWidget *m_navigatorsWidget;
+        /** Is only used to call adjustSpacing() whenever that is deemed necessary. */
+        DolphinNavigatorsWidgetAction *m_navigatorsWidgetAction;
+
+        QPointer<QWidget> m_primaryViewContainer;
+        QPointer<QWidget> m_secondaryViewContainer;
+    };
+
+    ViewGeometriesHelper m_viewGeometriesHelper;
 };
 
 #endif // DOLPHINNAVIGATORSWIDGETACTION_H
index 75784b522dbc4a2fb45884b80276cd527f849c17..37ffe9070ce32c31f007ba600f34a39e1fd31052 100644 (file)
@@ -17,7 +17,7 @@
 #include "views/dolphinview.h"
 #include "views/dolphinviewactionhandler.h"
 
-#include <KAboutData>
+#include <KPluginMetaData>
 #include <KActionCollection>
 #include <KAuthorized>
 #include <KConfigGroup>
 #include <QStandardPaths>
 #include <QTextDocument>
 
-K_PLUGIN_FACTORY(DolphinPartFactory, registerPlugin<DolphinPart>();)
+K_PLUGIN_CLASS_WITH_JSON(DolphinPart, "dolphinpart.json")
 
-DolphinPart::DolphinPart(QWidget* parentWidget, QObject* parent, const QVariantList& args)
+DolphinPart::DolphinPart(QWidget* parentWidget, QObject* parent,
+                         const KPluginMetaData& metaData, const QVariantList& args)
     : KParts::ReadOnlyPart(parent)
       ,m_openTerminalAction(nullptr)
       ,m_removeAction(nullptr)
 {
     Q_UNUSED(args)
-    setComponentData(*createAboutData(), false);
+    setMetaData(metaData);
+
     m_extension = new DolphinPartBrowserExtension(this);
 
     // make sure that other apps using this part find Dolphin's view-file-columns icons
@@ -141,7 +143,7 @@ DolphinPart::DolphinPart(QWidget* parentWidget, QObject* parent, const QVariantL
     // TODO there was a "always open a new window" (when clicking on a directory) setting in konqueror
     // (sort of spacial navigation)
 
-    loadPlugins(this, this, componentData());
+    loadPlugins(this, this, componentName());
 }
 
 DolphinPart::~DolphinPart()
@@ -163,7 +165,7 @@ void DolphinPart::createActions()
 
     QAction* selectItemsMatching = actionCollection()->addAction(QStringLiteral("select_items_matching"));
     selectItemsMatching->setText(i18nc("@action:inmenu Edit", "Select Items Matching..."));
-    actionCollection()->setDefaultShortcut(selectItemsMatching, Qt::CTRL + Qt::Key_S);
+    actionCollection()->setDefaultShortcut(selectItemsMatching, Qt::CTRL | Qt::Key_S);
     connect(selectItemsMatching, &QAction::triggered, this, &DolphinPart::slotSelectItemsMatchingPattern);
 
     QAction* unselectItemsMatching = actionCollection()->addAction(QStringLiteral("unselect_items_matching"));
@@ -178,7 +180,7 @@ void DolphinPart::createActions()
 
     QAction* invertSelection = actionCollection()->addAction(QStringLiteral("invert_selection"));
     invertSelection->setText(i18nc("@action:inmenu Edit", "Invert Selection"));
-    actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL + Qt::SHIFT + Qt::Key_A);
+    actionCollection()->setDefaultShortcut(invertSelection, Qt::CTRL | Qt::SHIFT | Qt::Key_A);
     connect(invertSelection, &QAction::triggered, m_view, &DolphinView::invertSelection);
 
     // View menu: all done by DolphinViewActionHandler
@@ -281,9 +283,16 @@ void DolphinPart::updatePasteAction()
     Q_EMIT m_extension->setActionText( "paste", pasteInfo.second );
 }
 
-KAboutData* DolphinPart::createAboutData()
+QString DolphinPart::urlToLocalFilePath(const QUrl &url)
 {
-    return new KAboutData(QStringLiteral("dolphinpart"), i18nc("@title", "Dolphin Part"), QStringLiteral("0.1"));
+    KIO::StatJob* statJob = KIO::mostLocalUrl(url);
+    KJobWidgets::setWindow(statJob, widget());
+    statJob->exec();
+    QUrl localUrl = statJob->mostLocalUrl();
+    if (localUrl.isLocalFile()) {
+        return localUrl.toLocalFile();
+    }
+    return QString();
 }
 
 bool DolphinPart::openUrl(const QUrl &url)
@@ -296,7 +305,8 @@ bool DolphinPart::openUrl(const QUrl &url)
     if (m_view->url() == url && !reload) { // DolphinView won't do anything in that case, so don't emit started
         return true;
     }
-    setUrl(url); // remember it at the KParts level
+    setUrl(url); // remember url at the KParts level
+    setLocalFilePath(urlToLocalFilePath(url)); // remember local path at the KParts level
     QUrl visibleUrl(url);
     if (!m_nameFilter.isEmpty()) {
         visibleUrl.setPath(visibleUrl.path() + '/' + m_nameFilter);
@@ -313,7 +323,7 @@ bool DolphinPart::openUrl(const QUrl &url)
         m_view->reload();
     // Disable "Find File" and "Open Terminal" actions for non-file URLs,
     // e.g. ftp, smb, etc. #279283
-    const bool isLocalUrl = url.isLocalFile();
+    const bool isLocalUrl = !(localFilePath().isEmpty());
     m_findFileAction->setEnabled(isLocalUrl);
     if (m_openTerminalAction) {
         m_openTerminalAction->setEnabled(isLocalUrl);
@@ -545,16 +555,25 @@ void DolphinPart::setNameFilter(const QString& nameFilter)
     // TODO save/restore name filter in saveState/restoreState like KonqDirPart did in kde3?
 }
 
+QString DolphinPart::localFilePathOrHome() const
+{
+    const QString localPath = localFilePath();
+    if (!localPath.isEmpty()) {
+        return localPath;
+    }
+    return QDir::homePath();
+}
+
 void DolphinPart::slotOpenTerminal()
 {
-    KToolInvocation::invokeTerminal(QString(), KParts::ReadOnlyPart::localFilePath());
+    KToolInvocation::invokeTerminal(QString(), localFilePathOrHome());
 }
 
 void DolphinPart::slotFindFile()
 {
     QMenu searchTools;
     KMoreToolsMenuFactory("dolphin/search-tools").fillMenuFromGroupingNames(
-        &searchTools, { "files-find" }, QUrl::fromLocalFile(KParts::ReadOnlyPart::localFilePath())
+        &searchTools, { "files-find" }, QUrl::fromLocalFile(localFilePathOrHome())
     );
     QList<QAction*> actions = searchTools.actions();
     if (!(actions.isEmpty())) {
similarity index 96%
rename from src/dolphinpart.desktop
rename to src/dolphinpart.desktop.in
index 0e7efd8e38532591b0f57dcfc110732688fd2f95..71690ead950bc2fd78d061f57883d211252df7e9 100644 (file)
@@ -51,13 +51,18 @@ Name[zh_CN]=Dolphin 视图
 Name[zh_TW]=Dolphin 檢視
 MimeType=inode/directory;
 X-KDE-ServiceTypes=KParts/ReadOnlyPart,Browser/View
-X-KDE-Library=dolphinpart
+X-KDE-Library=kf5/parts/dolphinpart
 #X-KDE-BrowserView-Args=Icon
 X-KDE-BrowserView-HideFromMenus=true
 X-KDE-BrowserView-Built-Into=konqueror
-Icon=view-icon
+Icon=view-list-icons
 InitialPreference=7
 
+X-KDE-PluginInfo-Name=dolphinpart
+X-KDE-PluginInfo-Version=@DOLPHIN_VERSION@
+X-KDE-PluginInfo-License=LGPL v2+
+
+
 # Provide info about the view modes using the Actions mechanism so that KService parses it.
 # Konqueror then queries KService to get hold of the translated texts for the view modes
 Actions=icons;details;compact;
index 3d613c2767761c8048f863b7a627d960a26cc048..a2088d4a2febec40530b95e088bb9b40b9a1b822 100644 (file)
@@ -20,7 +20,6 @@ class DolphinPartBrowserExtension;
 class DolphinRemoteEncoding;
 class KDirLister;
 class DolphinView;
-class KAboutData;
 class DolphinRemoveAction;
 
 class DolphinPart : public KParts::ReadOnlyPart
@@ -40,11 +39,10 @@ class DolphinPart : public KParts::ReadOnlyPart
     Q_PROPERTY( QList<QUrl> filesToSelect READ filesToSelect WRITE setFilesToSelect )
 
 public:
-    explicit DolphinPart(QWidget* parentWidget, QObject* parent, const QVariantList& args);
+    explicit DolphinPart(QWidget* parentWidget, QObject* parent,
+                         const KPluginMetaData& metaData, const QVariantList& args);
     ~DolphinPart() override;
 
-    static KAboutData* createAboutData();
-
     /**
      * Standard KParts::ReadOnlyPart openUrl method.
      * Called by Konqueror to view a directory in DolphinPart.
@@ -220,6 +218,8 @@ private:
 
     void openSelectionDialog(const QString& title, const QString& text,
                              bool selectItems);
+    QString urlToLocalFilePath(const QUrl &url);
+    QString localFilePathOrHome() const;
 
 private:
     DolphinView* m_view;
index df152fb20e4a30ebba0e234c747321f2ff3e7eeb..a65cf685ee448ed3d8f2414b656016ce887c4d26 100644 (file)
@@ -1,5 +1,6 @@
-<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<kpartgui name="dolphinpart" version="15" translationDomain="dolphin">
+<?xml version="1.0"?>
+<!DOCTYPE gui SYSTEM "kpartgui.dtd">
+<gui name="dolphinpart" version="15" translationDomain="dolphin">
  <MenuBar>
   <Menu name="edit"><text>&amp;Edit</text>
    <Action name="new_menu"/>
@@ -64,4 +65,4 @@
    <Action name="deletefile" />
   </disable>
 </State>
-</kpartgui>
+</gui>
index 138822cfd36a009c254f465d055956d93b49dbe0..36049fa9744605986e63fbf13fcf0178c9ede253 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta <emmanuelpescosta099@gmail.com>
+ * SPDX-FileCopyrightText: 2020 Felix Ernst <fe.a.ernst@gmail.com>
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
@@ -8,13 +9,17 @@
 
 #include "dolphin_generalsettings.h"
 #include "dolphinviewcontainer.h"
+#include "global.h"
 
+#include <QVariantAnimation>
 #include <QSplitter>
 #include <QGridLayout>
 #include <QWidgetAction>
+#include <QStyle>
 
 DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl, QWidget* parent) :
     QWidget(parent),
+    m_expandingContainer{nullptr},
     m_primaryViewActive(true),
     m_splitViewEnabled(false),
     m_active(true)
@@ -38,7 +43,6 @@ DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl,
             this, &DolphinTabPage::slotViewUrlRedirection);
 
     m_splitter->addWidget(m_primaryViewContainer);
-    m_primaryViewContainer->installEventFilter(this);
     m_primaryViewContainer->show();
 
     if (secondaryUrl.isValid() || GeneralSettings::splitView()) {
@@ -48,7 +52,6 @@ DolphinTabPage::DolphinTabPage(const QUrl &primaryUrl, const QUrl &secondaryUrl,
         const QUrl& url = secondaryUrl.isValid() ? secondaryUrl : primaryUrl;
         m_secondaryViewContainer = createViewContainer(url);
         m_splitter->addWidget(m_secondaryViewContainer);
-        m_secondaryViewContainer->installEventFilter(this);
         m_secondaryViewContainer->show();
     }
 
@@ -65,12 +68,24 @@ bool DolphinTabPage::splitViewEnabled() const
     return m_splitViewEnabled;
 }
 
-void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
+void DolphinTabPage::setSplitViewEnabled(bool enabled, Animated animated, const QUrl &secondaryUrl)
 {
     if (m_splitViewEnabled != enabled) {
         m_splitViewEnabled = enabled;
+        if (animated == WithAnimation && (
+            style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) < 1 ||
+            GlobalConfig::animationDurationFactor() <= 0.0)) {
+            animated = WithoutAnimation;
+        }
+        if (m_expandViewAnimation) {
+            m_expandViewAnimation->stop(); // deletes because of QAbstractAnimation::DeleteWhenStopped.
+            if (animated == WithoutAnimation) {
+                slotAnimationFinished();
+            }
+        }
 
         if (enabled) {
+            QList<int> splitterSizes = m_splitter->sizes();
             const QUrl& url = (secondaryUrl.isEmpty()) ? m_primaryViewContainer->url() : secondaryUrl;
             m_secondaryViewContainer = createViewContainer(url);
 
@@ -81,11 +96,19 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
             }
             m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator);
             m_navigatorsWidget->setSecondaryNavigatorVisible(true);
+            m_navigatorsWidget->followViewContainersGeometry(m_primaryViewContainer,
+                                                             m_secondaryViewContainer);
 
             m_splitter->addWidget(m_secondaryViewContainer);
-            m_secondaryViewContainer->installEventFilter(this);
-            m_secondaryViewContainer->show();
             m_secondaryViewContainer->setActive(true);
+
+            if (animated == WithAnimation) {
+                m_secondaryViewContainer->setMinimumWidth(1);
+                splitterSizes.append(1);
+                m_splitter->setSizes(splitterSizes);
+                startExpandViewAnimation(m_secondaryViewContainer);
+            }
+            m_secondaryViewContainer->show();
         } else {
             m_navigatorsWidget->setSecondaryNavigatorVisible(false);
             m_secondaryViewContainer->disconnectUrlNavigator();
@@ -117,8 +140,19 @@ void DolphinTabPage::setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl)
                 }
             }
             m_primaryViewContainer->setActive(true);
-            view->close();
-            view->deleteLater();
+            m_navigatorsWidget->followViewContainersGeometry(m_primaryViewContainer, nullptr);
+
+            if (animated == WithoutAnimation) {
+                view->close();
+                view->deleteLater();
+            } else {
+                // Kill it but keep it as a zombie for the closing animation.
+                m_secondaryViewContainer = nullptr;
+                view->blockSignals(true);
+                view->view()->blockSignals(true);
+                view->setDisabled(true);
+                startExpandViewAnimation(m_primaryViewContainer);
+            }
         }
     }
 }
@@ -167,7 +201,8 @@ void DolphinTabPage::connectNavigators(DolphinNavigatorsWidgetAction *navigators
         auto secondaryNavigator = navigatorsWidget->secondaryUrlNavigator();
         m_secondaryViewContainer->connectUrlNavigator(secondaryNavigator);
     }
-    resizeNavigators();
+    m_navigatorsWidget->followViewContainersGeometry(m_primaryViewContainer,
+                                                     m_secondaryViewContainer);
 }
 
 void DolphinTabPage::disconnectNavigators()
@@ -179,15 +214,6 @@ void DolphinTabPage::disconnectNavigators()
     }
 }
 
-bool DolphinTabPage::eventFilter(QObject *watched, QEvent *event)
-{
-    if (event->type() == QEvent::Resize && m_navigatorsWidget) {
-        resizeNavigators();
-        return false;
-    }
-    return QWidget::eventFilter(watched, event);
-}
-
 void DolphinTabPage::insertNavigatorsWidget(DolphinNavigatorsWidgetAction* navigatorsWidget)
 {
     QGridLayout *gridLayout = static_cast<QGridLayout *>(layout());
@@ -201,22 +227,6 @@ void DolphinTabPage::insertNavigatorsWidget(DolphinNavigatorsWidgetAction* navig
     }
 }
 
-
-void DolphinTabPage::resizeNavigators() const
-{
-    if (!m_splitViewEnabled) {
-        m_navigatorsWidget->followViewContainerGeometry(
-                m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
-                m_primaryViewContainer->width());
-    } else {
-        m_navigatorsWidget->followViewContainersGeometry(
-                m_primaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
-                m_primaryViewContainer->width(),
-                m_secondaryViewContainer->mapToGlobal(QPoint(0,0)).x(),
-                m_secondaryViewContainer->width());
-    }
-}
-
 void DolphinTabPage::markUrlsAsSelected(const QList<QUrl>& urls)
 {
     m_primaryViewContainer->view()->markUrlsAsSelected(urls);
@@ -285,7 +295,7 @@ void DolphinTabPage::restoreState(const QByteArray& state)
 
     bool isSplitViewEnabled = false;
     stream >> isSplitViewEnabled;
-    setSplitViewEnabled(isSplitViewEnabled);
+    setSplitViewEnabled(isSplitViewEnabled, WithoutAnimation);
 
     QUrl primaryUrl;
     stream >> primaryUrl;
@@ -329,7 +339,7 @@ void DolphinTabPage::restoreStateV1(const QByteArray& state)
 
     bool isSplitViewEnabled = false;
     stream >> isSplitViewEnabled;
-    setSplitViewEnabled(isSplitViewEnabled);
+    setSplitViewEnabled(isSplitViewEnabled, WithoutAnimation);
 
     QUrl primaryUrl;
     stream >> primaryUrl;
@@ -372,6 +382,72 @@ void DolphinTabPage::setActive(bool active)
     activeViewContainer()->setActive(active);
 }
 
+void DolphinTabPage::slotAnimationFinished()
+{
+    for (int i = 0; i < m_splitter->count(); ++i) {
+        QWidget *viewContainer = m_splitter->widget(i);
+        if (viewContainer != m_primaryViewContainer &&
+            viewContainer != m_secondaryViewContainer) {
+            viewContainer->close();
+            viewContainer->deleteLater();
+        }
+    }
+    for (int i = 0; i < m_splitter->count(); ++i) {
+        QWidget *viewContainer = m_splitter->widget(i);
+        viewContainer->setMinimumWidth(viewContainer->minimumSizeHint().width());
+    }
+    m_expandingContainer = nullptr;
+}
+
+void DolphinTabPage::slotAnimationValueChanged(const QVariant& value)
+{
+    Q_CHECK_PTR(m_expandingContainer);
+    const int indexOfExpandingContainer = m_splitter->indexOf(m_expandingContainer);
+    int indexOfNonExpandingContainer = -1;
+    if (m_expandingContainer == m_primaryViewContainer) {
+        indexOfNonExpandingContainer = m_splitter->indexOf(m_secondaryViewContainer);
+    } else {
+        indexOfNonExpandingContainer = m_splitter->indexOf(m_primaryViewContainer);
+    }
+    std::vector<QWidget *> widgetsToRemove;
+    const QList<int> oldSplitterSizes = m_splitter->sizes();
+    QList<int> newSplitterSizes{oldSplitterSizes};
+    int expansionWidthNeeded = value.toInt() - oldSplitterSizes.at(indexOfExpandingContainer);
+
+    // Reduce the size of the other widgets to make space for the expandingContainer.
+    for (int i = m_splitter->count() - 1; i >= 0; --i) {
+        if (m_splitter->widget(i) == m_primaryViewContainer ||
+            m_splitter->widget(i) == m_secondaryViewContainer) {
+            continue;
+        }
+        newSplitterSizes[i] = oldSplitterSizes.at(i) - expansionWidthNeeded;
+        expansionWidthNeeded = 0;
+        if (indexOfNonExpandingContainer != -1) {
+            // Make sure every zombie container is at least slightly reduced in size
+            // so it doesn't seem like they are here to stay.
+            newSplitterSizes[i]--;
+            newSplitterSizes[indexOfNonExpandingContainer]++;
+        }
+        if (newSplitterSizes.at(i) <= 0) {
+            expansionWidthNeeded -= newSplitterSizes.at(i);
+            newSplitterSizes[i] = 0;
+            widgetsToRemove.emplace_back(m_splitter->widget(i));
+        }
+    }
+    if (expansionWidthNeeded > 1 && indexOfNonExpandingContainer != -1) {
+        Q_ASSERT(m_splitViewEnabled);
+        newSplitterSizes[indexOfNonExpandingContainer] -= expansionWidthNeeded;
+    }
+    newSplitterSizes[indexOfExpandingContainer] = value.toInt();
+    m_splitter->setSizes(newSplitterSizes);
+    while (!widgetsToRemove.empty()) {
+        widgetsToRemove.back()->close();
+        widgetsToRemove.back()->deleteLater();
+        widgetsToRemove.pop_back();
+    }
+}
+
+
 void DolphinTabPage::slotViewActivated()
 {
     const DolphinView* oldActiveView = activeViewContainer()->view();
@@ -441,3 +517,33 @@ DolphinViewContainer* DolphinTabPage::createViewContainer(const QUrl& url) const
 
     return container;
 }
+
+void DolphinTabPage::startExpandViewAnimation(DolphinViewContainer *expandingContainer)
+{
+    Q_CHECK_PTR(expandingContainer);
+    Q_ASSERT(expandingContainer == m_primaryViewContainer ||
+             expandingContainer == m_secondaryViewContainer);
+    m_expandingContainer = expandingContainer;
+
+    m_expandViewAnimation = new QVariantAnimation(m_splitter);
+    m_expandViewAnimation->setDuration(2 *
+            style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) *
+            GlobalConfig::animationDurationFactor());
+    for (int i = 0; i < m_splitter->count(); ++i) {
+        m_splitter->widget(i)->setMinimumWidth(1);
+    }
+    connect(m_expandViewAnimation, &QAbstractAnimation::finished,
+            this, &DolphinTabPage::slotAnimationFinished);
+    connect(m_expandViewAnimation, &QVariantAnimation::valueChanged,
+            this, &DolphinTabPage::slotAnimationValueChanged);
+
+    m_expandViewAnimation->setStartValue(expandingContainer->width());
+    if (m_splitViewEnabled) { // A new viewContainer is being opened.
+        m_expandViewAnimation->setEndValue(m_splitter->width() / 2);
+        m_expandViewAnimation->setEasingCurve(QEasingCurve::OutCubic);
+    } else { // A viewContainer is being closed.
+        m_expandViewAnimation->setEndValue(m_splitter->width());
+        m_expandViewAnimation->setEasingCurve(QEasingCurve::InCubic);
+    }
+    m_expandViewAnimation->start(QAbstractAnimation::DeleteWhenStopped);
+}
index 63a246328f074bdfa4eb78355ecd8ddd51ba1703..a3659aa184fc4dce62ba8935a6beb9fb5443ce8a 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * SPDX-FileCopyrightText: 2014 Emmanuel Pescosta <emmanuelpescosta099@gmail.com>
+ * SPDX-FileCopyrightText: 2020 Felix Ernst <fe.a.ernst@gmail.com>
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
 class DolphinNavigatorsWidgetAction;
 class DolphinViewContainer;
 class QSplitter;
+class QVariantAnimation;
 class KFileItemList;
 
+enum Animated {
+    WithAnimation,
+    WithoutAnimation
+};
+
 class DolphinTabPage : public QWidget
 {
     Q_OBJECT
@@ -36,9 +43,15 @@ public:
     /**
      * Enables or disables the split view mode.
      *
-     * If \a enabled is true, it creates a secondary view with the url of the primary view.
+     * @param enabled      If true, creates a secondary viewContainer in this tab.
+     *                     Otherwise deletes it.
+     * @param animated     Decides wether the effects of this method call should
+     *                     happen instantly or be transitioned to smoothly.
+     * @param secondaryUrl If \p enabled is true, the new viewContainer will be opened at this
+     *                     parameter. The default value will set the Url of the new viewContainer
+     *                     to be the same as the existing one.
      */
-    void setSplitViewEnabled(bool enabled, const QUrl &secondaryUrl = QUrl());
+    void setSplitViewEnabled(bool enabled, Animated animated, const QUrl &secondaryUrl = QUrl());
 
     /**
      * @return The primary view container.
@@ -80,11 +93,6 @@ public:
      */
     void disconnectNavigators();
 
-    /**
-     * Calls resizeNavigators() when a watched object is resized.
-     */
-    bool eventFilter(QObject *watched, QEvent *event) override;
-
     void insertNavigatorsWidget(DolphinNavigatorsWidgetAction *navigatorsWidget);
 
     /**
@@ -147,6 +155,17 @@ signals:
     void splitterMoved(int pos, int index);
 
 private slots:
+    /**
+     * Deletes all zombie viewContainers that were used for the animation
+     * and resets the minimum size of the others to a sane value.
+     */
+    void slotAnimationFinished();
+
+    /**
+     * This method is called for every frame of the m_expandViewAnimation.
+     */
+    void slotAnimationValueChanged(const QVariant &value);
+
     /**
      * Handles the view activated event.
      *
@@ -170,6 +189,16 @@ private:
      */
     DolphinViewContainer* createViewContainer(const QUrl& url) const;
 
+    /**
+     * Starts an animation that transitions between split view mode states.
+     *
+     * One of the viewContainers is always being expanded when toggling so
+     * this method can animate both opening and closing of viewContainers.
+     * @param expandingContainer The container that will increase in size
+     *                           over the course of the animation.
+     */
+    void startExpandViewAnimation(DolphinViewContainer *expandingContainer);
+
 private:
     QSplitter* m_splitter;
 
@@ -177,6 +206,9 @@ private:
     QPointer<DolphinViewContainer> m_primaryViewContainer;
     QPointer<DolphinViewContainer> m_secondaryViewContainer;
 
+    DolphinViewContainer *m_expandingContainer;
+    QPointer<QVariantAnimation> m_expandViewAnimation;
+
     bool m_primaryViewActive;
     bool m_splitViewEnabled;
     bool m_active;
index da8f76d7c4fbf56c648f9bb449cf5ae23cbad0f4..d61a9f74f5a5cb4ee086c4cc2583bdcf4d2b388f 100644 (file)
@@ -152,10 +152,14 @@ void DolphinTabWidget::openNewActivatedTab()
 void DolphinTabWidget::openNewActivatedTab(const QUrl& primaryUrl, const QUrl& secondaryUrl)
 {
     openNewTab(primaryUrl, secondaryUrl);
-    setCurrentIndex(count() - 1);
+    if (GeneralSettings::openNewTabAfterLastTab()) {
+        setCurrentIndex(count() - 1);
+    } else {
+        setCurrentIndex(currentIndex() + 1);
+    }
 }
 
-void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryUrl, TabPlacement tabPlacement)
+void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryUrl)
 {
     QWidget* focusWidget = QApplication::focusWidget();
 
@@ -166,7 +170,7 @@ void DolphinTabWidget::openNewTab(const QUrl& primaryUrl, const QUrl& secondaryU
     connect(tabPage, &DolphinTabPage::activeViewUrlChanged,
             this, &DolphinTabWidget::tabUrlChanged);
     int newTabIndex = -1;
-    if (tabPlacement == AfterCurrentTab) {
+    if (!GeneralSettings::openNewTabAfterLastTab()) {
         newTabIndex = currentIndex() + 1;
     }
     insertTab(newTabIndex, tabPage, QIcon() /* loaded in tabInserted */, tabName(tabPage));
index 4a1b9d99c1063101763449d020315f8cf8ace82f..fbfe283026bc63549e5096a7b71af2fc34eb3dcf 100644 (file)
@@ -21,19 +21,6 @@ class DolphinTabWidget : public QTabWidget
     Q_OBJECT
 
 public:
-    /**
-     * @brief Controls where tabs are placed
-     */
-    enum TabPlacement {
-        /**
-          * The new tab is placed after the current tab
-          */
-        AfterCurrentTab,
-        /**
-          * The new tab is placed after the last tab
-          */
-        AfterLastTab
-    };
 
     /**
      * @param navigatorsWidget The navigatorsWidget which is always going to be connected
@@ -118,11 +105,9 @@ public slots:
 
     /**
      * Opens a new tab in the background showing the URL \a primaryUrl and the
-     * optional URL \a secondaryUrl. \a tabPlacement controls where the new tab
-     * is placed.
+     * optional URL \a secondaryUrl.
      */
-    void openNewTab(const QUrl &primaryUrl, const QUrl &secondaryUrl = QUrl(),
-                    DolphinTabWidget::TabPlacement tabPlacement = AfterLastTab);
+    void openNewTab(const QUrl &primaryUrl, const QUrl &secondaryUrl = QUrl());
 
     /**
      * Opens each directory in \p dirs in a separate tab. If \a splitView is set,
index 6c51497b1c51f2b141230426dc5b112b2a360392..e749abae09616a80e44488198206311b8b6ce85f 100644 (file)
@@ -1,5 +1,6 @@
-<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<kpartgui name="dolphin" version="33">
+<?xml version="1.0"?>
+<!DOCTYPE gui SYSTEM "kpartgui.dtd">
+<gui name="dolphin" version="33">
     <MenuBar>
         <Menu name="file">
             <Action name="new_menu" />
@@ -27,6 +28,7 @@
             <Action name="copy_location" />
             <Action name="edit_paste" />
             <Separator />
+            <Action name="show_filter_bar" />
             <Action name="edit_find" />
             <Separator />
             <Action name="copy_to_inactive_split_view" />
@@ -65,7 +67,6 @@
             <Action name="closed_tabs" />
         </Menu>
         <Menu name="tools">
-            <Action name="show_filter_bar" />
             <Action name="open_preferred_search_tool" />
             <Action name="open_terminal" />
             <Action name="focus_terminal_panel"/>
         <Action name="split_view" />
         <Action name="split_stash" />
         <Action name="toggle_search" />
+        <Action name="toggle_filter" />
     </ToolBar>
     <ActionProperties scheme="Default">
         <Action priority="0" name="go_back"/>
         <Action priority="0" name="edit_copy"/>
         <Action priority="0" name="edit_paste"/>
         <Action priority="0" name="toggle_search"/>
+        <Action priority="0" name="toggle_filter"/>
     </ActionProperties>
-</kpartgui>
+</gui>
index 1dfe5420f1df6d8d31464351575e6c5bd8bd1fd5..d8d325bb43530e588b7ff743cf25c926df0a9d4d 100644 (file)
@@ -101,6 +101,16 @@ void DolphinUrlNavigator::setVisualState(const VisualState& visualState)
     }
 }
 
+void DolphinUrlNavigator::clearText() const
+{
+    editor()->lineEdit()->clear();
+}
+
+void DolphinUrlNavigator::setPlaceholderText(const QString &text)
+{
+    editor()->lineEdit()->setPlaceholderText(text);
+}
+
 void DolphinUrlNavigator::slotReturnPressed()
 {
     if (!GeneralSettings::editableUrl()) {
index 9bcc32b4d1463d1cfbcc37a31dd3068b92cdb312..1962e2f06269c994bd0c30c4eda9e03fc2c0383f 100644 (file)
@@ -66,6 +66,16 @@ public:
      */
     void setVisualState(const VisualState &visualState);
 
+    /**
+     * Clears the text in the text field
+     */
+    void clearText() const;
+
+    /**
+     * Displays placeholder text in the URL navigator
+     */
+    void setPlaceholderText(const QString &text);
+
 public slots:
     /**
      * Switches to "breadcrumb" mode if the editable mode is not set to be
index 1018c7d4c496a3a5e9bce32bf9601ef5bba91aa7..3d17a733bca243110621a75069adbd2c5c5ec146 100644 (file)
@@ -10,6 +10,7 @@
 #include "dolphindebug.h"
 #include "dolphinmainwindowinterface.h"
 
+#include <KConfigWatcher>
 #include <KDialogJobUiDelegate>
 #include <KIO/ApplicationLauncherJob>
 #include <KService>
@@ -138,3 +139,29 @@ QVector<QPair<QSharedPointer<OrgKdeDolphinMainWindowInterface>, QStringList>> Do
 
     return dolphinInterfaces;
 }
+
+double GlobalConfig::animationDurationFactor()
+{
+    if (s_animationDurationFactor >= 0.0) {
+        return s_animationDurationFactor;
+    }
+    // This is the first time this method is called.
+    auto kdeGlobalsConfig = KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("KDE"));
+    updateAnimationDurationFactor(kdeGlobalsConfig, {"AnimationDurationFactor"});
+
+    KConfigWatcher::Ptr configWatcher = KConfigWatcher::create(KSharedConfig::openConfig());
+    connect(configWatcher.data(), &KConfigWatcher::configChanged,
+            &GlobalConfig::updateAnimationDurationFactor);
+    return s_animationDurationFactor;
+}
+
+void GlobalConfig::updateAnimationDurationFactor(const KConfigGroup &group, const QByteArrayList &names)
+{
+    if (group.name() == QLatin1String("KDE") &&
+        names.contains(QByteArrayLiteral("AnimationDurationFactor"))) {
+        s_animationDurationFactor = std::max(0.0,
+                group.readEntry("AnimationDurationFactor", 1.0));
+    }
+}
+
+double GlobalConfig::s_animationDurationFactor = -1.0;
index 65247351a7476d1ee0d9a219251b60a3ffd42c75..088e9c5b66b20f58e2dc686f801ea3e899493171 100644 (file)
@@ -11,6 +11,7 @@
 #include <QUrl>
 #include <QWidget>
 
+class KConfigGroup;
 class OrgKdeDolphinMainWindowInterface;
 
 namespace Dolphin {
@@ -52,4 +53,26 @@ namespace Dolphin {
     const int LAYOUT_SPACING_SMALL = 2;
 }
 
+class GlobalConfig : public QObject
+{
+    Q_OBJECT
+
+public:
+    GlobalConfig() = delete;
+
+    /**
+     * @return a value from the global KDE config that should be
+     *         multiplied with every animation duration once.
+     *         0.0 is returned if animations are globally turned off.
+     *         1.0 is the default value.
+     */
+    static double animationDurationFactor();
+
+private:
+    static void updateAnimationDurationFactor(const KConfigGroup &group, const QByteArrayList &names);
+
+private:
+    static double s_animationDurationFactor;
+};
+
 #endif //GLOBAL_H
index 69a40ddf3641d8626e498c504fc7ea334fbcae37..1b38176cc29c95fbc245e8268e9c1ca1a1f92be0 100644 (file)
@@ -47,41 +47,50 @@ QString KFileItemListWidgetInformant::roleText(const QByteArray& role,
 {
     QString text;
     const QVariant roleValue = values.value(role);
+    QLocale local;
+    KFormat formatter(local);
 
     // Implementation note: In case if more roles require a custom handling
     // use a hash + switch for a linear runtime.
 
+    auto formatDate = [formatter, local](const QDateTime& time) {
+        if (DetailsModeSettings::useShortRelativeDates()) {
+            return formatter.formatRelativeDateTime(time, QLocale::ShortFormat);
+        } else {
+            return local.toString(time, QLocale::ShortFormat);
+        }
+    };
+
     if (role == "size") {
         if (values.value("isDir").toBool()) {
-            // The item represents a directory.
-            if (!roleValue.isNull()) {
-                const int count = values.value("count").toInt();
-                if (count > 0) {
-                    if (DetailsModeSettings::directorySizeCount()) {
-                        //  Show the number of sub directories instead of the file size of the directory.
-                        text = i18ncp("@item:intable", "%1 item", "%1 items", count);
-                    } else {
-                        // if we have directory size available
-                        if (roleValue != -1) {
-                            const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
-                            text = KFormat().formatByteSize(size);
-                        }
-                    }
+            if (!roleValue.isNull() && roleValue != -1) {
+                // The item represents a directory.
+                if (DetailsModeSettings::directorySizeCount()) {
+                    //  Show the number of sub directories instead of the file size of the directory.
+                    const int count = values.value("count").toInt();
+                    text = i18ncp("@item:intable", "%1 item", "%1 items", count);
+                } else {
+                    // if we have directory size available
+                    const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
+                    text = formatter.formatByteSize(size);
                 }
             }
         } else {
             const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
-            text = KFormat().formatByteSize(size);
+            text = formatter.formatByteSize(size);
         }
     } else if (role == "modificationtime" || role == "creationtime" || role == "accesstime") {
             bool ok;
             const long long time = roleValue.toLongLong(&ok);
             if (ok && time != -1) {
-                return QLocale().toString(QDateTime::fromSecsSinceEpoch(time), QLocale::ShortFormat);
+                const QDateTime dateTime = QDateTime::fromSecsSinceEpoch(time);
+                text = formatDate(dateTime);
             }
     } else if (role == "deletiontime" || role == "imageDateTime") {
         const QDateTime dateTime = roleValue.toDateTime();
-        text = QLocale().toString(dateTime, QLocale::ShortFormat);
+        if (dateTime.isValid()) {
+            text = formatDate(dateTime);
+        }
     } else {
         text = KStandardItemListWidgetInformant::roleText(role, values);
     }
index 566f228f6b1982f5097971d8ac22da199e062fa4..42788d2fe6553b83629820b4451b7a500850f216 100644 (file)
@@ -776,9 +776,7 @@ void KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived(const QStrin
 
             if (getSizeRole) {
                 data.insert("count", count);
-                if (size != -1) {
-                    data.insert("size", QVariant::fromValue(size));
-                }
+                data.insert("size", QVariant::fromValue(size));
             }
             if (getIsExpandableRole) {
                 data.insert("isExpandable", count > 0);
index 5c9a2bbdd35bf3acd51d683f5397db06e1c0015c..8687872ee81b6f75d22fd6577e8bfc8f8c7f3587 100644 (file)
@@ -1550,8 +1550,9 @@ bool KItemListController::onRelease(const QPointF& pos, const Qt::KeyboardModifi
         return true;
     }
 
+    const bool controlPressed = modifiers & Qt::ControlModifier;
     const bool shiftOrControlPressed = modifiers & Qt::ShiftModifier ||
-                                       modifiers & Qt::ControlModifier;
+                                       controlPressed;
 
     KItemListRubberBand* rubberBand = m_view->rubberBand();
     if (rubberBand->isActive()) {
@@ -1585,6 +1586,11 @@ bool KItemListController::onRelease(const QPointF& pos, const Qt::KeyboardModifi
             } else if (shiftOrControlPressed) {
                 // The mouse click should only update the selection, not trigger the item
                 emitItemActivated = false;
+                // When Ctrl-clicking an item when in single selection mode
+                // i.e. where Ctrl won't change the selection, pretend it was middle clicked
+                if (controlPressed && m_selectionBehavior == SingleSelection) {
+                    Q_EMIT itemMiddleClicked(index);
+                }
             } else if (!(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced)) {
                 if (touch) {
                 emitItemActivated = true;
index f6e5e666bb8e2e00ecdf710d3c7aa492a4ff9bb6..96c337de39b02c873e9ed5335f396e5ec88d8367 100644 (file)
@@ -27,6 +27,7 @@
 #include <QPropertyAnimation>
 #include <QStyleOptionRubberBand>
 #include <QTimer>
+#include <QVariantAnimation>
 
 
 namespace {
@@ -36,6 +37,11 @@ namespace {
 
     // Delay in ms for triggering the next autoscroll
     const int RepeatingAutoScrollDelay = 1000 / 60;
+
+    // Copied from the Kirigami.Units.shortDuration
+    const int RubberFadeSpeed = 150;
+
+    const char* RubberPropertyName = "_kitemviews_rubberBandPosition";
 }
 
 #ifndef QT_NO_ACCESSIBILITY
@@ -660,6 +666,30 @@ void KItemListView::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt
 {
     QGraphicsWidget::paint(painter, option, widget);
 
+    for (auto animation : qAsConst(m_rubberBandAnimations)) {
+        QRectF rubberBandRect = animation->property(RubberPropertyName).toRectF();
+
+        const QPointF topLeft = rubberBandRect.topLeft();
+        if (scrollOrientation() == Qt::Vertical) {
+            rubberBandRect.moveTo(topLeft.x(), topLeft.y() - scrollOffset());
+        } else {
+            rubberBandRect.moveTo(topLeft.x() - scrollOffset(), topLeft.y());
+        }
+
+        QStyleOptionRubberBand opt;
+        initStyleOption(&opt);
+        opt.shape = QRubberBand::Rectangle;
+        opt.opaque = false;
+        opt.rect = rubberBandRect.toRect();
+
+        painter->save();
+
+        painter->setOpacity(animation->currentValue().toReal());
+        style()->drawControl(QStyle::CE_RubberBand, &opt, painter);
+
+        painter->restore();
+    }
+
     if (m_rubberBand->isActive()) {
         QRectF rubberBandRect = QRectF(m_rubberBand->startPosition(),
                                        m_rubberBand->endPosition()).normalized();
@@ -1455,6 +1485,30 @@ void KItemListView::slotRubberBandActivationChanged(bool active)
         connect(m_rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListView::slotRubberBandPosChanged);
         m_skipAutoScrollForRubberBand = true;
     } else {
+        QRectF rubberBandRect = QRectF(m_rubberBand->startPosition(),
+                                       m_rubberBand->endPosition()).normalized();
+
+        auto animation = new QVariantAnimation(this);
+        animation->setStartValue(1.0);
+        animation->setEndValue(0.0);
+        animation->setDuration(RubberFadeSpeed);
+        animation->setProperty(RubberPropertyName, rubberBandRect);
+
+        QEasingCurve curve;
+        curve.setType(QEasingCurve::BezierSpline);
+        curve.addCubicBezierSegment(QPointF(0.4, 0.0), QPointF(1.0, 1.0), QPointF(1.0, 1.0));
+        animation->setEasingCurve(curve);
+
+        connect(animation, &QVariantAnimation::valueChanged, this, [=](const QVariant&) {
+            update();
+        });
+        connect(animation, &QVariantAnimation::finished, this, [=]() {
+            m_rubberBandAnimations.removeAll(animation);
+            delete animation;
+        });
+        animation->start();
+        m_rubberBandAnimations << animation;
+
         disconnect(m_rubberBand, &KItemListRubberBand::startPositionChanged, this, &KItemListView::slotRubberBandPosChanged);
         disconnect(m_rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListView::slotRubberBandPosChanged);
         m_skipAutoScrollForRubberBand = false;
index df582aad05e2648142d812cbcdea3919d3278fe7..e6bf5ad90809fdc60b25759f6e9fe09bca305356 100644 (file)
@@ -32,6 +32,7 @@ class KItemListWidgetInformant;
 class KItemListWidgetCreatorBase;
 class QTimer;
 class QPropertyAnimation;
+class QVariantAnimation;
 
 /**
  * @brief Represents the view of an item-list.
@@ -747,6 +748,8 @@ private:
     // by KItemListView::showDropIndicator() and KItemListView::hideDropIndicator().
     QRectF m_dropIndicator;
 
+    QList<QVariantAnimation*> m_rubberBandAnimations;
+
     friend class KItemListContainer; // Accesses scrollBarRequired()
     friend class KItemListHeader;    // Accesses m_headerWidget
     friend class KItemListController;
index d45b06777ba300e684fbb312f9107303e139df82..5c87de7129f9570d76fca0a8b8ac3e2faddedc49 100644 (file)
 #include <Baloo/File>
 #include <KFileMetaData/PropertyInfo>
 #include <KFileMetaData/UserMetaData>
-#include <KFormat>
-#include <KLocalizedString>
 
 #include <QCollator>
 #include <QDebug>
 #include <QTime>
 
+namespace {
+    QString tagsFromValues(const QStringList& values)
+    {
+        if (values.size() == 1) {
+            return values.at(0);
+        }
+
+        QStringList alphabeticalOrderTags = values;
+        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(QLatin1String(", "));
+    }
+
+    using Property = KFileMetaData::Property::Property;
+    // Mapping from the KFM::Property to the KFileItemModel roles.
+    const QHash<Property, QByteArray> propertyRoleMap() {
+        static const auto map = QHash<Property, QByteArray> {
+            { Property::Rating,            QByteArrayLiteral("rating") },
+            { Property::Comment,           QByteArrayLiteral("comment") },
+            { Property::Title,             QByteArrayLiteral("title") },
+            { Property::WordCount,         QByteArrayLiteral("wordCount") },
+            { Property::LineCount,         QByteArrayLiteral("lineCount") },
+            { Property::Width,             QByteArrayLiteral("width") },
+            { Property::Height,            QByteArrayLiteral("height") },
+            { Property::ImageDateTime,     QByteArrayLiteral("imageDateTime") },
+            { Property::ImageOrientation,  QByteArrayLiteral("orientation") },
+            { Property::Artist,            QByteArrayLiteral("artist") },
+            { Property::Genre,             QByteArrayLiteral("genre")  },
+            { Property::Album,             QByteArrayLiteral("album") },
+            { Property::Duration,          QByteArrayLiteral("duration") },
+            { Property::BitRate,           QByteArrayLiteral("bitrate") },
+            { Property::AspectRatio,       QByteArrayLiteral("aspectRatio") },
+            { Property::FrameRate,         QByteArrayLiteral("frameRate") },
+            { Property::ReleaseYear,       QByteArrayLiteral("releaseYear") },
+            { Property::TrackNumber,       QByteArrayLiteral("track") }
+        };
+        return map;
+    }
+}
+
 struct KBalooRolesProviderSingleton
 {
     KBalooRolesProvider instance;
@@ -50,17 +89,17 @@ QHash<QByteArray, QVariant> KBalooRolesProvider::roleValues(const Baloo::File& f
 
     while (rangeBegin != propMap.constKeyValueEnd()) {
         auto key = (*rangeBegin).first;
-        const KFileMetaData::PropertyInfo propertyInfo(key);
-        const QByteArray role = roleForProperty(propertyInfo.name());
 
         auto rangeEnd = std::find_if(rangeBegin, propMap.constKeyValueEnd(),
             [key](const entry& e) { return e.first != key; });
 
+        const QByteArray role = propertyRoleMap().value(key);
         if (role.isEmpty() || !roles.contains(role)) {
             rangeBegin = rangeEnd;
             continue;
         }
 
+        const KFileMetaData::PropertyInfo propertyInfo(key);
         auto distance = std::distance(rangeBegin, rangeEnd);
         if (distance > 1) {
             QVariantList list;
@@ -78,74 +117,54 @@ QHash<QByteArray, QVariant> KBalooRolesProvider::roleValues(const Baloo::File& f
         rangeBegin = rangeEnd;
     }
 
-    KFileMetaData::UserMetaData md(file.path());
+    KFileMetaData::UserMetaData::Attributes attributes;
     if (roles.contains("tags")) {
-        values.insert("tags", tagsFromValues(md.tags()));
+        attributes |= KFileMetaData::UserMetaData::Tags;
     }
     if (roles.contains("rating")) {
-        values.insert("rating", QString::number(md.rating()));
+        attributes |= KFileMetaData::UserMetaData::Rating;
     }
     if (roles.contains("comment")) {
-        values.insert("comment", md.userComment());
+        attributes |= KFileMetaData::UserMetaData::Comment;
     }
     if (roles.contains("originUrl")) {
+        attributes |= KFileMetaData::UserMetaData::OriginUrl;
+    }
+
+    if (attributes == KFileMetaData::UserMetaData::None) {
+        return values;
+    }
+
+    KFileMetaData::UserMetaData md(file.path());
+    attributes = md.queryAttributes(attributes);
+
+    if (attributes & KFileMetaData::UserMetaData::Tags) {
+        values.insert("tags", tagsFromValues(md.tags()));
+    }
+    if (attributes & KFileMetaData::UserMetaData::Rating) {
+        values.insert("rating", QString::number(md.rating()));
+    }
+    if (attributes & KFileMetaData::UserMetaData::Comment) {
+        values.insert("comment", md.userComment());
+    }
+    if (attributes & KFileMetaData::UserMetaData::OriginUrl) {
         values.insert("originUrl", md.originUrl());
     }
 
     return values;
 }
 
-QByteArray KBalooRolesProvider::roleForProperty(const QString& property) const
-{
-    return m_roleForProperty.value(property);
-}
-
-KBalooRolesProvider::KBalooRolesProvider() :
-    m_roles(),
-    m_roleForProperty()
+KBalooRolesProvider::KBalooRolesProvider()
 {
-    struct PropertyInfo
-    {
-        const char* const property;
-        const char* const role;
-    };
-
-    // Mapping from the URIs to the KFileItemModel roles. Note that this must not be
-    // a 1:1 mapping: One role may contain several URI-values
-    static const PropertyInfo propertyInfoList[] = {
-        { "rating", "rating" },
-        { "tag",        "tags" },
-        { "comment",   "comment" },
-        { "title",         "title" },
-        { "wordCount",     "wordCount" },
-        { "lineCount",     "lineCount" },
-        { "width",         "width" },
-        { "height",        "height" },
-        { "imageDateTime",   "imageDateTime"},
-        { "imageOrientation", "orientation", },
-        { "artist",     "artist" },
-        { "genre",     "genre"  },
-        { "album",    "album" },
-        { "duration",      "duration" },
-        { "bitRate", "bitrate" },
-        { "aspectRatio", "aspectRatio" },
-        { "frameRate", "frameRate" },
-        { "releaseYear",    "releaseYear" },
-        { "trackNumber",   "track" },
-        { "originUrl", "originUrl" }
-    };
-
-    for (unsigned int i = 0; i < sizeof(propertyInfoList) / sizeof(PropertyInfo); ++i) {
-        m_roleForProperty.insert(propertyInfoList[i].property, propertyInfoList[i].role);
-        m_roles.insert(propertyInfoList[i].role);
+    // Display roles filled from Baloo property cache
+    for (const auto& role : propertyRoleMap()) {
+        m_roles.insert(role);
     }
-}
 
-QString KBalooRolesProvider::tagsFromValues(const QStringList& values) const
-{
-    QStringList alphabeticalOrderTags = values;
-    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(QLatin1String(", "));
+    // Display roles provided by UserMetaData
+    m_roles.insert(QByteArrayLiteral("tags"));
+    m_roles.insert(QByteArrayLiteral("rating"));
+    m_roles.insert(QByteArrayLiteral("comment"));
+    m_roles.insert(QByteArrayLiteral("originUrl"));
 }
+
index 99c601e16bce11124e11c0de163b8ce0cd0aaafb..97ed58f2b189df9bc00e50cbf268fb634adc28e9 100644 (file)
@@ -42,21 +42,11 @@ public:
     QHash<QByteArray, QVariant> roleValues(const Baloo::File& file,
                                            const QSet<QByteArray>& roles) const;
 
-    QByteArray roleForProperty(const QString& property) const;
-
 protected:
     KBalooRolesProvider();
 
-private:
-    /**
-     * @return User visible string for the given tag-values.
-     *         The tag-values are sorted in alphabetical order.
-     */
-    QString tagsFromValues(const QStringList& values) const;
-
 private:
     QSet<QByteArray> m_roles;
-    QHash<QString, QByteArray> m_roleForProperty;
 
     friend struct KBalooRolesProviderSingleton;
 };
index 1e3b7ff9f0b182bf3525e19a023ba16dc67b87de..73799e739678863657d98ada5fdba5d61d1db03f 100644 (file)
@@ -35,6 +35,7 @@ KDirectoryContentsCounterWorker::CountResult walkDir(const QString &dirPath,
     auto dir = QT_OPENDIR(QFile::encodeName(dirPath));
     if (dir) {
         count = 0;
+        size = 0;
         QT_STATBUF buf;
 
         while ((dirEntry = QT_READDIR(dir))) {
index 24d64446283091aef05f2489615453ca6bf8c83c..c3d80ccde790fc4fdaf2392082f82d77949fa0b6 100644 (file)
   <summary xml:lang="zh-CN">文件管理器</summary>
   <summary xml:lang="zh-TW">檔案管理員</summary>
   <description>
-    <p>Dolphin is a lightweight file manager. It has been designed with ease of use and simplicity in mind, while still allowing flexibility and customisation. This means that you can do your file management exactly the way you want to do it.</p>
-    <p xml:lang="ar">دولفين هو مدير ملفات خفيف. صُمِّم دولفين مع أخذ سهولة الاستخدام والبساطة بعين الاعتبار، مع السماح بالمرونة والتخصيص. يعني هذا أنه يمكنك إدارة ملفاتك كما تريد تمامًا.</p>
-    <p xml:lang="ast">Dolphin ye un xestor de ficheros llixeru. Diseñóse cola cenciellez y facilidá d'usu en mente, al empar que permite flexibilidá y personalización. Esto quier dicir que pues facer la xestión de ficheros del mou exautu que quieras.</p>
-    <p xml:lang="az">Dolphin yüngül bir fayl meneceridir. Bu tətbiq istifadə rahatlığı və sadələiyi ilə bərabər çevik və fərdi ayarlana bilmə üstünlükləri nəzərə alınaraq hazırlanmışdır. Bu o deməkdir ki, siz faylları istədiyiniz kimi idarə edə bilərsiniz.</p>
-    <p xml:lang="bs">Dolphinje lagan file manager. On je bio dizajniran sa lakoćom korišćenja i jednostavnosti u vidu, još omogućavajući fleksibilnost i prilagođavanje. To znači da možete da radite svoje upravljanje datotekama onako kako želite da to uradi.</p>
-    <p xml:lang="ca">El Dolphin és un gestor de fitxers lleuger. S'ha dissenyat pensant a facilitar el seu ús i que sigui simple, permetent la flexibilitat i la personalització. Això vol dir que podeu fer la gestió dels vostres fitxers de la manera exacta com ho vulgueu fer.</p>
-    <p xml:lang="ca-valencia">El Dolphin és un gestor de fitxers lleuger. S'ha dissenyat pensant a facilitar el seu ús i que siga simple, permetent la flexibilitat i la personalització. Això vol dir que podeu fer la gestió dels vostres fitxers de la manera exacta com ho vulgueu fer.</p>
-    <p xml:lang="da">Dolphin er letvægtsfilhåndtering. Den er blevet designet med henblik på brugervenlighed og simpelhed, mens fleksibilitet og tilpasning stadig er muligt. Det betyder at du klare din filhåndtering nøjagtig på den måde du vil gøre det.</p>
-    <p xml:lang="de">Dolphin ist ein schlankes Programm zur Dateiverwaltung. Es wurde mit dem Ziel entwickelt, einfach in der Anwendung, dabei aber auch flexibel und anpassungsfähig zu sein. Sie können daher Ihre Dateiverwaltungsaufgaben genau nach Ihren Bedürfnissen ausführen.</p>
-    <p xml:lang="el">Το Dolphin είναι ένας ελαφρύς διαχειριστής αρχείων. Έχει σχεδιαστεί με φιλοσοφία την απλότητα για ευκολία στη χρήση, ενώ επιτρέπει ευελιξία και προσαρμογές. Αυτό σημαίνει ότι μπορείτε να διαχειριστείτε τα αρχεία σας με τον τρόπο που εσείς θέλετε.</p>
-    <p xml:lang="en-GB">Dolphin is a lightweight file manager. It has been designed with ease of use and simplicity in mind, while still allowing flexibility and customisation. This means that you can do your file management exactly the way you want to do it.</p>
-    <p xml:lang="es">Dolphin es un administrador de archivos ligero. Se ha diseñado teniendo en cuenta la facilidad de uso y la simplicidad, así como la flexibilidad y la personalización. Esto significa que el usuario puede administrar los archivos exactamente de la manera que prefiera.</p>
-    <p xml:lang="et">Dolphin on vähest koormust tekitav failihaldur. Selle loomisel on peetud silmas kasutamise hõlpsust ja lihtsust, ometi pakub see suurt paindlikkust ja oma käe järgi kohandamise võimalusi. Sel moel saab faile hallata just, nagu ise soovid.</p>
-    <p xml:lang="eu">Dolphin pisu arineko fitxategi-kudeatzaile bat da. Erabilera erraza eta sinpletasuna gogoan diseinatua izan da, ordea, malgutasuna eta norbere nahietara egokitzea onartzen du. Honek esan nahi du fitxategi-kudeatzea zuk nahi duzun eran egin dezakezula.</p>
-    <p xml:lang="fi">Dolphin on kevyt tiedostonhallinta. Se on suunniteltu helppokäyttöiseksi ja yksinkertaiseksi, mutta silti joustavaksi ja mukautettavaksi. Voit siis hallita tiedostojasi juuri niin kuin haluat.</p>
-    <p xml:lang="fr">Dolphin est un gestionnaire de fichiers léger. Il a été conçu en gardant à l'esprit la simplicité et l'aisance à l'usage, tout en permettant flexibilité et personnalisation. Cela signifie que vous pouvez gérer vos fichiers de la manière exacte que vous voulez.</p>
-    <p xml:lang="gl">Dolphin é un xestor de ficheiros lixeiro. Deseñouse pensando na facilidade de uso e a simplicidade, pero permitindo flexibilidade e personalización. Noutras palabras, permítelle xestionar os seus ficheiros do xeito que máis lle agrade.</p>
-    <p xml:lang="he">‏Dolphin הוא מנהל קבצים קליל. הוא עוצב לקלות שימוש ופשטות, תוך כדי אפשור גמישות והתאמה אישית. זה אומר שניתן לנהל את הקבצים שלך כרצונך.</p>
-    <p xml:lang="hu">A Dolphin egy pehelysúlyú fájlkezelő. Az egyszerű használatot és az egyszerűséget szem előtt tartva tervezték, miközben továbbra is lehetővé teszi a rugalmasságot és a testre szabhatóságot. Ez azt jelenti, hogy pontosan oly módon végezheti a fájlkezelést, ahogy csak akarja.</p>
-    <p xml:lang="ia">Dolphin es un gerente de file legier. Il ha essite designate con facilitate de uso e simplicitate in le mente, mentre il permitte ancora flexibilitate e personalisation. Isto significa que tu pote facer le gerente de file exactemente como tu lo vole.</p>
-    <p xml:lang="id">Dolphin adalah pengelola file yang ringan. Ini telah dirancang dengan kemudahan penggunaan dan kesederhanaan dalam hal, sementara masih memungkinkan fleksibilitas dan kustomisasi. Ini berarti kamu bisa melakukan pengelolaan file-mu persis seperti yang kamu inginkan.</p>
-    <p xml:lang="it">Dolphin è un gestore file leggero. È stato progettato per essere facile da utilizzare e pensando alla semplicità, garantendo al contempo flessibilità e personalizzazione. Ciò significa che puoi gestire i tuoi file come meglio desideri.</p>
-    <p xml:lang="ko">Dolphin은 가벼운 파일 관리자입니다. 사용 편의성과 단순함을 염두에 두고 설계되었으며, 유연성과 사용자 정의를 여전히 허용합니다. 즉, 파일 관리를 원하는 방식으로 정확하게 수행할 수 있습니다.</p>
-    <p xml:lang="lt">Dolphin yra supaprastinta failų tvarkytuvė. Ji buvo sukurta taip, kad ją būtų lengva naudoti, susitelkiant į paprastumą, tačiau įgalinant lankstumą ir tinkinimą. Tai reiškia, kad galite tvarkyti failus būtent taip, kaip norite.</p>
-    <p xml:lang="ml">ഡോൾഫിൻ ഒരു ഭാരം കുറഞ്ഞ ഫയൽ മാനേജറാണ്. ഇത് നിർമ്മിച്ചിരിക്കുന്നത് ഉപയോഗിക്കുന്നതിനുള്ള എളുപ്പത്തിനും , മാനസികമായിയുള്ള എളുപ്പത്തിനുമാണ്, ഒപ്പം തന്നെ അഭിരുചിക്കനുസൃതമാക്കുന്നതിനും വഴക്കം നൽകുന്നതിനും അനുവദിക്കുന്നു. അതായത് നിങ്ങൾക്ക് നിങ്ങളുടെ ഫയലുകൾ  എങ്ങനെയൊക്കെ കൈകാര്യം ചെയ്യണോ അങ്ങനെ കൈകാര്യം ചെയ്യാവുന്നതാണ്.</p>
-    <p xml:lang="nb">Dolphin er en lettvekts filbehandler. Den er laget for å være enkel og lett å bruke, samtidig som den er fleksibel og kan tilpasses. Det betyr at du kan utføre dine filbehandlingsoppgaver akkurat slik du vil gjøre det.</p>
-    <p xml:lang="nds">Dolphin is en slank Dateipleger. Dat wöör buut mit de Idee vun't eenfache Bedenen vör Ogen, bides dat liekers flexibel un topassbor wesen schull. Du kannst Dien Dateien also jüst so plegen, as Du dat wullt.</p>
-    <p xml:lang="nl">Dolphin is een lichtgewicht bestandsbeheerder. Het is ontworpen met gebruiksgemak en eenvoud in gedachte en staat toch flexibiliteit en aan te passen toe. Dit betekent dat u uw bestandsbeheer kunt doen precies op de manier zoals u dat wilt.</p>
-    <p xml:lang="nn">Dolphin er ein lettvekts filhandsamar. Han er laga for å vera enkel å bruka, samtidig som han er fleksibel og kan tilpassast, slik at du kan gjera filhandsamingsoppgåvene nett slik du ønskjer.</p>
-    <p xml:lang="pl">Dolphin jest lekkim programem do zarządzania plikami. Został on opracowany mając na uwadze łatwość i prostotę obsługi, zapewniając jednocześnie elastyczność i możliwość dostosowania. Oznacza to, że można urządzić zarządzanie plikami w dokładnie taki sposób w jaki jest to pożądane.</p>
-    <p xml:lang="pt">O Dolphin é um gestor de ficheiros leve. Foi desenhado com a facilidade de uso e simplicidade em mente, permitindo à mesma a flexibilidade e personalização. Isto significa que poderá fazer a sua gestão de ficheiros exactamente da forma que deseja.</p>
-    <p xml:lang="pt-BR">Dolphin é um gerenciador de arquivos leve e fácil de usar. Foi projetado para ser simples e ao mesmo tempo manter a flexibilidade e personalização. Isso significa que você poderá gerenciar seus arquivos da forma que desejar.</p>
-    <p xml:lang="ro">Dolphin e un gestionar de fișiere simplu. A fost proiectat cu ușurința la utilizare și simplitatea în minte, în același timp permițând flexibilitate și personalizare. Aceasta înseamnă vă puteți gestiona fișierele exact așa cum vă doriți s-o faceți.</p>
-    <p xml:lang="ru">Dolphin — это упрощённый диспетчер файлов. Он создавался как лёгкий в использовании, но в то же время является гибким и расширяемым.</p>
-    <p xml:lang="sk">Dolphin je odľahčený správca súborov. Bol navrhnutý na jednoduché použitie a jednoduchosť, ale s možnosťami flexibility a prispôsobenia. To znamená, že môžete vykonávať správu súborov presne tak, ako chcete.</p>
-    <p xml:lang="sl">Dolphin je enostaven upravljalnik datotek. Bil je zasnovan kot enostaven in preprost, vseeno pa ostaja prilagodljiv. To pomeni, da lahko upravljanje datotek izvajate točno tako kot želite.</p>
-    <p xml:lang="sr">Делфин је лагани менаџер фајлова. Пројектован је да буде лак за употребу и једноставан, а да ипак омогућава флексибилност и прилагођавање. То значи да ће моћи да баратате фајловима тачно онако како бисте желели.</p>
-    <p xml:lang="sr-Latn">Dolphin je lagani menadžer fajlova. Projektovan je da bude lak za upotrebu i jednostavan, a da ipak omogućava fleksibilnost i prilagođavanje. To znači da će moći da baratate fajlovima tačno onako kako biste želeli.</p>
-    <p xml:lang="sr-ijekavian">Делфин је лагани менаџер фајлова. Пројектован је да буде лак за употребу и једноставан, а да ипак омогућава флексибилност и прилагођавање. То значи да ће моћи да баратате фајловима тачно онако како бисте желели.</p>
-    <p xml:lang="sr-ijekavianlatin">Dolphin je lagani menadžer fajlova. Projektovan je da bude lak za upotrebu i jednostavan, a da ipak omogućava fleksibilnost i prilagođavanje. To znači da će moći da baratate fajlovima tačno onako kako biste želeli.</p>
-    <p xml:lang="sv">Dolphin är en lättviktig filhanterare. Den har konstruerats med användbarhet och enkelhet i åtanke, men ändå tillåta flexibilitet och anpassning. Det betyder att du kan hantera filer exakt på det sätt som du vill göra det.</p>
-    <p xml:lang="tr">Dolphin hafif bir dosya yöneticisidir. Kolay kullanım ve basitliğin yanı sıra esneklik ve özelleştirilebilme de akılda tutularak geliştirilmiştir. Bu da dosya yöneticisini tam da istediğiniz gibi kullanabileceğiniz anlamına gelir.</p>
-    <p xml:lang="uk">Dolphin — невибаглива до ресурсів програма для керування файлами. Її створено простою у користуванні і гнучкою у налаштовуванні. Це означає, що ви можете зробити керування файлами саме таким, як вам потрібно.</p>
-    <p xml:lang="vi">Dolphin là một trình quản lí tệp nhẹ. Nó được thiết kế với lưu ý đến tính dễ dùng và sự đơn giản, đồng thời vẫn cho phép tính linh hoạt và sự tuỳ biến. Điều này nghĩa là bạn có thể quản lí tệp theo đúng cách bạn muốn.</p>
-    <p xml:lang="x-test">xxDolphin is a lightweight file manager. It has been designed with ease of use and simplicity in mind, while still allowing flexibility and customisation. This means that you can do your file management exactly the way you want to do it.xx</p>
-    <p xml:lang="zh-CN">Dolphin 是一个轻量的文件管理器。它设计时考虑了简单易用,但仍然保持了灵活性和定制性。这意味着您可以用完全属于您的方式来管理文件。</p>
-    <p xml:lang="zh-TW">Dolphin 是一套輕量級的檔案管理員。它設計的理念是易用與簡單,但仍然保持足夠的彈性。這表示您可以用您想要使用的方式來管理您的檔案。</p>
-    <p>Features:</p>
-    <p xml:lang="ar">المزايا:</p>
-    <p xml:lang="ast">Carauterístiques:</p>
-    <p xml:lang="az">Xüsusiyyətləri:</p>
-    <p xml:lang="bs">Svojstva:</p>
-    <p xml:lang="ca">Característiques:</p>
-    <p xml:lang="ca-valencia">Característiques:</p>
-    <p xml:lang="cs">Vlastnosti:</p>
-    <p xml:lang="da">Funktioner:</p>
-    <p xml:lang="de">Funktionen:</p>
-    <p xml:lang="el">Χαρακτηριστικά:</p>
-    <p xml:lang="en-GB">Features:</p>
-    <p xml:lang="es">Características:</p>
-    <p xml:lang="et">Omadused:</p>
-    <p xml:lang="eu">Eginbideak:</p>
-    <p xml:lang="fi">Ominaisuudet:</p>
-    <p xml:lang="fr">Fonctionnalités :</p>
-    <p xml:lang="gl">Funcionalidades:</p>
-    <p xml:lang="he">תכונות:</p>
-    <p xml:lang="hu">Szolgáltatások:</p>
-    <p xml:lang="ia">Characteristicas:</p>
-    <p xml:lang="id">Fitur:</p>
-    <p xml:lang="it">Funzionalità:</p>
-    <p xml:lang="ko">기능:</p>
-    <p xml:lang="lt">Ypatybės:</p>
-    <p xml:lang="ml">വിശേഷതകൾ:</p>
-    <p xml:lang="nb">Egenskaper:</p>
-    <p xml:lang="nds">Markmalen:</p>
-    <p xml:lang="nl">Mogelijkheden:</p>
-    <p xml:lang="nn">Funksjonar:</p>
-    <p xml:lang="pa">ਲੱਛਣ:</p>
-    <p xml:lang="pl">Możliwości:</p>
-    <p xml:lang="pt">Funcionalidades:</p>
-    <p xml:lang="pt-BR">Funcionalidades:</p>
-    <p xml:lang="ro">Caracteristici:</p>
-    <p xml:lang="ru">Возможности:</p>
-    <p xml:lang="sk">Funkcie:</p>
-    <p xml:lang="sl">Zmožnosti:</p>
-    <p xml:lang="sr">Могућности:</p>
-    <p xml:lang="sr-Latn">Mogućnosti:</p>
-    <p xml:lang="sr-ijekavian">Могућности:</p>
-    <p xml:lang="sr-ijekavianlatin">Mogućnosti:</p>
-    <p xml:lang="sv">Funktioner:</p>
-    <p xml:lang="tr">Özellikler:</p>
-    <p xml:lang="uk">Можливості:</p>
-    <p xml:lang="vi">Tính năng:</p>
-    <p xml:lang="x-test">xxFeatures:xx</p>
-    <p xml:lang="zh-CN">功能:</p>
-    <p xml:lang="zh-TW">功能:</p>
-    <ul>
-      <li>Navigation (or breadcrumb) bar for URLs, allowing you to quickly navigate through the hierarchy of files and folders.</li>
-      <li xml:lang="az">Ünvan sətri qovluqlar üzrə cəld hərəkət etməyə imkan verir.</li>
-      <li xml:lang="bs">Navigacijska (ili mrvična) traka za URL, dopušta vam da se brzo krećete kroz hijerarhiju datoteka i direktorija.</li>
-      <li xml:lang="ca">Barra de navegació (o fil d'Ariadna) pels URL, permetent una navegació ràpida per la jerarquia dels fitxers i carpetes.</li>
-      <li xml:lang="ca-valencia">Barra de navegació (o fil d'Ariadna) pels URL, permetent una navegació ràpida per la jerarquia dels fitxers i carpetes.</li>
-      <li xml:lang="da">Navigationsbjælke (eller brødkrumme-bjælke) til URL'er, lader dig navigere hurtigt igennem hierarkiet af filer og mapper.</li>
-      <li xml:lang="de">Navigationsleiste für Adressen (auch editierbar), mit der Sie schnell durch die Hierarchie der Dateien und Ordner navigieren können.</li>
-      <li xml:lang="el">Η γραμμή πλοήγησης (ή ιχνηλάτησης) για URL, σας επιτρέπει να πλοηγηθείτε γρήγορα μέσα από την ιεραρχία αρχείων και φακέλων.</li>
-      <li xml:lang="en-GB">Navigation (or breadcrumb) bar for URLs, allowing you to quickly navigate through the hierarchy of files and folders.</li>
-      <li xml:lang="es">barra de navegación (o de ruta completa) para URL que permite navegar rápidamente a través de la jerarquía de archivos y carpetas.</li>
-      <li xml:lang="et">Liikumisriba URL-idele, mis lubab kiiresti liigelda failide ja kataloogide hierarhias.</li>
-      <li xml:lang="eu">Nabigatzeko (edo ogi-apurren) barra URLentzako, fitxategi eta karpeten hierarkian zehar azkar nabigatzeko aukera ematen dizuna.</li>
-      <li xml:lang="fi">Osoiterivi, jonka avulla siirtyminen tiedostojen ja kansioiden hierarkiassa on nopeaa.</li>
-      <li xml:lang="fr">Barre de navigation (ou fil d'Ariane) permettant de naviguer rapidement dans la hiérarchie de fichiers et de dossiers.</li>
-      <li xml:lang="gl">Barra de navegación (ou ronsel) para enderezos URL, que lle permite navegar rapidamente pola xerarquía de ficheiros e cartafoles.</li>
-      <li xml:lang="hu">Navigációs (vagy webmorzsa) sáv az URL-ekhez, amely lehetővé teszi a fájlok és mappák hierarchiáján keresztüli gyors navigációt.</li>
-      <li xml:lang="ia">Barra de navigation (o "breadcrumb") pro URLs, que il permitte te navigar rapidemente a transverso del hierarchia de files e dossieres.</li>
-      <li xml:lang="id">Bilah navigasi (atau breadcrumb) untuk URL-URL, memungkinkan kamu secara cepat bernavigasi melalui hirerarki file-file dan folder-folder.</li>
-      <li xml:lang="it">La barra di navigazione per gli URL, che ti consente di navigare rapidamente attraverso la struttura di file e cartelle.</li>
-      <li xml:lang="ko">URL에 대한 탐색(또는 이동 경로) 표시줄을 사용하면 파일 및 폴더의 계층 구조를 빠르게 탐색할 수 있습니다.</li>
-      <li xml:lang="lt">Naršymo (arba trupinių) juosta, skirta URL adresams, leidžianti greitai naršyti per failų ar aplankų hierarchiją.</li>
-      <li xml:lang="ml">ഫയലുകളുടെയും അറകളുടെയും ശ്രേണി കണ്ടുപിടിക്കുന്നതിന് URL കൾക്ക്  നാവിഗേഷൻ (അല്ലെങ്കിൽ വഴി കാട്ടുന്നതിനുള്ള) സ്ഥലം.</li>
-      <li xml:lang="nb">Navigasjonslinje (brødsmulelinje) for URL-er slik at du raskt kan navigere gjennom hierarkiet av filer og mapper.</li>
-      <li xml:lang="nds">Steed- (oder Krömelspoor-)Balken för URLs, mit de Du Di fix dör de Hierarchie ut Dateien un Ornern bewegen kannst</li>
-      <li xml:lang="nl">Navigatie- (of broodkruimel)balk voor URL's, waarmee u snel kunt navigeren door de hiërarchie van bestanden en mappen.</li>
-      <li xml:lang="nn">Navigasjonslinje (brødsmulelinje), slik at du raskt kan navigera gjennom hierarkiet av filer og mapper.</li>
-      <li xml:lang="pl">Pasek nawigacji (lub okruchy chleba) dla adresów URL, umożliwiające szybkie przechodzenie w hierarchii plików i katalogów.</li>
-      <li xml:lang="pt">Barra de navegação dos URL's, que lhe permite navegar rapidamente pela hierarquia de ficheiros e pastas.</li>
-      <li xml:lang="pt-BR">Barra de navegação de URLs, permitindo-lhe navegar rapidamente pela hierarquia de arquivos e pastas.</li>
-      <li xml:lang="ro">Bară de navigare (sau firimituri) pentru URL-uri, ceea ce vă permite să navigați rapid prin ierarhia de fișiere și dosare.</li>
-      <li xml:lang="ru">Адресная строка позволяет быстро перемещаться по дереву папок;</li>
-      <li xml:lang="sk">Navigačná lišta pre URL, umožňujúca vám rýchlu navigáciu cez hierarchiu súborov a priečinkov.</li>
-      <li xml:lang="sl">Vrstica za krmarjenje po naslovih URL, ki omogoča hitro krmarjenje po hierarhiji datotek in map.</li>
-      <li xml:lang="sr">Навигациона трака (или мрвице) за УРЛ‑ове, преко које се можете брзо кретати кроз стабло фајлова и фасцикли.</li>
-      <li xml:lang="sr-Latn">Navigaciona traka (ili mrvice) za URL‑ove, preko koje se možete brzo kretati kroz stablo fajlova i fascikli.</li>
-      <li xml:lang="sr-ijekavian">Навигациона трака (или мрвице) за УРЛ‑ове, преко које се можете брзо кретати кроз стабло фајлова и фасцикли.</li>
-      <li xml:lang="sr-ijekavianlatin">Navigaciona traka (ili mrvice) za URL‑ove, preko koje se možete brzo kretati kroz stablo fajlova i fascikli.</li>
-      <li xml:lang="sv">Navigeringsrad (eller länkstig) för webbadresser, som låter dig snabbt navigera igenom hierarkin av filer och kataloger.</li>
-      <li xml:lang="tr">Dosya ve dizinlerin sıralı dizilerinde hızlıca gezinmenize imkan veren adresler için gezinti (veya işaret) çubuğu.</li>
-      <li xml:lang="uk">Панель навігації (звичайний режим і режим послідовної навігації) для адрес надає вам змогу швидко пересуватися ієрархією файлів та каталогів.</li>
-      <li xml:lang="vi">Thanh điều hướng (hay "vụn bánh") cho URL, cho phép bạn điều hướng nhanh chóng qua hệ thống cây tệp và thư mục.</li>
-      <li xml:lang="x-test">xxNavigation (or breadcrumb) bar for URLs, allowing you to quickly navigate through the hierarchy of files and folders.xx</li>
-      <li xml:lang="zh-CN">URL 的导航栏(面包屑导航),允许您快速地在文件和文件夹的层次结构间跳转。</li>
-      <li xml:lang="zh-TW">網址導覽列讓您可以快速瀏覽檔案與資料夾。</li>
-      <li>Supports several different kinds of view styles and properties and allows you to configure the view exactly how you want it.</li>
-      <li xml:lang="ar">يدعم العديد من الأنواع المختلفة من الخصائص وأنماط العرض ويسمح لك بضبط العرض كما تريد تمامًا.</li>
-      <li xml:lang="ast">Sofita estilos y propiedaes de vista diferentes, y permítete configurar la vista exautamente como quieras.</li>
-      <li xml:lang="az">Bir neçə fərqli görünüş tərzi və xüsusiyyətlərini dəstəkləyir və görünüşü tam olaraq istədiyiniz kimi tənzimləməyə imkan verir.</li>
-      <li xml:lang="bs">Dopušta vište vrsta stilova pogleda i svojstava i dopšta vam da konfigurišete pogled baš kako želite.</li>
-      <li xml:lang="ca">Accepta diferents classes diverses d'estils de visualització i propietats i us permet configurar la visualització exactament com la vulgueu.</li>
-      <li xml:lang="ca-valencia">Accepta diferents classes diverses d'estils de visualització i propietats i vos permet configurar la visualització exactament com la vulgueu.</li>
-      <li xml:lang="da">Understøtter flere forskellige slags visninger og egenskaber og lader dig konfigurere visningen nøjagtig som du vil have den.</li>
-      <li xml:lang="de">Unterstützt mehrere unterschiedliche Arten von Ansichtsstilen  und Eigenschaften und erlaubt es Ihnen, die Ansichten genau nach Ihren Bedürfnissen einzustellen.</li>
-      <li xml:lang="el">Υποστηρίζει πολλά διαφορετικά είδη στιλ και ιδιότητες επισκόπησης και σας επιτρέπει να διαμορφώσετε την επισκόπηση ακριβώς όπως τη θέλετε.</li>
-      <li xml:lang="en-GB">Supports several different kinds of view styles and properties and allows you to configure the view exactly how you want it.</li>
-      <li xml:lang="es">Admite varios tipos diferentes de estilos de vista y propiedades y permite configurar la vista exactamente como prefiera el usuario.</li>
-      <li xml:lang="et">Võimalus kasutada mitut laadi vaatestiile ja -omadusi ning neid igati enda käe järgi seadistada.</li>
-      <li xml:lang="eu">Hainbat mota desberdineko ikuspegi estilo eta propietate onartzen ditu eta ikuspegia zehazki zuk nahi duzun gisan konfiguratzeko aukera ematen dizu. </li>
-      <li xml:lang="fi">Tukee useita erilaisia näkymätyylejä ja -ominaisuuksia, ja mahdollistaa näkymän muokkaamisen mieleisekseen.</li>
-      <li xml:lang="fr">Prend en charge plusieurs types de styles d'affichage et de propriété et vous permet de configurer l'affichage de la manière exacte que vous voulez.</li>
-      <li xml:lang="gl">É compatíbel con varios estilos e propiedades de vista distintos, e permítelle configurar a vista como mellor lle pareza.</li>
-      <li xml:lang="hu">Számos különféle nézetstílus fajtát és tulajdonságot támogat, valamint lehetővé teszi a nézet beállítását pontosan olyanra, ahogy azt látni szeretné.</li>
-      <li xml:lang="ia">Il supporta multe differente typos de stilos de vista e proprietates e il permitte te configurar le vista exactemente como tu vole.</li>
-      <li xml:lang="id">Mendukung beberapa jenis gaya tampilan dan properti yang berbeda dan memungkinkanmu untuk mengonfigurasi tampilan persis seperti yang kamu inginkan.</li>
-      <li xml:lang="it">Supporta diversi stili di visualizzazione e proprietà e ti consente di configurare la vista come desideri.</li>
-      <li xml:lang="ko">여러 종류의 보기 스타일 및 속성을 지원하며 원하는 방식으로 보기를 구성할 수 있습니다.</li>
-      <li xml:lang="lt">Palaiko kelias įvairias stilių ir savybių rūšis ir leidžia konfigūruoti rodinį būtent taip, kaip norite.</li>
-      <li xml:lang="ml">നിങ്ങൾക്ക് ഇഷ്ടമുള്ള രീതിയിൽ കാണുന്നതിന് ആവശ്യമായിട്ടുള്ള വിവിധ അലങ്കാര രീതികള്‍ക്ക് പിന്തുണ നൽകുന്നു.</li>
-      <li xml:lang="nb">Støtter flere forskjellige visningsstiler og kan sette opp visningen akkurat slik du vil ha den.</li>
-      <li xml:lang="nds">Ünnerstütt en Reeg verscheden Ansichtstilen un -egenschappen un lett Di de Ansicht jüst so topassen, as Du dat bruukst.</li>
-      <li xml:lang="nl">Ondersteunt een aantal verschillende soorten stijlen van weergave en eigenschappen en biedt u de mogelijkheid de weergave in te stellen precies zoals u dat wilt.</li>
-      <li xml:lang="nn">Støttar fleire ulike visingsstilar, og du kan setja opp visinga nett slik du vil ha ho.</li>
-      <li xml:lang="pl">Obsługa wielu różnych rodzajów stylów widoków i właściwości oraz możliwość ustawienia widoku dopasowanego do potrzeb.</li>
-      <li xml:lang="pt">Suposta diferentes tipos de vistas e propriedades e permite-lhe configurar cada vista exactamente como a deseja.</li>
-      <li xml:lang="pt-BR">Suporte a diferentes tipos de visualização, permitindo-lhe configurar cada modo de exibição da forma que desejar.</li>
-      <li xml:lang="ro">Susține câteva feluri de stiluri și proprietăți de vizualizare, ceea ce vă permite să configurați vizualizarea exact așa cum vă doriți.</li>
-      <li xml:lang="ru">Несколько различных визуальных представлений папок, каждое из которых можно настроить по своему вкусу;</li>
-      <li xml:lang="sk">Podporuje niekoľko rôznych typov štýlov zobrazenia a vlastností a umožňuje vám nastaviť pohľad presne tak, ako chcete.</li>
-      <li xml:lang="sl">Podpira številne vrste slogov in lastnosti pogledov ter omogoča, da pogled nastavite točno tako kot vam ustreza.</li>
-      <li xml:lang="sr">Неколико начина приказа, са својствима које можете подесити по жељи.</li>
-      <li xml:lang="sr-Latn">Nekoliko načina prikaza, sa svojstvima koje možete podesiti po želji.</li>
-      <li xml:lang="sr-ijekavian">Неколико начина приказа, са својствима које можете подесити по жељи.</li>
-      <li xml:lang="sr-ijekavianlatin">Nekoliko načina prikaza, sa svojstvima koje možete podesiti po želji.</li>
-      <li xml:lang="sv">Stöder flera olika sorters visningsstilar och egenskaper och låter dig anpassa visningen exakt som du vill ha den.</li>
-      <li xml:lang="tr">Bir çok farklı görünüm tipini ve özelliğini destekler ve görünümü tam istediğiniz gibi yapılandırmanıza izin verir.</li>
-      <li xml:lang="uk">Підтримка декількох різних типів та параметрів перегляду надає вам змогу налаштувати перегляд каталогів саме так, як вам це потрібно.</li>
-      <li xml:lang="vi">Hỗ trợ nhiều loại kiểu cách và thuộc tính xem khác nhau, và cho phép bạn cấu hình khung xem đúng với cách bạn muốn.</li>
-      <li xml:lang="x-test">xxSupports several different kinds of view styles and properties and allows you to configure the view exactly how you want it.xx</li>
-      <li xml:lang="zh-CN">支持多种不同的视图风格和属性并且允许您用您想要的方式配置视图。</li>
-      <li xml:lang="zh-TW">網址導覽列讓您可以快速瀏覽檔案與資料夾。</li>
-      <li>Split view, allowing you to easily copy or move files between locations.</li>
-      <li xml:lang="ar">العرض المقسوم، يسمح لك بنسخ ونقل الملفات بين مكانين بسهولة.</li>
-      <li xml:lang="ast">La vista dixebrada permítete copiar o mover ficheros de mou fácil ente allugamientos.</li>
-      <li xml:lang="az">İkipanelli rejimdə faylları müxtəlif qovluqlar arasında cəld kopyalamq və köçürmək daha rahatdır.</li>
-      <li xml:lang="bs">Razdvaja pogled, dopuštajući lako kopiranje ili pomijeranje datoteka između lokacija</li>
-      <li xml:lang="ca">Divisió de visualització, permetent copiar o moure fitxers fàcilment entre les ubicacions.</li>
-      <li xml:lang="ca-valencia">Divisió de visualització, permetent copiar o moure fitxers fàcilment entre les ubicacions.</li>
-      <li xml:lang="da">Opdelt visning lader dig kopiere filer mellem placeringer på en nem måde.</li>
-      <li xml:lang="de">Geteilte Ansichten, damit können Sie einfach Daten zwischen Orten kopieren oder verschieben.</li>
-      <li xml:lang="el">Η διαίρεση επισκόπησης, σάς επιτρέπει με ευκολία να αντιγράφετε ή να μετακινείτε αρχεία μεταξύ διαφορετικών θέσεων.</li>
-      <li xml:lang="en-GB">Split view, allowing you to easily copy or move files between locations.</li>
-      <li xml:lang="es">Dividir vista, para poder copiar o mover archivos fácilmente entre distintas ubicaciones.</li>
-      <li xml:lang="et">Vaate poolitamise võimalus, mis muudab väga lihtsaks failide ühest kohast teise kopeerimise või liigutamise.</li>
-      <li xml:lang="eu">Ikuspegi zatitua, fitxategiak kokapen batetik bestera erraz kopiatu edo mugitzeko.</li>
-      <li xml:lang="fi">Näkymän puolitus, joka helpottaa tiedostojen kopiointia ja siirtämistä paikasta toiseen.</li>
-      <li xml:lang="fr">Affichage divisé, permettant de facilement copier ou déplacer des fichiers dans les différents emplacements.</li>
-      <li xml:lang="gl">Vista dividida, que lle permite copiar ou mover ficheiros facilmente entre dous lugares.</li>
-      <li xml:lang="hu">Osztott nézet, amely lehetővé teszi a fájlok könnyű másolását és áthelyezését a helyek között.</li>
-      <li xml:lang="ia">Scinde vista,  il permitte te copiar o mover facilemente files inter locationes.</li>
-      <li xml:lang="id">Tampilan belah, memungkinkanmu untuk menyalin atau memindah file antar lokasi dengan mudah.</li>
-      <li xml:lang="it">La vista divisa, che ti consente di copiare o spostare i file tra le diverse posizioni in maniera semplice.</li>
-      <li xml:lang="ko">분할 보기를 통해 위치간에 파일을 쉽게 복사하거나 이동할 수 있습니다.</li>
-      <li xml:lang="lt">Padalytas rodinys, leidžiantis lengvai kopijuoti ar perkelti failus tarp įvairių vietų.</li>
-      <li xml:lang="ml">എളുപ്പത്തിൽ ഫയലുകൾ പക‍‍ർത്തുന്നതിനും നീക്കുന്നതിനും സഹായിക്കുന്ന വേർതിരിച്ച കാഴ്ച</li>
-      <li xml:lang="nb">Delt visning, så du lett kan kopiere eller flytte filer mellom steder.</li>
-      <li xml:lang="nds">Deelt Ansicht, mit De Du Dateien eenfach twischen Steden koperen oder bewegen kannst.</li>
-      <li xml:lang="nl">Gesplitst beeld, waarmee u gemakkelijk bestanden kunt kopiëren of verplaatsen tussen locaties.</li>
-      <li xml:lang="nn">Delt vising, så du lett kan kopiera eller flytta filer mellom mapper.</li>
-      <li xml:lang="pl">Widok podzielony, umożliwiający łatwe kopiowane lub przenoszenie plików pomiędzy położeniami.</li>
-      <li xml:lang="pt">Uma vista dividida, que lhe permite facilmente copiar ou mover os ficheiros entre locais.</li>
-      <li xml:lang="pt-BR">Um modo de exibição dividido, permitindo-lhe copiar ou mover arquivos facilmente entre locais.</li>
-      <li xml:lang="ro">Desparte vizualizarea, ceea ce vă permite să copiați sau mutați ușor fișiere între amplasări.</li>
-      <li xml:lang="ru">Двухпанельный режим, в котором удобно копировать и перемещать файлы между разными папками;</li>
-      <li xml:lang="sk">Rozdelený pohľad, umožňuje vám jednoducho kopírovať alebo presúvať súbory medzi umiestneniami.</li>
-      <li xml:lang="sl">Razdeljeni pogled vam omogoča enostavno kopiranje ali premikanje datotek med mesti.</li>
-      <li xml:lang="sr">Подељени приказ, за лако копирање и премештање фајлова између локација.</li>
-      <li xml:lang="sr-Latn">Podeljeni prikaz, za lako kopiranje i premeštanje fajlova između lokacija.</li>
-      <li xml:lang="sr-ijekavian">Подељени приказ, за лако копирање и премештање фајлова између локација.</li>
-      <li xml:lang="sr-ijekavianlatin">Podeljeni prikaz, za lako kopiranje i premeštanje fajlova između lokacija.</li>
-      <li xml:lang="sv">Delad visning, som låter dig enkelt kopiera eller flytta filer mellan platser.</li>
-      <li xml:lang="tr">Dosyaları farklı konumlar arasında kolayca kopyalamaya ve taşımaya izin veren ayrık görünüm.</li>
-      <li xml:lang="uk">За допомогою режиму двопанельного розділеного перегляду ви зможе без проблем копіювати або пересувати файли між каталогами.</li>
-      <li xml:lang="vi">Khung xem chia đôi, cho phép bạn dễ dàng chép hay di chuyển tệp giữa các địa điểm.</li>
-      <li xml:lang="x-test">xxSplit view, allowing you to easily copy or move files between locations.xx</li>
-      <li xml:lang="zh-CN">拆分视图,让您可以方便地在不同位置间复制和移动文件。</li>
-      <li xml:lang="zh-TW">支援數個檢視模式,您也可以調整檢視模式的屬性。</li>
-      <li>Additional information and shortcuts are available as dock-able panels, allowing you to move them around freely and display exactly what you want.</li>
-      <li xml:lang="ar">تتوفر معلومات واختصارات إضافية كلوحات قابلة للرصف، مما يسمح لك بنقلها بحريّة وعرضها بالضبط كما تريد.</li>
-      <li xml:lang="ast">La información adicional y los atayos tán disponibles como paneles anclables que pues mover ande quieras y amosar como exautamente quieras.</li>
-      <li xml:lang="az">Əlavə məlumatlar və yarlıqlar yeri dəyişdirilə bilən panellər kimidir və bu sizə onları istədiyiniz yerə daşımağa və görünüşünü istədiyiniz kimi dəyişməyə imkan verir.</li>
-      <li xml:lang="bs">Dodatne informacije i kratice su dostupne kao usidreni paneli, dopuštajući vam da se krećete slobodno i prikažete šta želite.</li>
-      <li xml:lang="ca">Hi ha informació addicional i dreceres disponibles com a plafons que es poden acoblar, permetent moure'ls lliurement i mostrar exactament el què vulgueu.</li>
-      <li xml:lang="ca-valencia">Hi ha informació addicional i dreceres disponibles com a plafons que es poden acoblar, permetent moure'ls lliurement i mostrar exactament el què vulgueu.</li>
-      <li xml:lang="da">Yderligere information og genveje er tilgængelige som dokbare paneler, som lader dig flytte dem frit omkring og vise nøjagtigt det du vil have.</li>
-      <li xml:lang="de">Zusätzliche Informationen und Kurzbefehle sind als andockbare Seitenleisten vorhanden, diese Leisten können Sie beliebig verschieben und in ihnen die gewünschten Informationen anzeigen lassen.</li>
-      <li xml:lang="el">Πρόσθετες πληροφορίες και συντομεύσεις είναι διαθέσιμα ως προσαρτήσιμοι πίνακες, που σας επιτρέπουν να τα μετακινείτε ελεύθερα και να παρουσιάζετε ακριβώς αυτό που θέλετε.</li>
-      <li xml:lang="en-GB">Additional information and shortcuts are available as dock-able panels, allowing you to move them around freely and display exactly what you want.</li>
-      <li xml:lang="es">Hay disponible información adicional y accesos rápidos en forma de paneles separables para que se puedan mover libremente a la vez que muestran exactamente lo que prefiera el usuario.</li>
-      <li xml:lang="et">Lisateave ja otseteed dokitavate paneelidena, mida saab vabalt vajalikku kohta tõsta ja panna näitama just vajalikku teavet.</li>
-      <li xml:lang="eu">Informazio eta lasterbide osagarriak erabilgarri daude panel ainguragarrien bidez, haiek askatasun osoz mugitu ditzakezu eta zehazki nahi duzuna bistaratu.</li>
-      <li xml:lang="fi">Lisätiedoille ja oikoteille on paneelit, joita voi siirtää sekä näyttää ja piilottaa vapaasti.</li>
-      <li xml:lang="fr">Des informations supplémentaires et des raccourcis sont disponibles comme des panneaux ancrables, librement déplaçable et affichant exactement ce que vous voulez.</li>
-      <li xml:lang="gl">Información adicional e atallos dispoñíbeis como paneis acoplábeis que pode colocar en calquera parte e mostrar como prefira.</li>
-      <li xml:lang="hu">További információk és gyorsbillentyűk érhetők el dokkolható panelekként, lehetővé téve azok szabad mozgatását, illetve pontosan úgy megjelenítve, ahogy szeretné.</li>
-      <li xml:lang="ia">Information additional e vias breve es disponibile como pannellos de basin (dock-panels), il permitte mover los liberemente e monstrar los exactemente como tu vole.</li>
-      <li xml:lang="id">Informasi tambahan dan pintasan tersedia sebagai panel yang bisa di-dock, memungkinkanmu untuk memindahkannya secara bebas dan menampilkan apa yang kamu inginkan.</li>
-      <li xml:lang="it">Informazioni aggiuntive e scorciatoie sono disponibili come pannelli agganciabili, che possono essere spostati liberamente e visualizzare esattamente ciò che desideri.</li>
-      <li xml:lang="ko">추가 정보 및 바로 가기는 도킹 가능한 패널로 제공되므로 자유롭게 이동할 수 있고 원하는 대로 정확히 표시할 수 있습니다.</li>
-      <li xml:lang="lt">Papildoma informacija ir šaukiniai yra prieinami kaip pritvirtinami skydeliai, leidžiantys juos laisvai perkelinėti ir atvaizduoti būtent tai, ką norite.</li>
-      <li xml:lang="ml">നിങ്ങൾക്ക് ആവശ്യമായിട്ടുള്ള കുറുക്കുവഴികളും വിവരങ്ങളും എളുപ്പത്തിൽ തുറക്കാവുന്ന ഭാഗങ്ങളായി ലഭ്യമാണ്.</li>
-      <li xml:lang="nb">Mer informasjon og snarveier er tilgjengelige som dokkbare ruter, som du kan flytte fritt rundt og bruke til å vise akkurat hva du vil.</li>
-      <li xml:lang="nds">Bito-Infos un Leestekens laat sik as Paneels andocken, Du kannst ehr verschuven un se jüst dat wiesen laten, wat Du weten wullt.</li>
-      <li xml:lang="nl">Extra informatie en sneltoetsen zijn beschikbaar als vast te zetten panelen, die u vrij kunt verplaatsen en precies kunt tonen wat u wilt.</li>
-      <li xml:lang="nn">Tilleggsinformasjon og snarvegar er tilgjengelege som dokkpanel, som du kan flytta fritt rundt og bruka til å visa det du ønskjer.</li>
-      <li xml:lang="pl">Dodatkowe szczegóły i skróty dostępne jako dokowalne panele, umożliwiające ich dowolne przenoszenie i wyświetlanie dopasowane do potrzeb.</li>
-      <li xml:lang="pt">Estão disponíveis informações e atalhos adicionais como painéis acopláveis, permitindo-lhe movê-los à vontade e apresentar como desejar.</li>
-      <li xml:lang="pt-BR">As informações e atalhos adicionais estão disponíveis na forma de painéis acopláveis, permitindo-lhe movê-los à vontade e apresentar como desejar.</li>
-      <li xml:lang="ro">Informații suplimentare și scurtături sunt disponibile ca panouri andocabile, ceea ce vă permite să le mutați liber și să afișați exact ceea ce doriți.</li>
-      <li xml:lang="ru">Дополнительные сведения об элементах и ярлыки быстрого доступа в виде отдельных перемещаемых панелей;</li>
-      <li xml:lang="sk">Dodatočné informácie a skratky sú dostupné ako dokovateľné panely, umožňujúce vám ich voľný presun a zobrazenie presne tak, ako chcete.</li>
-      <li xml:lang="sl">Dodatne podrobnosti in bližnjice lahko vklopite kot sidrne pulte, ki jih lahko poljubno premikate in prikazujete.</li>
-      <li xml:lang="sr">Допунски подаци и пречице доступни су као усидриви панели, које можете поставити где вам одговара и подесити да приказују тачно оно што желите.</li>
-      <li xml:lang="sr-Latn">Dopunski podaci i prečice dostupni su kao usidrivi paneli, koje možete postaviti gde vam odgovara i podesiti da prikazuju tačno ono što želite.</li>
-      <li xml:lang="sr-ijekavian">Допунски подаци и пречице доступни су као усидриви панели, које можете поставити где вам одговара и подесити да приказују тачно оно што желите.</li>
-      <li xml:lang="sr-ijekavianlatin">Dopunski podaci i prečice dostupni su kao usidrivi paneli, koje možete postaviti gde vam odgovara i podesiti da prikazuju tačno ono što želite.</li>
-      <li xml:lang="sv">Ytterligare information och genvägar är tillgängliga som dockningsbara paneler, vilket låter dig flytta omkring dem fritt och visa exakt vad du vill.</li>
-      <li xml:lang="tr">Ek bilgi ve kısayollar kilitlenebilen panolar olarak kullanılabilirler, bu sayede onları istediğiniz gibi taşıyabilir ve tam istediğiniz gibi görüntülenmelerini sağlayabilirsiniz.</li>
-      <li xml:lang="uk">За допомогою бічних пересувних панелей ви зможете отримувати додаткову інформацію та пересуватися каталогами. Ви можете розташувати ці панелі так, як вам це зручно, і наказати програмі показувати на них саме те, що вам потрібно.</li>
-      <li xml:lang="vi">Thông tin bổ sung và các lối tắt hiện có dưới dạng các bảng lắp ghép được, cho phép bạn di chuyển chúng khắp nơi một cách tự do và hiển thị đúng những gì bạn muốn.</li>
-      <li xml:lang="x-test">xxAdditional information and shortcuts are available as dock-able panels, allowing you to move them around freely and display exactly what you want.xx</li>
-      <li xml:lang="zh-CN">额外信息,快捷键,可停靠面板,允许您自由地移动它们并且完全按照您想要的方式来显示。</li>
-      <li xml:lang="zh-TW">分割檢視讓您可以輕鬆複製或移動檔案。</li>
-      <li>Multiple tab support</li>
-      <li xml:lang="ar">دعم تعدّد الألسنة</li>
-      <li xml:lang="ast">Sofitu pa munches llingüetes</li>
-      <li xml:lang="az">Birdən çox vərəqi dəstəkləyir</li>
-      <li xml:lang="bs">Podrška za više kartica</li>
-      <li xml:lang="ca">Admet pestanyes múltiples</li>
-      <li xml:lang="ca-valencia">Admet pestanyes múltiples</li>
-      <li xml:lang="cs">Podpora vícero karet</li>
-      <li xml:lang="da">Understøttelse af flere faneblade</li>
-      <li xml:lang="de">Unterstützung für Unterfenster</li>
-      <li xml:lang="el">Υποστήριξη πολλαπλών καρτελών</li>
-      <li xml:lang="en-GB">Multiple tab support</li>
-      <li xml:lang="es">Admite varias pestañas</li>
-      <li xml:lang="et">Mitme kaardi kasutamise toetus.</li>
-      <li xml:lang="eu">Fitxen erabilera onartzen du</li>
-      <li xml:lang="fi">Useiden välilehtien tuki</li>
-      <li xml:lang="fr">Prise en charge des onglets multiples</li>
-      <li xml:lang="gl">Permite abrir varios separadores</li>
-      <li xml:lang="he">תמיכה בלשוניות מרובות</li>
-      <li xml:lang="hu">Több lap támogatása</li>
-      <li xml:lang="ia">Supporto de scheda multiple</li>
-      <li xml:lang="id">Dukungan multipel tab</li>
-      <li xml:lang="it">Supporto di schede multiple</li>
-      <li xml:lang="ko">다중 탭 지원</li>
-      <li xml:lang="lt">Daugelio kortelių palaikymas</li>
-      <li xml:lang="ml">അനേക  ടാബുകളുടെ പിൻതുണ</li>
-      <li xml:lang="nb">Støtte for flere faner</li>
-      <li xml:lang="nds">Ünnerstütten för Paneels</li>
-      <li xml:lang="nl">Ondersteuning voor meerdere tabbladen</li>
-      <li xml:lang="nn">Støtte for fleire faner</li>
-      <li xml:lang="pa">ਬਹੁ ਟੈਬ ਸਹਿਯੋਗ</li>
-      <li xml:lang="pl">Obsługa wielu kart</li>
-      <li xml:lang="pt">Suporte para várias páginas</li>
-      <li xml:lang="pt-BR">Suporte a várias abas</li>
-      <li xml:lang="ro">Suport pentru file multiple</li>
-      <li xml:lang="ru">Поддержка нескольких вкладок;</li>
-      <li xml:lang="sk">Podpora viacerých kariet</li>
-      <li xml:lang="sl">Podpora več zavihkom</li>
-      <li xml:lang="sr">Вишеструки језичци.</li>
-      <li xml:lang="sr-Latn">Višestruki jezičci.</li>
-      <li xml:lang="sr-ijekavian">Вишеструки језичци.</li>
-      <li xml:lang="sr-ijekavianlatin">Višestruki jezičci.</li>
-      <li xml:lang="sv">Stöd för flera flikar</li>
-      <li xml:lang="tr">Çoklu sekme desteği</li>
-      <li xml:lang="uk">Підтримка роботи з вкладками.</li>
-      <li xml:lang="vi">Hỗ trợ đa thẻ</li>
-      <li xml:lang="x-test">xxMultiple tab supportxx</li>
-      <li xml:lang="zh-CN">多标签支持</li>
-      <li xml:lang="zh-TW">額外資訊與嵌入式面板捷徑讓您可以輕易顯示您常用的項目。</li>
-      <li>Informational dialogues are displayed in an unobtrusive way.</li>
-      <li xml:lang="ar">حواريات المعلومات تُعرَض بطريقة غير مُزعجة.</li>
-      <li xml:lang="ast">Los diálogos informativos amuésense d'un mou non intrusivu.</li>
-      <li xml:lang="az">İnformasiya pəncərələri maneə olmadan görünür.</li>
-      <li xml:lang="bs">Informativni dijalozi su prikazani na nenametljiv način.</li>
-      <li xml:lang="ca">Els diàlegs informatius es mostren d'una manera no molesta.</li>
-      <li xml:lang="ca-valencia">Els diàlegs informatius es mostren d'una manera no molesta.</li>
-      <li xml:lang="da">Informationsdialoger vises på en ikke-forstyrrende måde.</li>
-      <li xml:lang="de">Informationen werden unaufdringlich angezeigt.</li>
-      <li xml:lang="el">Ενημερωτικοί διάλογοι εμφανίζονται με μη παρεμβατικό τρόπο.</li>
-      <li xml:lang="en-GB">Informational dialogues are displayed in an unobtrusive way.</li>
-      <li xml:lang="es">Los diálogos informativos se muestran de manera discreta.</li>
-      <li xml:lang="et">Teavitavate dialoogide näitamine kasutajat liigselt ärritamata.</li>
-      <li xml:lang="eu">Informatzeko elkarrizketa-koadroak trabarik ez sortzeko eran bistaratzen dira.</li>
-      <li xml:lang="fi">Informatiiviset valintaikkunat näytetään niin, että ne eivät keskeytä kaikkea muuta toimintaa.</li>
-      <li xml:lang="fr">Les dialogues d'information sont affiché de manière discrète.</li>
-      <li xml:lang="gl">Os diálogos de información móstranse dunha maneira non intrusiva.</li>
-      <li xml:lang="hu">Az információs párbeszédablakok szerény módon vannak megjelenítve.</li>
-      <li xml:lang="ia">Dialogos de information es monstrate de modo non importun.</li>
-      <li xml:lang="id">Dialog informasi ditampilkan dengan cara yang tidak mengganggu.</li>
-      <li xml:lang="it">Le finestre informative sono visualizzate in modo molto discreto.</li>
-      <li xml:lang="ko">정보 대화 상자는 눈에 거슬리지 않는 방식으로 표시됩니다.</li>
-      <li xml:lang="lt">Informaciniai dialogai yra rodomi neįkyriai.</li>
-      <li xml:lang="ml">വിവരങ്ങൾ അച്ചടക്കമുള്ള രീതിയിൽ ദൃശ്യമാകുന്നു.</li>
-      <li xml:lang="nb">Informasjonsdialoger vises på en lite påtrengende måte.</li>
-      <li xml:lang="nds">Informatschoondialogen kaamt Di nich in'n Weg.</li>
-      <li xml:lang="nl">Informatiedialogen worden op een prettige manier getoond.</li>
-      <li xml:lang="nn">Informasjonsdialogar vert viste på ein lite påtrengjande måte.</li>
-      <li xml:lang="pl">Pokazywanie informacyjnych okien dialogowych w nienatrętny sposób.</li>
-      <li xml:lang="pt">As janelas informativas são apresentadas de forma não-intrusiva.</li>
-      <li xml:lang="pt-BR">As janelas informativas são apresentadas de forma não-intrusiva.</li>
-      <li xml:lang="ro">Dialogurile informaționale sunt afișate într-un mod discret.</li>
-      <li xml:lang="ru">Ненавязчивый способ показа информационных диалогов;</li>
-      <li xml:lang="sk">Informačné dialógy sú zobrazené nevtieravým spôsobom.</li>
-      <li xml:lang="sl">Pogovorna okna s podrobnostmi so prikazana na nevsiljiv način.</li>
-      <li xml:lang="sr">Информативни дијалози који се ненаметљиво појављују.</li>
-      <li xml:lang="sr-Latn">Informativni dijalozi koji se nenametljivo pojavljuju.</li>
-      <li xml:lang="sr-ijekavian">Информативни дијалози који се ненаметљиво појављују.</li>
-      <li xml:lang="sr-ijekavianlatin">Informativni dijalozi koji se nenametljivo pojavljuju.</li>
-      <li xml:lang="sv">Dialogrutor med information visas på ett diskret sätt.</li>
-      <li xml:lang="tr">Bilgi pencereleri rahatsız etmeyecek şekilde görüntülenir.</li>
-      <li xml:lang="uk">Показ інформаційних панелей у зручний спосіб, що не заважає роботі.</li>
-      <li xml:lang="vi">Các hộp thoại thông tin được hiển thị một cách không gây phiền nhiễu.</li>
-      <li xml:lang="x-test">xxInformational dialogues are displayed in an unobtrusive way.xx</li>
-      <li xml:lang="zh-CN">信息对话框采用了非侵入式的方式来呈现。</li>
-      <li xml:lang="zh-TW">支援多分頁</li>
-      <li>Undo/redo support</li>
-      <li xml:lang="ar">دعم التراجع والإعادة</li>
-      <li xml:lang="ast">Sofitu pa la desfechura/refechura</li>
-      <li xml:lang="az">Geri qaytarmaq və təkrarlamaq dəstəyi</li>
-      <li xml:lang="bs">Podrška za poništavanje/ponavljanje akcija</li>
-      <li xml:lang="ca">Admet desfer/refer</li>
-      <li xml:lang="ca-valencia">Admet desfer/refer</li>
-      <li xml:lang="cs">Podpora zpět/vpřed</li>
-      <li xml:lang="da">Understøttelse af fortryd/gendan</li>
-      <li xml:lang="de">Unterstützung für Rückgängig/Wiederherstellen</li>
-      <li xml:lang="el">Υποστήριξη αναίρεσης/επανάληψης</li>
-      <li xml:lang="en-GB">Undo/redo support</li>
-      <li xml:lang="es">Admite las operaciones de deshacer y rehacer</li>
-      <li xml:lang="et">Tagasivõtmise ja uuestitegemise toetus.</li>
-      <li xml:lang="eu">Desegin/berregin onartzen du</li>
-      <li xml:lang="fi">Tuki muutosten kumoamiselle ja tekemiselle uudelleen</li>
-      <li xml:lang="fr">Prise en charge d'annulation et recommencement</li>
-      <li xml:lang="gl">Permite desfacer e refacer.</li>
-      <li xml:lang="he">תמיכה בביטול וביצוע חוזר</li>
-      <li xml:lang="hu">Visszavonás/ismétlés támogatás</li>
-      <li xml:lang="ia">Supporto de annulla/reface</li>
-      <li xml:lang="id">Dukungan urungkan/lanjurkan</li>
-      <li xml:lang="it">Supporto di annulla/rifai</li>
-      <li xml:lang="ko">실행 취소/다시 실행 지원</li>
-      <li xml:lang="lt">Atšaukimo/grąžinimo palaikymas</li>
-      <li xml:lang="ml">നിഷ്ക്രിയമാക്കുക/വീണ്ടും ചെയ്യുക പിന്തുണയ്ക്കുന്നു</li>
-      <li xml:lang="nb">Støtte for angring/omgjøring</li>
-      <li xml:lang="nds">Ünnerstütten för Torüchnehmen un Wedderherstellen</li>
-      <li xml:lang="nl">Ondersteuning ongedaan maken/opnieuw</li>
-      <li xml:lang="nn">Støtte for angring/omgjering</li>
-      <li xml:lang="pa">ਵਾਪਿਸ ਕਰੋ/ਪਰਤਾਉਣ ਸਹਿਯੋਗ</li>
-      <li xml:lang="pl">Obsługa cofnij/ponów</li>
-      <li xml:lang="pt">Suporte para desfazer/refazer</li>
-      <li xml:lang="pt-BR">Suporte para desfazer/refazer</li>
-      <li xml:lang="ro">Suport pentru desfacere/refacere</li>
-      <li xml:lang="ru">Отмена и возврат действий;</li>
-      <li xml:lang="sk">Podpora Späť/Znova</li>
-      <li xml:lang="sl">Podpora razveljavitvam/uveljavitvam</li>
-      <li xml:lang="sr">Опозивање и понављање.</li>
-      <li xml:lang="sr-Latn">Opozivanje i ponavljanje.</li>
-      <li xml:lang="sr-ijekavian">Опозивање и понављање.</li>
-      <li xml:lang="sr-ijekavianlatin">Opozivanje i ponavljanje.</li>
-      <li xml:lang="sv">Stöd för ångra och gör om</li>
-      <li xml:lang="tr">Geri alma/tekrarlama desteği</li>
-      <li xml:lang="uk">Підтримка скасовування та повторення дій.</li>
-      <li xml:lang="vi">Hỗ trợ đảo ngược/làm lại</li>
-      <li xml:lang="x-test">xxUndo/redo supportxx</li>
-      <li xml:lang="zh-CN">撤销/重做支持</li>
-      <li xml:lang="zh-TW">以不唐突的方式顯示資訊對話框。</li>
-      <li>Transparent network access through the KIO system.</li>
-      <li xml:lang="ar">اتصال شبكيّ مباشر باستخدام نظام KIO.</li>
-      <li xml:lang="ast">Accesu tresparente a la rede pente'l sistema KIO.</li>
-      <li xml:lang="az">KİO vasitəsi ilə şəbəkə fayl sisteminə şəffaf giriş.</li>
-      <li xml:lang="bs">Transparentni mrežni pristup kroz KIO sistem.</li>
-      <li xml:lang="ca">Accés transparent a la xarxa a través del sistema KIO.</li>
-      <li xml:lang="ca-valencia">Accés transparent a la xarxa a través del sistema KIO.</li>
-      <li xml:lang="cs">Transparentní přístup k síti pomocí systému KIO.</li>
-      <li xml:lang="da">Transparent netværksadgang igennem KIO-systemet</li>
-      <li xml:lang="de">Transparenter Netzwerkzugriff durch das KIO-System.</li>
-      <li xml:lang="el">Διαφανής δικτυακή πρόσβαση με το σύστημα KIO.</li>
-      <li xml:lang="en-GB">Transparent network access through the KIO system.</li>
-      <li xml:lang="es">Acceso transparente a la red a través del sistema KIO.</li>
-      <li xml:lang="et">Võrgu läbipaistev kasutamine KIO-moodulite süsteemi vahendusel.</li>
-      <li xml:lang="eu">Sare-atzipen gardena KIO sistemen bitartez.</li>
-      <li xml:lang="fi">Läpinäkyvä verkon käyttö KIO-järjestelmän välityksellä.</li>
-      <li xml:lang="fr">Accès au réseau transparent grâce au système des KIO.</li>
-      <li xml:lang="gl">Ofrece acceso transparente á rede mediante o sistema KIO.</li>
-      <li xml:lang="hu">Átlátszó hálózati hozzáférés a KIO rendszeren keresztül.</li>
-      <li xml:lang="ia">Accesso de rete transparente a transverso del systema KIO.</li>
-      <li xml:lang="id">Akses jaringan transparan melalui sistem KIO.</li>
-      <li xml:lang="it">Accesso trasparente alla rete tramite il sistema KIO.</li>
-      <li xml:lang="ko">KIO 시스템을 통한 투명한 네트워크 액세스.</li>
-      <li xml:lang="lt">Skaidri tinklo prieiga per KIO sistemą.</li>
-      <li xml:lang="ml">KIO സിസ്റ്റത്തിലൂടെ ശൃംഖലയെ സമീപിക്കുന്നു.</li>
-      <li xml:lang="nb">Gjennomsiktig nettverkstilgang via KIO-systemet.</li>
-      <li xml:lang="nds">Direkt Nettwarktogriep över dat KDE-In-/Utgaav-(KIO-)Moduulsysteem</li>
-      <li xml:lang="nl">Transparante toegang tot het netwerk via het KIO systeem.</li>
-      <li xml:lang="nn">Direkte nettverkstilgang via KIO-systemet.</li>
-      <li xml:lang="pl">Przezroczysty dostęp do sieci przez system KIO.</li>
-      <li xml:lang="pt">Acesso transparente à rede através do sistema KIO.</li>
-      <li xml:lang="pt-BR">Acesso transparente à rede através do sistema KIO.</li>
-      <li xml:lang="ro">Acces transparent la rețea prin sistemul KIO.</li>
-      <li xml:lang="ru">Прозрачный доступ к сетевым файловым системам при помощи KIO.</li>
-      <li xml:lang="sk">Transparentný prístup na sieť cez KIO systém.</li>
-      <li xml:lang="sl">Enostaven dostop do omrežja preko sistema KIO.</li>
-      <li xml:lang="sr">Прозиран мрежни приступ кроз систем К‑У/И.</li>
-      <li xml:lang="sr-Latn">Proziran mrežni pristup kroz sistem K‑U/I.</li>
-      <li xml:lang="sr-ijekavian">Прозиран мрежни приступ кроз систем К‑У/И.</li>
-      <li xml:lang="sr-ijekavianlatin">Proziran mrežni pristup kroz sistem K‑U/I.</li>
-      <li xml:lang="sv">Transparent nätverksåtkomst via I/O-slavsystemet.</li>
-      <li xml:lang="tr">KIO sistemi üzerinden şeffaf ağ erişimi.</li>
-      <li xml:lang="uk">Прозорий доступ до ресурсів у мережі за допомогою системи KIO.</li>
-      <li xml:lang="vi">Truy cập tệp mạng như tệp cục bộ thông qua hệ thống KIO.</li>
-      <li xml:lang="x-test">xxTransparent network access through the KIO system.xx</li>
-      <li xml:lang="zh-CN">通过 KIO 系统支持透明的网络访问。</li>
-      <li xml:lang="zh-TW">復原支援</li>
-    </ul>
+    <p>Dolphin is KDE's file manager that lets you navigate and browse the contents of your hard drives, USB sticks, SD cards, and more. Creating, moving, or deleting files and folders is simple and fast.</p>
+    <p xml:lang="az">Dolphin sizin sərt disklərinizin, USB yaddaş qurğularınızın, SD katlarınızın və s. tərkibindəkiləri nəzərdən keçirmənizə imkan verən fayl meneceridir. Faylların və qovluqların yaradılması, Köçürülməsi və ya silinməsi sadə, rahat və cəld icra edilir.</p>
+    <p xml:lang="ca">El Dolphin és el gestor de fitxers del KDE que permet navegar i explorar el contingut dels discs durs, memòries USB, targetes SD i més. Crear, moure o suprimir fitxers i carpetes és senzill i ràpid.</p>
+    <p xml:lang="el">Το Dolphin είναι ο διαχειριστής αρχείων του KDE για την πλοήγηση και την περιήγηση στο περιεχόμενο δίσκων, USB, SD καρτών και άλλων αποθηκευτικών μέσων. Η δημιουργία, η μεταφορά, η διαγραφή αρχείων και φακέλων είναι διαδικασίες απλές και γρήγορες.</p>
+    <p xml:lang="en-GB">Dolphin is KDE's file manager that lets you navigate and browse the contents of your hard drives, USB sticks, SD cards, and more. Creating, moving, or deleting files and folders is simple and fast.</p>
+    <p xml:lang="es">Dolphin es el gestor de archivos de KDE que le permite explorar el contenido de sus discos duros, memorias USB, tarjetas SD y más. Crear, mover o eliminar archivos y carpetas es simple y rápido.</p>
+    <p xml:lang="eu">Dolphin zure disko zurrun, USB memoria, SD txartel, eta gehiagoren edukian nabigatu eta arakatzen uzten dizun KDEren fitxategi-kudeatzailea da. Fitxategi eta karpetak sortzea, mugitzea, edo ezabatzea erraza eta azkarra da.</p>
+    <p xml:lang="fi">Dolphin on KDE:n tiedostonhallinta, jolla voit selata kiintolevyjen, USB-tikkujen, SD-korttien ja muiden tallennusvälineiden sisältöä. Tiedostojen ja kansioiden luominen, siirtäminen ja poistaminen on yksinkertaista ja helppoa.</p>
+    <p xml:lang="fr">Dolphin est le gestionnaire de fichiers de KDE, vous permettant de naviguer et d'explorer le contenu de vos disques durs, vos clés USB et bien plus. La création, le déplacement ou la suppression de fichiers et de dossiers sont simples et rapides.</p>
+    <p xml:lang="hu">A Dolphin a KDE fájlkezelője, amely lehetővé teszi a merevlemezei, USB-kulcsai, SD-kártyái és más adathordozói tartalmának böngészését. Gyorsan és egyszerűen hozhat létre, helyezhet át vagy törölhet vele fájlokat és mappákat.</p>
+    <p xml:lang="id">Dolphin adalah pengelola file KDE yang memungkinkan kamu menavigasi dan menelusuri konten hard drive, stik USB, kartu SD, dan lainnya. Membuat, memindahkan, atau menghapus file dan folder itu sederhana dan cepat.</p>
+    <p xml:lang="it">Dolphin è il gestore file di KDE che ti consente di navigare e sfogliare i contenuti dei tuoi dischi fissi, chiavette USB, schede SD e altro. Creare, spostare o eliminare file e cartelle è semplice e veloce.</p>
+    <p xml:lang="nl">Dolphin is de bestandsbeheerder van KDE die u laat navigeren en bladeren de inhoud van uw vaste schijven, USB-sticks, SD-cards en meer. Aanmaken, verplaatsen of verwijderen van bestanden en mappen is eenvoudig en snel.</p>
+    <p xml:lang="nn">Dolphin er KDEs filhandsamar, som du kan bruka til å bla gjennom innhaldet på harddiskar, minnepinnar/-kort og liknande. Han gjer det svært kjapt og enkelt å oppretta, flytta og sletta filer og mapper.</p>
+    <p xml:lang="pl">Dolphin jest programem do zarządzania plikami w KDE, który umożliwia przeglądanie zawartości twoich dysków twardych, pendrajwów, kart SD oraz więcej. Tworzenie, przenoszenie, czy usuwanie plików za jego pomocą jest proste i szybkie.</p>
+    <p xml:lang="pt">O Dolphin é o gestor de ficheiros do KDE que lhe permite navegar e percorrer o conteúdo dos seus discos rígidos, unidades USB, cartões SD, entre outros. A criação, movimentação ou remoção de ficheiros e pastas é simples e rápida.</p>
+    <p xml:lang="ru">Dolphin — диспетчер файлов, разработанный KDE. Он позволяет управлять содержимым, расположенным на разных носителях: жёстких и USB-дисках, SD-картах и прочих. Операции создания, перемещения и удаления файлов и папок выполняются в Dolphin просто и быстро.</p>
+    <p xml:lang="sk">Dolphin je správca súborov KDE, ktorý vám umožní prechádzať a prehľadávať obsah vašich pevných diskov, USB kľúčov, SD kariet a ďalších. Vytváranie, presúvanie alebo mazanie súborov a priečinkov je jednoduché a rýchle.</p>
+    <p xml:lang="sl">Dolphin je upravitelj datotek KDE, ki vam omogoča krmarjenje in brskanje po vsebini trdih diskov, USB ključkov, SD kartic in še več. Ustvarjanje, premikanje ali brisanje datotek in map je preprosto in hitro.</p>
+    <p xml:lang="sv">Dolphin är KDE:s filhanterare som låter dig navigera och bläddra i innehållet på hårddiskar, USB-minnen, SD-kort, med mera. Skapa, flytta eller ta bort filer och kataloger är enkelt och går snabbt.</p>
+    <p xml:lang="uk">Dolphin — програма для керування файлами KDE, за допомогою якої ви можете пересуватися та переглядати вміст дисків, флешок USB, SD-карток тощо. Створення, пересування або вилучення файлів та тек є простим і швидким завданням.</p>
+    <p xml:lang="vi">Dolphin là trình quản lí tệp của KDE, nó cho phép bạn điều hướng và duyệt nội dung các ổ cứng, các thẻ USB, thẻ SD và các thiết bị khác của bạn. Việc tạo, chuyển, hay xoá tệp và thư mục đều đơn giản và nhanh chóng.</p>
+    <p xml:lang="x-test">xxDolphin is KDE's file manager that lets you navigate and browse the contents of your hard drives, USB sticks, SD cards, and more. Creating, moving, or deleting files and folders is simple and fast.xx</p>
+    <p xml:lang="zh-CN">Dolphin 是 KDE 的文件管理器,您可以使用它来浏览硬盘、U 盘、SD 卡和其他存储设备中的内容,也可以方便快捷地创建、移动、删除文件和文件夹。</p>
+    <p>Dolphin contains plenty of productivity features that will save you time. The multiple tabs and split view features allow navigating multiple folders at the same time, and you can easily drag and drop files between views to move or copy them. Dolphin's right-click menu provides with many quick actions that let you compress, share, and duplicate files, among many other things. You can also add your own custom actions.</p>
+    <p xml:lang="az">Dolphin, səmərəliyi artıracaq bir çox funksiyalardan ibarətdir və bu da sizə vaxtınıza qənaət edəcəkdir. Birdən çox vərəq və bölünmə funksiyaları, qovluqlar arasında rahat hərəkət etməyə imkan verir, həmçinin, siz faylları, həmin görünən qovluqlar arasında tutub yerini dəyişməklə köçürə və kopyalaya bilərsiniz. Siçanın sağ düyməsi ilə açılan Dolpin menyusunda faylları sıxmağa, paylaşmağa, yeni surətini yaratmağa və bu kimi başqa bir çox cəld əməlləri təqdim edir. Bundan başqa siz həmçinin öz fərdi əməlinizi də bu menyuya daxil edə bilərsiniz.</p>
+    <p xml:lang="ca">El Dolphin conté moltes característiques de productivitat que us estalviaran temps. Les característiques de múltiples pestanyes i de vista dividida permeten navegar per diverses carpetes al mateix temps, i poder arrossegar i deixar anar els fitxers amb facilitat entre les vistes per a moure'ls o copiar-los. El menú contextual del Dolphin ofereix moltes accions ràpides que us permeten comprimir, compartir i duplicar els fitxers, entre moltes altres coses. També podreu afegir-hi les vostres pròpies accions personalitzades.</p>
+    <p xml:lang="el">Το Dolphin περιέχει ένα πλήθος χαρακτηριστικών παραγωγικότητας με τα οποία κερδίζετε χρόνο. Οι πολλαπλές καρτέλες και τα χαρακτηριστικά διαίρεσηςς της προβολής επιτρέπουν την ταυτόχρονη πλοήγηση σε πολλούς φακέλους και μπορείτε εύκολα να αντιγράψετε ή να μεταφέρετε με έλξη και απόθεση αρχεία μεταξύ προβολών. Το μενού του Dolphin με δεξί κλικ παρέχει πολλές και γρήγορες ενέργειες π.χ. για συμπίεση, διαμοιρασμό και αντιγραφή αρχείων. Μπορείτε επίσης να προσθέσετε τις δικές σας προσαρμοσμένες ενέργειες.</p>
+    <p xml:lang="en-GB">Dolphin contains plenty of productivity features that will save you time. The multiple tabs and split view features allow navigating multiple folders at the same time, and you can easily drag and drop files between views to move or copy them. Dolphin's right-click menu provides with many quick actions that let you compress, share, and duplicate files, among many other things. You can also add your own custom actions.</p>
+    <p xml:lang="es">Dolphin contiene muchas funciones de productividad que le ahorrarán tiempo. Las pestañas múltiples y las funciones de vista dividida permiten explorar varias carpetas al mismo tiempo, y puede arrastrar y soltar archivos fácilmente entre las vistas para moverlos o copiarlos. El menú de contexto de Dolphin ofrece muchas acciones rápidas que le permiten comprimir, compartir y duplicar archivos, entre otras muchas cosas. También puede añadir sus propias acciones personalizadas.</p>
+    <p xml:lang="eu">Dolphin-ek denbora aurreztuko dizuten produktibitate-ezaugarri ugari ditu. Fitxa anitzen eta ikuspegi zatituen ezaugarriek aldi berean karpeta anitz nabigatzen uzten dute, eta fitxategiak ikuspegien artean arrastatu eta jaregin ditzakezu haiek erraz mugitu edo kopiatzeko. Dolphin-en eskuin-klik laster-menuak, besteak beste, fitxategiak konprimatzeko, partekatzeko, eta bikoizteko ekintza azkarrak eskaintzen ditu. Zuk nahi dituzun ekintzak ere erants ditzakezu.</p>
+    <p xml:lang="fi">Dolphinin monet tuottavuusominaisuudet säästävät aikaasi. Välilehdet ja jaetut näkyvät mahdollistavat useamman kansion tarkastelun yhtä aikaa, jolloin tiedostoja voi helposti kopioida tai siirtää näkymästä toiseen vetämällä ja pudottamalla. Dolphinin kontekstivalikon tarjoamin pikatoiminnoin tiedostoja voi muun muassa pakata, jakaa ja monistaa. Myös omia mukautettuja toimintoja voi luoda.</p>
+    <p xml:lang="fr">Dolphin contient de nombreuses fonctionnalités pour la productivité vous permettant de gagner du temps. Les fonctionnalités d'onglets multiples et d'affichage scindé vous permettent de naviguer dans plusieurs dossiers en même temps. Vous pouvez aussi réaliser facilement des glisser et déposer entre les affichages pour les déplacer ou les copier. Le menu de Dolphin accessible par un clic droit fournit plusieurs actions rapides vous permettant de compresser, partager et dupliquer des fichiers, entre autres actions. Vous pouvez aussi ajouter votre propres actions personnalisées.</p>
+    <p xml:lang="hu">A Dolphin számos olyan funkcióval bír, amelyek időt spórolnak Önnek. A lapokkal és osztott nézetekkel egyszerre navigálhat több mappában egyszerre, és könnyen húzhat át fájlokat az egyik nézetből a másikba, átmásolva vagy áthelyezve azokat. A Dolphin jobb gombos menüje rengeteg gyors műveletet biztosít, például tömörítést, megosztást vagy fájlduplikálást. Akár saját műveletekkel is bővítheti azt.</p>
+    <p xml:lang="id">Dolphin mengandung banyak fitur produktivitas yang akan menghemat waktumu. Fitur multi tab dan tampilan terpisah memungkinkan navigasi beberapa folder secara bersamaan, dan kamu bisa dengan mudah menyeret dan meletakkan file antar tampilan untuk memindahkan atau menyalinnya. Menu klik kanan pada dolphin menyediakan banyak tindakan cepat yang memungkinkan kamu mengompres, berbagi, dan menggandakan file, di antara banyak hal lainnya. Kamu juga bisa menambahkan tindakan kustom milikmu sendiri.</p>
+    <p xml:lang="it">Dolphin contiene molte funzionalità di produttività che ti faranno risparmiare tempo.Le schede multiple e le funzioni di visualizzazione divisa consentono di navigare in più cartelle contemporaneamente e puoi facilmente trascinare e rilasciare i file tra le visualizzazioni per spostarli o copiarli. Il menu di scelta rapida di Dolphin fornisce molte azioni rapide che ti consentono di comprimere, condividere e duplicare file, tra molte altre cose. Puoi anche aggiungere le tue azioni personalizzate.</p>
+    <p xml:lang="nl">Dolphin bevat veel functies voor productiviteit die u tijd zal besparen. De vele tabbladen en gesplitste weergeeffuncties bieden het tegelijk navigeren in meerdere mappen en u kunt gemakkelijk bestanden slepen en loslaten tussen weergaven om ze te verplaatsen of te kopiëren. Het rechtsklikmenu van Dolphin biedt met veel snelle acties dat u bestanden kan comprimeren, delen en dupliceren, naast vele andere dingen. U kunt ook uw eigen aangepaste acties toevoegen.</p>
+    <p xml:lang="nn">Dolphin inneheld mange funksjonar laga for å spara deg tid. Med faner og delt vising kan du arbeida med fleire mapper samtidig, og du kan enkelt flytta eller kopiera filene ved å dra og sleppa dei mellom mappe­visingane. Og med høgreklikk­menyen får du kjapp tilgang til vanlege handlingar, for eksempel komprimering, deling og duplisering av filer. Du kan òg leggja til eigne handlingar her.</p>
+    <p xml:lang="pl">Dolphin zawiera wiele możliwości, zwiększających twoją sprawność i oszczędzających czas. Możliwość posiadania wielu kart i podzielonych widoków umożliwia poruszanie się po wielu katalogach w tym samym czasie, a także łatwe przeciąganie i upuszczanie plików pomiędzy widokami w celu ich przeniesienia lub skopiowania. Menu podręczne Dolphina dostępna pod prawym przyciskiem myszy otwiera menu szybkich działań, umożliwiające pakowanie, udostępnianie i powielanie plików. Istnieje także możliwość dodawania własnych działań.</p>
+    <p xml:lang="pt">O Dolphin contém diversas funcionalidades de produtividade que lhe pouparão tempo. As funcionalidades de várias páginas e áreas divididas permitem-lhe navegar em várias pastas ao mesmo tempo, podendo arrastar e largar ficheiros entre essas áreas para os copiar ou mover. O menu do botão direito do Dolphin oferece muitas acções rápidas que lhe permitem comprimir, partilhar e duplicar os ficheiros, entre muitas outras coisas. Também poderá adicionar as suas próprias acções personalizadas.</p>
+    <p xml:lang="ru">Приложение содержит множество функций, позволяющих экономить время. Использование вкладок и двухпанельный режим позволяют просматривать содержимое нескольких папок одновременно, а также копировать и перемещать файлы между ними простым перетаскиванием. Контекстное меню содержит набор действий, позволяющих управлять архивами, публиковать и копировать файлы, а также выполнять множество других операций. В контекстное меню возможно добавлять собственные действия.</p>
+    <p xml:lang="sk">Dolphin obsahuje množstvo funkcií produktivity, ktoré vám ušetria čas. Viaceré karty a funkcie rozdeleného zobrazenia umožňujú navigáciu vo viacerých priečinkoch súčasne. Medzi jednotlivými zobrazeniami môžete súbory jednoducho presúvať a presúvať alebo kopírovať. Ponuka pravým tlačidlom myši Dolphin ponúka mnoho rýchlych akcií, ktoré vám okrem iného umožňujú kompresiu, zdieľanie a duplikovanie súborov. Môžete tiež pridať svoje vlastné vlastné akcie.</p>
+    <p xml:lang="sl">Dolphin vsebuje veliko produktivnih funkcij, s katerimi boste prihranili čas. Več zavihkov in funkcij razdeljenega pogleda omogočajo sočasno krmarjenje po več mapah, tako da lahko datoteke enostavno vlečete in spustite med pogledi, da jih premaknete ali kopirate. Dolphinov meni z desnim klikom nudi veliko hitrih dejanj, ki vam med drugim omogočajo stiskanje, skupno rabo in podvajanje datotek. Dodate lahko tudi svoja dejanja po meri.</p>
+    <p xml:lang="sv">Dolphin innehåller mängder av produktivitetsfunktioner som sparar tid. Funktionerna för flera flikar och delad vy tillåter att flera kataloger navigeras samtidigt, och du kan enkelt dra och släppa filer mellan vyer för att flytta eller kopiera dem. Dolphins högerklicksmeny tillhandahåller många snabbåtgärder som låter dig bland annat komprimera, dela och duplicera filer. Du kan också lägga till egna åtgärder.</p>
+    <p xml:lang="uk">У Dolphin передбачено багато можливостей, які роблять вашу роботу продуктивнішою та заощаджують час. За допомогою можливостей використання декількох вкладок та поділу панелей перегляду ви можете переглядати вміст декількох тек одночасно і без проблем перетягувати і скидати пункти файлів і тек між різними панелями з метою копіювання або пересування. У контекстному меню Dolphin, яке можна викликати клацанням правою кнопкою миші, серед іншого, передбачено багато пунктів для швидкого доступу до стискання, оприлюднення та дублювання файлів. Крім того, ви можете додавати туди власні нетипові пункти дій.</p>
+    <p xml:lang="vi">Dolphin bao gồm nhiều tính năng năng suất sẽ giúp bạn tiết kiệm thời gian. Các tính năng đa thẻ và khung xem chia đôi cho phép điều hướng nhiều thư mục cùng lúc, và bạn có thể dễ dàng kéo thả tệp giữa các khung xem để chuyển hay chép chúng. Trình đơn chuột phải của Dolphin cung cấp nhiều hành động nhanh gọn cho phép bạn nén, chia sẻ, và tạo bản sao cho các tệp, cùng nhiều việc khác nữa. Bạn cũng có thể thêm các hành động tự chọn của mình.</p>
+    <p xml:lang="x-test">xxDolphin contains plenty of productivity features that will save you time. The multiple tabs and split view features allow navigating multiple folders at the same time, and you can easily drag and drop files between views to move or copy them. Dolphin's right-click menu provides with many quick actions that let you compress, share, and duplicate files, among many other things. You can also add your own custom actions.xx</p>
+    <p xml:lang="zh-CN">Dolphin 内建了许多有助于提高生产力的功能,助您省时省力。多标签页窗口、拆分视图等功能可以让您同时浏览多个文件夹,还可以在标签页和拆分的视图之间拖放、复制、移动文件。Dolphin 的右键菜单内建了许多快捷操作功能,例如压缩、分享、创建文件的副本等。您还可以将自定义操作添加到右键菜单。</p>
+    <p>Dolphin is very lightweight, but at the same time, you can adapt it to your specific needs. This means that you can carry out your file management exactly the way you want to. Dolphin supports three different view modes: a classic grid view of all the files, a more detailed view, and a tree view. You can also configure most of Dolphin's behavior.</p>
+    <p xml:lang="az">Dolphin çox yüngüldür, bununla belə siz onu öz ehtiyaclarınıza uyğunlaşdıra bilərsiniz. Bu o deməkdir ki, siz fayllarınızı istədiyiniz kimi idarə edə bilərsiniz. Dolphin üç müxtəlif baxış rejimini dəstəkləyir: bütün faylları üçün şəbəkə formasında klassik görünüş, budaqlanan şəkildə daha təfərrüatlı baxış forması. Siz həmçinin daha çox Dolphin davranışlarını tənzimləyə bilərsiniz.</p>
+    <p xml:lang="ca">El Dolphin és molt lleuger, però al mateix temps, podreu adaptar-lo a les vostres necessitats específiques. Això significa que podreu realitzar la gestió de fitxers exactament de la manera que vulgueu. El Dolphin admet tres modes de vista diferents: una vista de quadrícula clàssica amb tots els fitxers, una vista més detallada i una vista en arbre. També podreu configurar la major part del comportament del Dolphin.</p>
+    <p xml:lang="el">Το Dolphin είναι πολύ ελαφρύ, αλλά ταυτόχρονα και προσαρμόσιμο στις ανάγκες σας. Αυτό σημαίνει ότι μπορείτε να διεκπεραιώσετε τη διαχείριση αρχείων ακριβώς με τον τρόπο που θέλετε. Το Dolphin υποστηρίζει τρεις διαφορετικές λειτουργίες προβολής: το κλασικό πλέγμα με όλα τα αρχεία, μια λεπτομερή άποψη και μια δενδρική προβολή. Μπορείτε επίσης να διαμορφώσετε στο Dolphin το μεγαλύτερο τμήμα της συμπεριφοράς του.</p>
+    <p xml:lang="en-GB">Dolphin is very lightweight, but at the same time, you can adapt it to your specific needs. This means that you can carry out your file management exactly the way you want to. Dolphin supports three different view modes: a classic grid view of all the files, a more detailed view, and a tree view. You can also configure most of Dolphin's behaviour.</p>
+    <p xml:lang="es">Dolphin es muy ligero, aunque también se puede adaptar a sus necesidades específicas. Esto significa que puede realizar la gestión de sus archivos exactamente de la forma que desee. Dolphin admite tres modos de vista diferentes: una vista de cuadrícula clásica de todos los archivos, una vista más detallada y una vista de árbol. También puede configurar la mayor parte del comportamiento de Dolphin.</p>
+    <p xml:lang="eu">Dolphin oso arina da, baina, aldi berean, zure beharretara egoki dezakezu. Horrek esan nahi du fitxategien kudeaketa zuk nahi duzun modura egin dezakezula. Dolphin-ek hiru ikuspegi modu ezberdin onartzen ditu: fitxategi guztien sareta-ikuspegi klasiko bat, xehetasun gehiago dituen ikuspegi bat, eta zuhaitz-ikuspegi bat. Dolphin-en jokabide gehienak ere konfigura ditzakezu.</p>
+    <p xml:lang="fi">Dolphin on hyvin kevyt mutta samalla sovitettavissa tarpeisiisi, joten voit hallita tiedostojasi juuri kuten haluat. Dolphin tukee kolmea eri näkymää: perinteistä ruudukkoa, yksityiskohtaisempaa tilanäkymää ja puunäkymää. Useimpia Dolphinin toiminta-asetuksia voi säätää.</p>
+    <p xml:lang="fr">Dolphin est peu consommateur de ressources mais, en même temps, vous pouvez l'adapter à vos besoins spécifiques. Cela signifie que vous pouvez configurer votre gestion de fichiers, exactement comme vous le souhaitez. Dolphin prend en charge trois modes différents d'affichage : un affichage classique en grille pour tous vos fichiers, un affichage plus détaillé et un affichage en arborescence. Vous pouvez configurer la plupart des comportement de Dolphin.</p>
+    <p xml:lang="hu">A Dolphin pehelysúlyú, ugyanakkor a saját igényeire is szabhatja, vagyis a fájlkezelést teljesen a saját szája íze szerint végezheti. A Dolphin három nézetmódot támogat: a klasszikus rácsnézetet, a részletes nézetet és a fastruktúra nézetet. A legtöbb funkciót módosíthatja.</p>
+    <p xml:lang="id">Dolphin sangat ringan, tetapi pada saat yang sama, kamu bisa menyesuaikannya dengan kebutuhan spesifikmu. Ini berarti kamu bisa menjalankan pengelola file-mu persis seperti yang kamu inginkan. Dolphin mendukung tiga mode tampilan yang berbeda: tampilan kisi klasik dari semua file, tampilan yang lebih detail, dan tampilan ranting. Kamu juga bisa mengkonfigurasi sebagian besar perilaku Dolphin.</p>
+    <p xml:lang="it">Dolphin è molto leggero, ma allo stesso tempo puoi adattarlo alle tue esigenze specifiche. Ciò significa che puoi eseguire la gestione dei file esattamente come desideri. Dolphin supporta tre diverse modalità di visualizzazione: una classica visualizzazione a griglia di tutti i file, una visualizzazione più dettagliata e una visualizzazione ad albero. Puoi anche configurare la maggior parte del comportamento di Dolphin.</p>
+    <p xml:lang="nl">Dolphin is erg lichtgewicht, maar tegelijkertijd kunt u het aanpassen aan uw specifieke behoeften. Dit betekent dat u uw bestandsbeheer kunt uitvoeren exact op de manier die u wilt. Dolphin ondersteunt drie verschillende weergavemodi: een klassieke rasterweergave van alle bestanden, een meer gedetailleerde weergave en een boomstructuurweergave. U kunt het meeste van het gedrag van Dolphin ook configureren.</p>
+    <p xml:lang="nn">Dolpin krev få system­ressursar og kan tilpassast måten du arbeider på. Programmet støttar tre ulike visings­modusar – klassisk rutenett­vising av filer, detaljvising med metadata og trevising. Du kan òg finjustera det meste av funksjonaliteten i programmet.</p>
+    <p xml:lang="pl">Dolphin jest bardzo lekki, a zarazem może dostosować się do szczególnych wymagań. Oznacz to, że możesz działać na swoich plikach tak, jak chcesz. W Dolphinie można ustawić trzy różne tryby widoku: klasyczny siatkowy widok wszystkich plików, bardziej szczegółowy widok oraz widok drzewa. Możesz także zmienić ustawienia większości zachowań Dolphina.</p>
+    <p xml:lang="pt">O Dolphin é bastante leve mas, ao mesmo tempo, poderá adaptá-lo de acordo com as suas necessidades específicas. Isto significa que poderá desempenhar a sua gestão de ficheiros da forma exacta que necessita. O Dolphin suporta três modos de visualização diferentes: uma grelha clássica com todos os ficheiros, uma área mais detalhada e uma vista em árvore. Poderá também configurar a maioria do comportamento do Dolphin.</p>
+    <p xml:lang="ru">Dolphin не занимает много места и быстро работает, но при этом может быть настрое в соответствии с потребностями. Приложение поддерживает три режима просмотра: классический режим просмотра значков, более подробный режим и режим иерархического просмотра. Поведение приложения также может быть гибко настроено.</p>
+    <p xml:lang="sk">Delfín je veľmi ľahký, ale zároveň ho môžete prispôsobiť svojim konkrétnym potrebám. To znamená, že správu súborov môžete vykonávať presne tak, ako chcete. Dolphin podporuje tri rôzne režimy zobrazenia: klasické zobrazenie všetkých súborov v mriežke, podrobnejšie zobrazenie a stromové zobrazenie. Môžete tiež nakonfigurovať väčšinu správania Dolphin.</p>
+    <p xml:lang="sl">Dolphin je zelo lahek, hkrati pa ga lahko prilagodite svojim posebnim potrebam. To pomeni, da lahko izvajate upravljanje datotek natanko tako, kot želite. Dolphin podpira tri različne načine pogleda: klasičen mrežni pogled vseh datotek, podrobnejši pogled in drevesni pogled. Večino vedenja Dolphina lahko tudi nastavljate.</p>
+    <p xml:lang="sv">Dolphin är mycket lättviktigt, men samtidigt kan du anpassa det för dina specifika behov. Det betyder att du kan utföra filhantering precis på det sätt du vill. Dolphin stöder tre olika visningsmetoder: en klassisk rutnätsvy av alla filer, en mer detaljerad vy och en trädvy. Du kan också anpassa det mesta av Dolphins beteende.</p>
+    <p xml:lang="uk">Dolphin є дуже невибагливим до ресурсів. Втім, ви можете адаптувати програму до ваших потреб. Це означає, що ви можете здійснювати керування файлами саме так, як вам того хочеться. У Dolphin передбачено три різних режими перегляду: класичний перегляд таблицею усіх файлів, режим докладного перегляду та ієрархічний перегляд. Більшу частину характеристик роботи програми можна налаштувати Dolphin.</p>
+    <p xml:lang="vi">Dolphin rất nhẹ, nhưng đồng thời bạn có thể điều chỉnh nó theo các nhu cầu cụ thể của mình. Điều này nghĩa là bạn có thể thực hiện việc quản lí tệp đúng như cách bạn muốn. Dolphin hỗ trợ ba chế độ xem khác nhau: một khung xem tất cả các tệp ở dạng lưới cổ điển, một khung xem chi tiết hơn, và một khung xem dạng cây. Bạn cũng có thể cấu hình hầu hết tất cả các ứng xử của Dolphin.</p>
+    <p xml:lang="x-test">xxDolphin is very lightweight, but at the same time, you can adapt it to your specific needs. This means that you can carry out your file management exactly the way you want to. Dolphin supports three different view modes: a classic grid view of all the files, a more detailed view, and a tree view. You can also configure most of Dolphin's behavior.xx</p>
+    <p xml:lang="zh-CN">Dolphin 是一个体积轻巧的应用程序,您还可以按照自己的需要对其进行调整,让文件管理操作更加得心应手。Dolphin 的文件视图有三种模式:图标网格、简洁单栏、多栏详情。您还可以对 Dolphin 的程序行为进行配置。</p>
+    <p>Dolphin can display files and folders from many Internet cloud services and other remote machines as if they were right there on your desktop.</p>
+    <p xml:lang="az">Dolphin, bir çox İnternet və digər uzaq maşınların bulud xidmətindən faylları və qovluqları birbaşa sizin İş Masanızdakı kimi göstərəcəkdir.</p>
+    <p xml:lang="ca">El Dolphin pot mostrar els fitxers i carpetes de molts serveis en el núvol d'Internet i altres màquines remotes com si hi estiguessin al vostre escriptori.</p>
+    <p xml:lang="el">Το Dolphin εμφανίζει αρχεία και φακέλους από πολλές υπηρεσίες νέφους στο Διαδίκτυο και από άλλες απομακρυσμένες συσκευές σαν να βρίσκονταν στον υπολογιστή σας.</p>
+    <p xml:lang="en-GB">Dolphin can display files and folders from many Internet cloud services and other remote machines as if they were right there on your desktop.</p>
+    <p xml:lang="es">Dolphin puede mostrar archivos y carpetas de muchos servicios en la nube de Internet y otras máquinas remotas como si estuvieran directamente en el escritorio.</p>
+    <p xml:lang="eu">Dolphin-ek Interneteko hodei-zerbitzu askotako eta urruneko beste makina batzuetako fitxategi eta karpetak zure mahaigainean egongo balira bezala erakuts ditzake.</p>
+    <p xml:lang="fi">Dolphin osaa näyttää tiedostot ja kansiot monista internetin pilvipalveluista sekä etäkoneilta kuin ne olisivat välittömästi työpöydälläsi.</p>
+    <p xml:lang="fr">Dolphin peut afficher des fichiers et des dossiers à partir de nombreux services de stockage sur Internet (Cloud) et d'ordinateurs distants, comme s'ils étaient directement sur votre ordinateur.</p>
+    <p xml:lang="hu">A Dolphin úgy képes fájlokat megjeleníteni számos felhőszolgáltatásból vagy távoli gépekről, mintha azok a saját számítógépén lennének.</p>
+    <p xml:lang="id">Dolphin bisa menampilkan file dan folder dari banyak layanan cloud Internet dan mesin jarak jauh lainnya seolah-olah mereka ada di desktop-mu.</p>
+    <p xml:lang="it">Dolphin può visualizzare file e cartelle da molti servizi cloud Internet e altre macchine remote come se fossero direttamente sul tuo desktop.</p>
+    <p xml:lang="nl">Dolphin kan bestanden en mappen uit vele Internet-cloudservices en andere machines op afstand tonen alsof ze direct op uw bureaublad staan.</p>
+    <p xml:lang="nn">Dolphin kan visa filer og mapper frå mange sky­tenester og andre eksterne maskiner på same måte som om dei var lokale filer og mapper.</p>
+    <p xml:lang="pl">Dolphin może wyświetlać pliki i katalogi z wielu usług chmury w internecie oraz zdalnych komputerów tak, jakby były na twoim własnym komputerze.</p>
+    <p xml:lang="pt">O Dolphin consegue mostrar ficheiros e pastas de muitos serviços na 'cloud' da Internet e de outras máquinas remotas, como se estivesse na sua máquina local.</p>
+    <p xml:lang="ru">Dolphin поддерживает работу с облачными хранилищами и папками, размещёнными на сетевых устройствах, позволяя работать с ними как с локальными.</p>
+    <p xml:lang="sk">Dolphin dokáže zobraziť súbory a priečinky z mnohých internetových cloudových služieb a iných vzdialených počítačov, akoby sa nachádzali priamo na vašej pracovnej ploche.</p>
+    <p xml:lang="sl">Dolphin lahko prikazuje datoteke in mape iz številnih internetnih storitev v oblaku in druge oddaljene računalnike, kot da bi bili na namizju.</p>
+    <p xml:lang="sv">Dolphin kan visa filer och kataloger från många molntjänster på Internet och från andra datorer, som om de fanns direkt på ditt eget skrivbord.</p>
+    <p xml:lang="uk">Dolphin здатен показувати файли і теки із багатьох «хмарних» служб інтернету та віддалених комп'ютерів так, наче усі ці дані зберігаються на вашому робочому комп'ютері.</p>
+    <p xml:lang="vi">Dolphin có thể hiển thị tệp và thư mục từ nhiều dịch vụ đám mây Liên Mạng và các máy ở xa khác như thể chúng ở ngay trên máy tính của bạn vậy.</p>
+    <p xml:lang="x-test">xxDolphin can display files and folders from many Internet cloud services and other remote machines as if they were right there on your desktop.xx</p>
+    <p xml:lang="zh-CN">Dolphin 可以显示多种云存储服务和远程计算机中的文件和文件夹,与本机文件的体验完全一致。</p>
+    <p>Dolphin also comes with an integrated terminal that allows you to run commands on the current folder. You can extend the capabilities of Dolphin even further with powerful plugins to adapt it to your workflow. You can use the git integration plugin to interact with git repositories, or the Nextcloud plugin to synchronize your files online, and much more.</p>
+    <p xml:lang="az">Dolphin həmçinin daxilə quraşdırılmış terminalla təmin olunur ki, bu da cari qovluqda əmrləri başlatmağa imkan verir. Siz, Dolphinin imkanlarını iş prosesinizə uyğunlaşdıracaq, güclü qoşmaların köməyi ilə daha da genişləndirə bilərsiniz. Sİz git repazitoriyaları ilə işləmək üçün, qoşulmuş git inteqrasiya modulundan və ya fayllarınızı internet üzərindən sinxronlaşdırmaq üçün Nextcloud qoşmasından və s. istifadə edə bilərsiniz.</p>
+    <p xml:lang="ca">El Dolphin també ve amb un terminal integrat que permet executar ordres a la carpeta actual. Podreu estendre encara més les capacitats de Dolphin amb potents connectors per a que s'adapti al vostre flux de treball. Podreu utilitzar el connector d'integració amb el Git per a interactuar amb els repositoris de Git, o el connector de Nextcloud per a sincronitzar els vostres fitxers en línia, i molt més.</p>
+    <p xml:lang="el">Το Dolphin επίσης συνοδεύεται από ένα ενσωματωμένο τερματικό για να εκτελείτε εντολές στον τρέχοντα φάκελο. Μπορείτε να επεκτείνετε τις δυνατότητες του Dolphin ακόμη περισσότερο με ισχυρά πρόσθετα για να το προσαρμόσετε στη ροή των εργασιών σας. Μπορείτε να χρησιμοποιήσετε το ενσωματωμένο πρόσθετο του git για να αλληλεπιδράτε με αποθετήρια git, ή το πρόσθετο για το Nextcloud για να συγχρονίζετε τα επιγραμμικά αρχεία σας και υπάρχουν ακόμη πολλές δυνατότητες.</p>
+    <p xml:lang="en-GB">Dolphin also comes with an integrated terminal that allows you to run commands on the current folder. You can extend the capabilities of Dolphin even further with powerful plugins to adapt it to your workflow. You can use the git integration plugin to interact with git repositories, or the Nextcloud plugin to synchronise your files online, and much more.</p>
+    <p xml:lang="es">Dolphin también proporciona un terminal integrado que le permite ejecutar órdenes en la carpeta actual. Puede ampliar aún más las capacidades de Dolphin con potentes complementos para adaptarlo a su forma de trabajar. Puede usar el complemento de integración de git para interactuar con repositorios de git, o el complemento de Nextcloud para sincronizar archivos en línea, entre otras cosas.</p>
+    <p xml:lang="eu">Dolphin-ek terminal bat ere badu, uneko karpetan komandoak erabiltzeko aukera ematen duena. Dolphin-en gaitasunak are gehiago hedatu ditzakezu zure lan egiteko modura egokitzeko plugin ahaltsuak erabiliz. Git bateratzeko plugina erabil dezakezu Git gordetegiekin elkarreragiteko, edo Nextcloud plugina zure fitxategiak lerroan sinkronizatzeko, eta askoz gehiago.</p>
+    <p xml:lang="fi">Dolphinissa on myös sisään rakennettu pääte komentojen suorittamiseksi nykyisessä kansiossa. Dolphinin ominaisuuksia voi myös laajentaa sopimaan työtapaasi tehokkain laajennuksin. Git-integrointiliitännäinen auttaa toimimaan Git-lähteiden kanssa, Nextcloud-liitännäisellä voi synkronoida tiedostot verkkoon jne.</p>
+    <p xml:lang="fr">Dolphin est aussi livré avec un terminal intégré, vous permettant d'exécuter des commandes sur votre dossier courant. Vous pouvez étendre les fonctionnalités de Dolphin encore plus avec de puissants modules externes pour s'adapter à vos processus de travail. Vous pouvez utiliser le module externe « git » pour interagir avec les dépôts « git » ou le module externe « Nextcloud » pour synchroniser vos fichiers en ligne et bien d'autres choses encore.</p>
+    <p xml:lang="hu">A Dolphin tovább tartalmaz egy integrált terminálemulátort, amely lehetővé teszi parancsok futtatását az aktuális mappában. Bővítményekkel még jobban kiterjesztheti a Dolphin képességeinek határait. A git integrációs bővítménnyek git tárolókat kezelhet, a Nextcloud bővítménnyel szinkronizálhatja fájljait, és így tovább.</p>
+    <p xml:lang="id">Dolphin juga dilengkapi dengan terminal terintegrasi yang memungkinkan kamu menjalankan perintah di folder saat ini. Kamu bisa memperluas kemampuan Dolphin lebih jauh dengan plugin yang hebat untuk menyesuaikannya dengan alur kerja kamu. Kamu bisa menggunakan plugin integrasi git untuk berinteraksi dengan repositori git, atau plugin Nextcloud untuk menyinkronkan file-mu secara online, dan banyak lagi.</p>
+    <p xml:lang="it">Dolphin è inoltre dotato di un terminale integrato che ti consente di eseguire comandi nella cartella attuale. Puoi estendere ulteriormente le capacità di Dolphin con potenti estensioni per adattarlo al tuo flusso di lavoro. Puoi utilizzare l'estensione di integrazione con git per interagire con i depositi git o l'estensione Nextcloud per sincronizzare i tuoi file in linea e molto altro ancora.</p>
+    <p xml:lang="nl">Dolphin komt ook met een geïntegreerde terminal die u commando's laat uitvoeren in de huidige map. U kunt de mogelijkheden van Dolphin zelfs nog verder uitbreiden met krachtige plug-ins om deze aan uw werkmethode aan te passen. U kunt de git-integratie-plug-in gebruiken om met git-opslagruimten interacties uit te voeren of met de Nextcloud-plug-in om uw bestanden online te synchroniseren en nog veel meer.</p>
+    <p xml:lang="nn">Dolphin kjem med ein innebygd terminal som lèt deg køyra kommandoar frå gjeldande mappe. Du kan òg leggja til meir funksjonalitet i programmet ved hjelp av program­tillegg. Det finst blant anna eit tillegg for Git-integrasjon for å arbeida med Git-depot og tillegg for Nextcloud for å synkronisera filene dine via nettet.</p>
+    <p xml:lang="pl">Dolphin dostarczany jest także z wbudowanym terminalem, który umożliwia wykonywanie poleceń w bieżącym katalogu. Możliwości Dolphina można rozszerzyć jeszcze bardziej dzięki złożonym wtyczkom. Możesz użyć wtyczki wbudowującej git, aby działać na repozytoriach git lub wtyczkę Nextcloud, aby synchronizować swoje pliki będąc na łączach, a także wiele innych.</p>
+    <p xml:lang="pt">O Dolphin também tem um terminal integrado que lhe permite executar comandos na pasta actual. Poderá alargar ainda mais as capacidades do Dolphin com os 'plugins' poderosos existentes, de forma a adaptá-lo à sua forma de trabalhar. Poderá usar o 'plugin' de integração com o Git para interagir com os repositórios de Git ou o 'plugin' do Nextcloud para sincronizar os seus ficheiros na rede, entre muitos outros.</p>
+    <p xml:lang="ru">В приложение также встроен эмулятор терминала, который позволяет выполнять команды в текущей папке. Возможности Dolphin могут быть расширены в соответствии с потребностями использованием подключаемых внешних модулей. Такие модули позволяют, например, работать с репозиториями git, синхронизировать файлы с облачным хранилищем Nextcloud, а также многое другое.</p>
+    <p xml:lang="sk">Dolphin tiež prichádza s integrovaným terminálom, ktorý umožňuje spúšťať príkazy v aktuálnom priečinku. Možnosti Dolphinu môžete ešte rozšíriť pomocou výkonných doplnkov, ktoré ho prispôsobia vášmu pracovnému toku. Integračný doplnok git môžete použiť na interakciu s úložiskami git, alebo doplnok Nextcloud na synchronizáciu súborov online a oveľa viac.</p>
+    <p xml:lang="sl">Dolphin ima tudi integriran terminal, ki vam omogoča zagon ukazov v trenutni mapi. Zmogljivosti Dolphina lahko razširite še močnimi vtičniki, ki ga prilagodijo vašemu delovnemu toku. Lahko uporabite git integracijski vtičnik za interakcijo s skladišči git ali vtičnik Nextcloud za sinhronizacijo datotek v spletu in še veliko več.</p>
+    <p xml:lang="sv">Dolphin levereras också med en integrerad terminal som låter dig köra kommandon i den aktuella katalogen. Du kan utöka Dolphins funktioner ytterligare med kraftfulla insticksprogram för att anpassa programmet till ditt arbetsflöde. Du kan använda insticksprogrammet git-integrering för att komma åt git-arkiv, eller insticksprogrammet Nextcloud för att synkronisera filer på nätet, med mera.</p>
+    <p xml:lang="uk">Також до Dolphin вбудовано термінал, за допомогою якого ви можете виконувати команди у поточній теці. Ви можете розширити можливості Dolphin за допомогою потужних додатків з метою пристосування програми до ваших робочих процедур. Ви можете скористатися додатком інтеграції із git для роботи зі сховищами git або додатком Nextcloud для синхронізації ваших файлів зі сховищами даних в інтернеті тощо.</p>
+    <p xml:lang="vi">Dolphin còn đi kèm với một dòng lệnh tích hợp, cho phép bạn chạy lệnh ở thư mục hiện tại. Bạn thậm chí có thể mở rộng khả năng của Dolphin thêm nữa bằng các phần cài cắm mạnh mẽ để đáp ứng với cách làm việc của bạn. Bạn có thể dùng phần cài cắm tích hợp git để tương tác với các kho git, hay phần cài cắm Nextcloud để đồng bộ trực tuyến các tệp của bạn, và còn nhiều nữa.</p>
+    <p xml:lang="x-test">xxDolphin also comes with an integrated terminal that allows you to run commands on the current folder. You can extend the capabilities of Dolphin even further with powerful plugins to adapt it to your workflow. You can use the git integration plugin to interact with git repositories, or the Nextcloud plugin to synchronize your files online, and much more.xx</p>
+    <p xml:lang="zh-CN">Dolphin 还整合了命令行终端,可以在当前文件夹中执行命令行指令。您还可以通过插件来进一步增强 Dolphin 的功能,适应您的使用习惯。例如您可以使用 git 整合插件来与 git 源代码仓库进行交互,或者使用 Nextcloud 插件来在线同步文件等。</p>
   </description>
   <url type="homepage">https://kde.org/applications/en/dolphin</url>
   <url type="bugtracker">https://bugs.kde.org/enter_bug.cgi?format=guided&amp;product=dolphin</url>
       <caption xml:lang="sk">Správa súborov v Dolphin</caption>
       <caption xml:lang="sl">Upravljanje datotek v Dolphinu</caption>
       <caption xml:lang="sv">Filhantering i Dolphin</caption>
+      <caption xml:lang="tr">Dolphin'de dosya yönetimi</caption>
       <caption xml:lang="uk">Керування файлами у Dolphin</caption>
       <caption xml:lang="vi">Quản lí tệp trong Dolphin</caption>
       <caption xml:lang="x-test">xxFile management in Dolphinxx</caption>
index 16f12b989e7dbf699ccd12319d8350a966ea31d5..9143ddcb770023038ef245b2d61d05836216c7b6 100644 (file)
@@ -416,8 +416,12 @@ void DolphinSearchBox::init()
     m_facetsWidget->layout()->setSpacing(Dolphin::LAYOUT_SPACING_SMALL);
     connect(m_facetsWidget, &DolphinFacetsWidget::facetChanged, this, &DolphinSearchBox::slotFacetChanged);
 
+    // Put the options into a QScrollArea. This prevents increasing the view width
+    // in case that not enough width for the options is available.
+    QWidget* optionsContainer = new QWidget(this);
+
     // Apply layout for the options
-    QHBoxLayout* optionsLayout = new QHBoxLayout();
+    QHBoxLayout* optionsLayout = new QHBoxLayout(optionsContainer);
     optionsLayout->setContentsMargins(0, 0, 0, 0);
     optionsLayout->setSpacing(Dolphin::LAYOUT_SPACING_SMALL);
     optionsLayout->addWidget(m_fileNameButton);
@@ -429,11 +433,6 @@ void DolphinSearchBox::init()
     optionsLayout->addWidget(moreSearchToolsButton);
     optionsLayout->addStretch(1);
 
-    // Put the options into a QScrollArea. This prevents increasing the view width
-    // in case that not enough width for the options is available.
-    QWidget* optionsContainer = new QWidget(this);
-    optionsContainer->setLayout(optionsLayout);
-
     m_optionsScrollArea = new QScrollArea(this);
     m_optionsScrollArea->setFrameShape(QFrame::NoFrame);
     m_optionsScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
similarity index 76%
rename from src/settings/services/servicessettingspage.cpp
rename to src/settings/contextmenu/contextmenusettingspage.cpp
index fa064d8a13bf78fcb3126175157da2b30c6ced02..0723fee2ec52a2e282ebfeda9280c825c51fec2f 100644 (file)
@@ -4,10 +4,11 @@
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
-#include "servicessettingspage.h"
+#include "contextmenusettingspage.h"
 
 #include "dolphin_generalsettings.h"
 #include "dolphin_versioncontrolsettings.h"
+#include "dolphin_contextmenusettings.h"
 #include "settings/serviceitemdelegate.h"
 #include "settings/servicemodel.h"
 
@@ -36,13 +37,17 @@ namespace
     const char CopyToMoveToService[] ="_copy_to_move_to";
 }
 
-ServicesSettingsPage::ServicesSettingsPage(QWidget* parent) :
+ContextMenuSettingsPage::ContextMenuSettingsPage(QWidget* parent,
+                                                 const KActionCollection* actions,
+                                                 const QStringList& actionIds) :
     SettingsPageBase(parent),
     m_initialized(false),
     m_serviceModel(nullptr),
     m_sortModel(nullptr),
     m_listView(nullptr),
-    m_enabledVcsPlugins()
+    m_enabledVcsPlugins(),
+    m_actions(actions),
+    m_actionIds(actionIds)
 {
     QVBoxLayout* topLayout = new QVBoxLayout(this);
 
@@ -70,7 +75,7 @@ ServicesSettingsPage::ServicesSettingsPage(QWidget* parent) :
     m_listView->setModel(m_sortModel);
     m_listView->setItemDelegate(delegate);
     m_listView->setVerticalScrollMode(QListView::ScrollPerPixel);
-    connect(m_listView, &QListView::clicked, this, &ServicesSettingsPage::changed);
+    connect(m_listView, &QListView::clicked, this, &ContextMenuSettingsPage::changed);
 
 #ifndef Q_OS_WIN
     auto *downloadButton = new KNS3::Button(i18nc("@action:button", "Download New Services..."),
@@ -96,9 +101,49 @@ ServicesSettingsPage::ServicesSettingsPage(QWidget* parent) :
     std::sort(m_enabledVcsPlugins.begin(), m_enabledVcsPlugins.end());
 }
 
-ServicesSettingsPage::~ServicesSettingsPage() = default;
+ContextMenuSettingsPage::~ContextMenuSettingsPage() {
+}
+
+bool ContextMenuSettingsPage::entryVisible(const QString& id)
+{
+    if (id == "add_to_places") {
+        return ContextMenuSettings::showAddToPlaces();
+    } else if (id == "sort") {
+        return ContextMenuSettings::showSortBy();
+    } else if (id == "view_mode") {
+        return ContextMenuSettings::showViewMode();
+    } else if (id == "open_in_new_tab") {
+        return ContextMenuSettings::showOpenInNewTab();
+    } else if (id == "open_in_new_window") {
+        return ContextMenuSettings::showOpenInNewWindow();
+    } else if (id == "copy_location") {
+        return ContextMenuSettings::showCopyLocation();
+    } else if (id == "duplicate") {
+        return ContextMenuSettings::showDuplicateHere();
+    }
+    return false;
+}
+
+void ContextMenuSettingsPage::setEntryVisible(const QString& id, bool visible)
+{
+    if (id == "add_to_places") {
+        ContextMenuSettings::setShowAddToPlaces(visible);
+    } else if (id == "sort") {
+        ContextMenuSettings::setShowSortBy(visible);
+    } else if (id == "view_mode") {
+        ContextMenuSettings::setShowViewMode(visible);
+    } else if (id == "open_in_new_tab") {
+        ContextMenuSettings::setShowOpenInNewTab(visible);
+    } else if (id == "open_in_new_window") {
+        ContextMenuSettings::setShowOpenInNewWindow(visible);
+    } else if (id == "copy_location") {
+        ContextMenuSettings::setShowCopyLocation(visible);
+    } else if (id == "duplicate") {
+        ContextMenuSettings::setShowDuplicateHere(visible);
+    }
+}
 
-void ServicesSettingsPage::applySettings()
+void ContextMenuSettingsPage::applySettings()
 {
     if (!m_initialized) {
         return;
@@ -125,8 +170,11 @@ void ServicesSettingsPage::applySettings()
             configGroup.writeEntry("ShowDeleteCommand", checked);
             configGroup.sync();
         } else if (service == QLatin1String(CopyToMoveToService)) {
-            GeneralSettings::setShowCopyMoveMenu(checked);
-            GeneralSettings::self()->save();
+            ContextMenuSettings::setShowCopyMoveMenu(checked);
+            ContextMenuSettings::self()->save();
+        } else if (m_actionIds.contains(service)) {
+            setEntryVisible(service, checked);
+            ContextMenuSettings::self()->save();
         } else {
             showGroup.writeEntry(service, checked);
         }
@@ -146,7 +194,7 @@ void ServicesSettingsPage::applySettings()
     }
 }
 
-void ServicesSettingsPage::restoreDefaults()
+void ContextMenuSettingsPage::restoreDefaults()
 {
     QAbstractItemModel* model = m_listView->model();
     for (int i = 0; i < model->rowCount(); ++i) {
@@ -160,7 +208,7 @@ void ServicesSettingsPage::restoreDefaults()
     }
 }
 
-void ServicesSettingsPage::showEvent(QShowEvent* event)
+void ContextMenuSettingsPage::showEvent(QShowEvent* event)
 {
     if (!event->spontaneous() && !m_initialized) {
         loadServices();
@@ -179,7 +227,15 @@ void ServicesSettingsPage::showEvent(QShowEvent* event)
         addRow(QStringLiteral("edit-copy"),
                i18nc("@option:check", "'Copy To' and 'Move To' commands"),
                CopyToMoveToService,
-               GeneralSettings::showCopyMoveMenu());
+               ContextMenuSettings::showCopyMoveMenu());
+
+        // Add other built-in actions
+        for (const QString& id : m_actionIds) {
+            const QAction* action = m_actions->action(id);
+            if (action) {
+                addRow(action->icon().name(), action->text(), id, entryVisible(id));
+            }
+        }
 
         m_sortModel->sort(Qt::DisplayRole);
 
@@ -188,7 +244,7 @@ void ServicesSettingsPage::showEvent(QShowEvent* event)
     SettingsPageBase::showEvent(event);
 }
 
-void ServicesSettingsPage::loadServices()
+void ContextMenuSettingsPage::loadServices()
 {
     const KConfig config(QStringLiteral("kservicemenurc"), KConfig::NoGlobals);
     const KConfigGroup showGroup = config.group("Show");
@@ -243,7 +299,7 @@ void ServicesSettingsPage::loadServices()
     m_searchLineEdit->setFocus(Qt::OtherFocusReason);
 }
 
-void ServicesSettingsPage::loadVersionControlSystems()
+void ContextMenuSettingsPage::loadVersionControlSystems()
 {
     const QStringList enabledPlugins = VersionControlSettings::enabledPlugins();
 
@@ -260,7 +316,7 @@ void ServicesSettingsPage::loadVersionControlSystems()
     m_sortModel->sort(Qt::DisplayRole);
 }
 
-bool ServicesSettingsPage::isInServicesList(const QString &service) const
+bool ContextMenuSettingsPage::isInServicesList(const QString &service) const
 {
     for (int i = 0; i < m_serviceModel->rowCount(); ++i) {
         const QModelIndex index = m_serviceModel->index(i, 0);
@@ -271,10 +327,10 @@ bool ServicesSettingsPage::isInServicesList(const QString &service) const
     return false;
 }
 
-void ServicesSettingsPage::addRow(const QString &icon,
-                                  const QString &text,
-                                  const QString &value,
-                                  bool checked)
+void ContextMenuSettingsPage::addRow(const QString &icon,
+                                     const QString &text,
+                                     const QString &value,
+                                     bool checked)
 {
     m_serviceModel->insertRow(0);
 
@@ -284,4 +340,3 @@ void ServicesSettingsPage::addRow(const QString &icon,
     m_serviceModel->setData(index, value, ServiceModel::DesktopEntryNameRole);
     m_serviceModel->setData(index, checked, Qt::CheckStateRole);
 }
-
similarity index 66%
rename from src/settings/services/servicessettingspage.h
rename to src/settings/contextmenu/contextmenusettingspage.h
index b569852ae9e71065b2489ec17d0b78265fb48d9b..88b42770fbccf7cf36737005c04be3dcd9a7d3e3 100644 (file)
@@ -3,11 +3,13 @@
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
-#ifndef SERVICESSETTINGSPAGE_H
-#define SERVICESSETTINGSPAGE_H
+#ifndef CONTEXTMENUSETTINGSPAGE_H
+#define CONTEXTMENUSETTINGSPAGE_H
 
 #include "settings/settingspagebase.h"
 
+#include <KActionCollection>
+
 #include <QString>
 
 class QListView;
@@ -16,15 +18,17 @@ class ServiceModel;
 class QLineEdit;
 
 /**
- * @brief Page for the 'Services' settings of the Dolphin settings dialog.
+ * @brief Configurations for services in the context menu.
  */
-class ServicesSettingsPage : public SettingsPageBase
+class ContextMenuSettingsPage : public SettingsPageBase
 {
     Q_OBJECT
 
 public:
-    explicit ServicesSettingsPage(QWidget* parent);
-    ~ServicesSettingsPage() override;
+    explicit ContextMenuSettingsPage(QWidget* parent,
+                                     const KActionCollection* actions,
+                                     const QStringList& actionIds);
+    ~ContextMenuSettingsPage() override;
 
     /** @see SettingsPageBase::applySettings() */
     void applySettings() override;
@@ -56,6 +60,8 @@ private:
                 const QString &text,
                 const QString &value,
                 bool checked);
+    bool entryVisible(const QString& id);
+    void setEntryVisible(const QString& id, bool visible);
 
 private:
     bool m_initialized;
@@ -64,6 +70,8 @@ private:
     QListView* m_listView;
     QLineEdit *m_searchLineEdit;
     QStringList m_enabledVcsPlugins;
+    const KActionCollection* m_actions;
+    const QStringList m_actionIds;
 };
 
 #endif
diff --git a/src/settings/dolphin_contextmenusettings.kcfg b/src/settings/dolphin_contextmenusettings.kcfg
new file mode 100644 (file)
index 0000000..9e70565
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+      http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
+    <kcfgfile name="dolphinrc"/>
+    <group name="ContextMenu">
+        <entry name="ShowCopyMoveMenu" type="Bool">
+            <label>Show 'Copy To' and 'Move To' commands in context menu</label>
+            <default>false</default>
+        </entry>
+        <entry name="ShowAddToPlaces" type="Bool">
+            <label>Show 'Add to Places' in context menu.</label>
+            <default>true</default>
+        </entry>
+        <entry name="ShowSortBy" type="Bool">
+            <label>Show 'Sort By' in context menu.</label>
+            <default>true</default>
+        </entry>
+        <entry name="ShowViewMode" type="Bool">
+            <label>Show 'View Mode' in context menu.</label>
+            <default>true</default>
+        </entry>
+        <entry name="ShowOpenInNewTab" type="Bool">
+            <label>Show 'Open in New Tab' and 'Open in New Tabs' in context menu.</label>
+            <default>true</default>
+        </entry>
+        <entry name="ShowOpenInNewWindow" type="Bool">
+            <label>Show 'Open in New Window' in context menu.</label>
+            <default>true</default>
+        </entry>
+        <entry name="ShowCopyLocation" type="Bool">
+            <label>Show 'Copy Location' in context menu.</label>
+            <default>true</default>
+        </entry>
+        <entry name="ShowDuplicateHere" type="Bool">
+            <label>Show 'Duplicate Here' in context menu.</label>
+            <default>true</default>
+        </entry>
+    </group>
+</kcfg>
diff --git a/src/settings/dolphin_contextmenusettings.kcfgc b/src/settings/dolphin_contextmenusettings.kcfgc
new file mode 100644 (file)
index 0000000..b50e98f
--- /dev/null
@@ -0,0 +1,4 @@
+File=dolphin_contextmenusettings.kcfg
+ClassName=ContextMenuSettings
+Singleton=yes
+Mutators=true
index 9d05a8ab004e14bfefd4eeedb0e95c146c432ace..c8238f1e827df548c91915c104c0da315c6d1615 100644 (file)
@@ -52,5 +52,9 @@
             <label>Recursive directory size limit</label>
             <default>10</default>
         </entry>
+        <entry name="UseShortRelativeDates" type="Bool">
+            <label>if true we use short relative dates, if not short dates</label>
+            <default>true</default>
+        </entry>
     </group>
 </kcfg>
index c397b2945124a49ab4867ff608337842c8d75e3d..bc1cf72aab3552490147a53770053da08a9e2143 100644 (file)
             <label>Close active pane when toggling off split view</label>
             <default>true</default>
         </entry>
-        <entry name="ShowToolTips" type="Bool">
-            <label>Show tooltips</label>
+        <entry name="OpenNewTabAfterLastTab" type="Bool">
+            <label>New tab will be open after last one</label>
             <default>false</default>
         </entry>
-        <entry name="ShowCopyMoveMenu" type="Bool">
-            <label>Show 'Copy To' and 'Move To' commands in context menu</label>
+        <entry name="ShowToolTips" type="Bool">
+            <label>Show tooltips</label>
             <default>false</default>
         </entry>
         <entry name="ViewPropsTimestamp" type="DateTime" >
index 9d8fb032a705d6a956db7bbb39a13fa4f555659e..4d759c91106c152a4d2e355dd5e4f7a5538fb4b6 100644 (file)
@@ -10,7 +10,7 @@
 #include "dolphinmainwindow.h"
 #include "general/generalsettingspage.h"
 #include "navigation/navigationsettingspage.h"
-#include "services/servicessettingspage.h"
+#include "contextmenu/contextmenusettingspage.h"
 #include "startup/startupsettingspage.h"
 #include "trash/trashsettingspage.h"
 #include "viewmodes/viewsettingspage.h"
@@ -28,7 +28,7 @@
 #include <QCloseEvent>
 #include <QPushButton>
 
-DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent) :
+DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent, KActionCollection* actions) :
     KPageDialog(parent),
     m_pages(),
     m_unsavedChanges(false)
@@ -77,12 +77,20 @@ DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent) :
     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("preferences-system-services")));
-    connect(servicesSettingsPage, &ServicesSettingsPage::changed, this, &DolphinSettingsDialog::enableApply);
+    // Context Menu
+    auto contextMenuSettingsPage = new ContextMenuSettingsPage(this, actions, {
+        QStringLiteral("add_to_places"),
+        QStringLiteral("sort"),
+        QStringLiteral("view_mode"),
+        QStringLiteral("open_in_new_tab"),
+        QStringLiteral("open_in_new_window"),
+        QStringLiteral("copy_location"),
+        QStringLiteral("duplicate")
+    });
+    KPageWidgetItem* contextMenuSettingsFrame = addPage(contextMenuSettingsPage,
+                                                        i18nc("@title:group", "Context Menu"));
+    contextMenuSettingsFrame->setIcon(QIcon::fromTheme(QStringLiteral("application-menu")));
+    connect(contextMenuSettingsPage, &ContextMenuSettingsPage::changed, this, &DolphinSettingsDialog::enableApply);
 
     // Trash
     SettingsPageBase* trashSettingsPage = nullptr;
@@ -111,7 +119,7 @@ DolphinSettingsDialog::DolphinSettingsDialog(const QUrl& url, QWidget* parent) :
     m_pages.append(startupSettingsPage);
     m_pages.append(viewSettingsPage);
     m_pages.append(navigationSettingsPage);
-    m_pages.append(servicesSettingsPage);
+    m_pages.append(contextMenuSettingsPage);
     if (trashSettingsPage) {
         m_pages.append(trashSettingsPage);
     }
index 7749a3ad89ec715d4dee740068b1d25e5dc1aaf6..1f1a5145649079a347f2a506b0b8877895036339 100644 (file)
@@ -8,6 +8,7 @@
 #define DOLPHINSETTINGSDIALOG_H
 
 #include <KPageDialog>
+#include <KActionCollection>
 
 class QUrl;
 class SettingsPageBase;
@@ -22,7 +23,7 @@ class DolphinSettingsDialog : public KPageDialog
     Q_OBJECT
 
 public:
-    explicit DolphinSettingsDialog(const QUrl& url, QWidget* parent = nullptr);
+    explicit DolphinSettingsDialog(const QUrl& url, QWidget* parent = nullptr, KActionCollection* actions = {});
     ~DolphinSettingsDialog() override;
 
 signals:
index d29b63b7dc3d2a902b057e559bcb2100f6bc55a4..26b7deb88a357c61ff4f594b0b7c5753f664d577 100644 (file)
@@ -38,7 +38,6 @@ ConfigurePreviewPluginDialog::ConfigurePreviewPluginDialog(const QString& plugin
     setMinimumWidth(400);
 
     auto layout = new QVBoxLayout(this);
-    setLayout(layout);
 
     if (previewPlugin) {
         auto configurationWidget = previewPlugin->createConfigurationWidget();
@@ -65,6 +64,6 @@ ConfigurePreviewPluginDialog::ConfigurePreviewPluginDialog(const QString& plugin
     layout->addWidget(buttonBox);
 
     auto okButton = buttonBox->button(QDialogButtonBox::Ok);
-    okButton->setShortcut(Qt::CTRL + Qt::Key_Return);
+    okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
     okButton->setDefault(true);
 }
index f2fb604b2f4da98d2cc20f4f12d96a36fac089a9..3a0aa779bdfc3defc179739d77731508701f4ea2 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <KLocalizedString>
 #include <KPluginFactory>
-#include <KPluginLoader>
 #include <kconfigwidgets_version.h>
 
 #include <QTabWidget>
index 725fc83f0ebf96edd1cf2e0ad93ffd2d463f021c..74fce85c7f3ac2155b5421840034b572a9c27dad 100644 (file)
@@ -10,7 +10,6 @@
 #include <kconfigwidgets_version.h>
 
 #include <KPluginFactory>
-#include <KPluginLoader>
 
 #include <QVBoxLayout>
 
diff --git a/src/settings/kcm/kcmdolphinservices.cpp b/src/settings/kcm/kcmdolphinservices.cpp
deleted file mode 100644 (file)
index 2a411f9..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2009 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#include "kcmdolphinservices.h"
-
-#include "settings/services/servicessettingspage.h"
-
-#include <kconfigwidgets_version.h>
-#include <KPluginFactory>
-#include <KPluginLoader>
-
-#include <QVBoxLayout>
-
-K_PLUGIN_FACTORY(KCMDolphinServicesConfigFactory, registerPlugin<DolphinServicesConfigModule>(QStringLiteral("dolphinservices"));)
-
-DolphinServicesConfigModule::DolphinServicesConfigModule(QWidget* parent, const QVariantList& args) :
-    KCModule(parent, args),
-    m_services(nullptr)
-{
-    setButtons(KCModule::Default | KCModule::Help);
-
-    QVBoxLayout* topLayout = new QVBoxLayout(this);
-    topLayout->setContentsMargins(0, 0, 0, 0);
-
-    m_services = new ServicesSettingsPage(this);
-    connect(m_services, &ServicesSettingsPage::changed, this, &DolphinServicesConfigModule::markAsChanged);
-    topLayout->addWidget(m_services, 0, {});
-}
-
-DolphinServicesConfigModule::~DolphinServicesConfigModule()
-{
-}
-
-void DolphinServicesConfigModule::save()
-{
-    m_services->applySettings();
-}
-
-void DolphinServicesConfigModule::defaults()
-{
-    m_services->restoreDefaults();
-}
-
-#include "kcmdolphinservices.moc"
diff --git a/src/settings/kcm/kcmdolphinservices.desktop b/src/settings/kcm/kcmdolphinservices.desktop
deleted file mode 100644 (file)
index 2e188f3..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-Name=Dolphin Services
-Name[ar]=خدمات دولفين
-Name[ast]=Servicios de Dolphin
-Name[az]=Dolphin xidmətləri
-Name[ca]=Serveis del Dolphin
-Name[ca@valencia]=Serveis del Dolphin
-Name[cs]=Služby Dolphinu
-Name[da]=Dolphin-tjenester
-Name[de]=Dolphin-Dienste
-Name[el]=Dolphin Υπηρεσίες
-Name[en_GB]=Dolphin Services
-Name[es]=Servicios de Dolphin
-Name[et]=Dolphini teenused
-Name[eu]=Dolphin zerbitzuak
-Name[fi]=Dolphin – palvelut
-Name[fr]=Services de Dolphin
-Name[gl]=Servizos de Dolphin
-Name[he]=שרותי Dolphin
-Name[hu]=Dolphin szolgáltatások
-Name[ia]=Servicios de Dolphin
-Name[id]=Layanan Dolphin
-Name[it]=Servizi di Dolphin
-Name[ja]=Dolphin サービス
-Name[ko]=Dolphin 서비스
-Name[lt]=Dolphin paslaugos
-Name[lv]=Dolphin servisi
-Name[ml]=ഡോള്‍ഫിന്‍ സേവനങ്ങള്‍
-Name[nb]=Dolphin-tjenester
-Name[nl]=Dolphin-services
-Name[nn]=Dolphin-tenester
-Name[pa]=ਡਾਲਫਿਨ ਸੇਵਾਵਾਂ
-Name[pl]=Usługi Dolphina
-Name[pt]=Serviços do Dolphin
-Name[pt_BR]=Serviços do Dolphin
-Name[ro]=Dolphin – Servicii
-Name[ru]=Действия Dolphin
-Name[sk]=Služby Dolphinu
-Name[sl]=Dolphin - storitve
-Name[sr]=Делфинови сервиси
-Name[sr@ijekavian]=Делфинови сервиси
-Name[sr@ijekavianlatin]=Dolphinovi servisi
-Name[sr@latin]=Dolphinovi servisi
-Name[sv]=Dolphin tjänster
-Name[tr]=Dolphin Servisleri
-Name[uk]=Служби Dolphin
-Name[vi]=Các dịch vụ Dolphin
-Name[x-test]=xxDolphin Servicesxx
-Name[zh_CN]=Dolphin 服务
-Name[zh_TW]=Dolphin 服務
-
-[Desktop Entry]
-Icon=preferences-system-services
-Type=Service
-X-KDE-ServiceTypes=KCModule
-
-X-KDE-Library=kcm_dolphinservices
-X-KDE-PluginKeyword=dolphinservices
-X-DocPath=dolphin/index.html#preferences-dialog-services
-Name=Services
-Name[ar]=الخدمات
-Name[ast]=Servicios
-Name[az]=Xidmətlər
-Name[ca]=Serveis
-Name[ca@valencia]=Serveis
-Name[cs]=Služby
-Name[da]=Tjenester
-Name[de]=KDE-Dienste
-Name[el]=Υπηρεσίες
-Name[en_GB]=Services
-Name[es]=Servicios
-Name[et]=Teenused
-Name[eu]=Zerbitzuak
-Name[fi]=Palvelut
-Name[fr]=Services
-Name[gl]=Servizos
-Name[he]=שירותים
-Name[hu]=Szolgáltatások
-Name[ia]=Servicios
-Name[id]=Layanan
-Name[it]=Servizi
-Name[ja]=サービス
-Name[ko]=서비스
-Name[lt]=Paslaugos
-Name[lv]=Servisi
-Name[ml]=സേവനങ്ങള്‍
-Name[nb]=Tjenester
-Name[nl]=Services
-Name[nn]=Tenester
-Name[pa]=ਸੇਵਾਵਾਂ
-Name[pl]=Usługi
-Name[pt]=Serviços
-Name[pt_BR]=Serviços
-Name[ro]=Servicii
-Name[ru]=Действия
-Name[sk]=Služby
-Name[sl]=Storitve
-Name[sr]=Сервиси
-Name[sr@ijekavian]=Сервиси
-Name[sr@ijekavianlatin]=Servisi
-Name[sr@latin]=Servisi
-Name[sv]=Tjänster
-Name[tr]=Servisler
-Name[uk]=Служби
-Name[vi]=Các dịch vụ
-Name[x-test]=xxServicesxx
-Name[zh_CN]=服务
-Name[zh_TW]=服務
-Comment=Configure file manager services
-Comment[ar]=اضبط خدمات مدير الملفّات
-Comment[ast]=Configura los servicios del xestor de ficheros
-Comment[az]=Fayl meneceri xidmətlərini tənzimləmək
-Comment[ca]=Configura els serveis del gestor de fitxers
-Comment[ca@valencia]=Configura els serveis del gestor de fitxers
-Comment[cs]=Nastavení služeb správce souborů
-Comment[da]=Indstil filhåndteringstjenester
-Comment[de]=Dateiverwaltungs-Dienste einrichten
-Comment[el]=Διαμόρφωση υπηρεσιών του διαχειριστή αρχείων
-Comment[en_GB]=Configure file manager services
-Comment[es]=Configurar los servicios del gestor de archivos
-Comment[et]=Failihalduri teenuste seadistamine
-Comment[eu]=Konfiguratu fitxategi-kudeatzailearen zerbitzuak
-Comment[fi]=Tiedostonhallinnan palveluasetukset
-Comment[fr]=Configuration des services du gestionnaire de fichiers
-Comment[gl]=Configurar servizos de xestores de ficheiros.
-Comment[hu]=A fájlkezelő szolgáltatásainak beállítása
-Comment[ia]=Configura servicios del gerente de file
-Comment[id]=Konfigurasikan layanan pengelola file
-Comment[it]=Configura i servizi del gestore dei file
-Comment[ja]=ファイルマネージャのサービスを設定します
-Comment[ko]=파일 관리자 서비스 구성
-Comment[lt]=Konfigūruoti failų tvarkytuvės paslaugas
-Comment[lv]=Konfigurēt datņu pārvaldnieka servisus
-Comment[ml]=ഫയല്‍ മാനേജർ സേവനങ്ങള്‍ ക്രമീകരിയ്ക്കുക
-Comment[nb]=Sett opp tjenester i filbehandleren
-Comment[nl]=Bestandsbeheerderservices configureren
-Comment[nn]=Set opp tenester i filhandsamaren
-Comment[pa]=ਫਾਇਲ ਮੈਨੇਜਰ ਦੀਆਂ ਸਰਵਿਸਾਂ ਦੀ ਸੰਰਚਨਾ
-Comment[pl]=Ustawienia usług zarządzania plikami
-Comment[pt]=Configurar os serviços do gestor de ficheiros
-Comment[pt_BR]=Configura os serviços do gerenciador de arquivos
-Comment[ro]=Configurează serviciile gestionarului de fișiere
-Comment[ru]=Настройка действий в диспетчере файлов
-Comment[sk]=Nastavenie služieb správcu súborov
-Comment[sl]=Nastavitve storitev upravljalnika datotek
-Comment[sr]=Подешавање сервиса менаџера фајлова
-Comment[sr@ijekavian]=Подешавање сервиса менаџера фајлова
-Comment[sr@ijekavianlatin]=Podešavanje servisa menadžera fajlova
-Comment[sr@latin]=Podešavanje servisa menadžera fajlova
-Comment[sv]=Anpassa filhanterarens tjänster
-Comment[tr]=Dosya yöneticisi servislerini yapılandır
-Comment[uk]=Налаштувати служби менеджера файлів
-Comment[vi]=Cấu hình các dịch vụ trình quản lí tệp
-Comment[x-test]=xxConfigure file manager servicesxx
-Comment[zh_CN]=配置文件管理器服务
-Comment[zh_TW]=設定檔案管理員服務
-X-KDE-Keywords=file manager
-X-KDE-Keywords[ar]=مدير ملفّات ملفات الملفّات الملفات
-X-KDE-Keywords[ast]=xestor de ficheros
-X-KDE-Keywords[az]=fayl meneceri
-X-KDE-Keywords[ca]=gestor de fitxers
-X-KDE-Keywords[ca@valencia]=gestor de fitxers
-X-KDE-Keywords[cs]=správce souborů
-X-KDE-Keywords[da]=filhåndtering
-X-KDE-Keywords[de]=Dateiverwaltung
-X-KDE-Keywords[el]=διαχειριστής αρχείων
-X-KDE-Keywords[en_GB]=file manager
-X-KDE-Keywords[es]=gestor de archivos
-X-KDE-Keywords[et]=failihaldur
-X-KDE-Keywords[eu]=Fitxategi-kudeatzailea
-X-KDE-Keywords[fi]=tiedostonhallinta
-X-KDE-Keywords[fr]=gestionnaire de fichiers
-X-KDE-Keywords[gl]=xestor de ficheiros
-X-KDE-Keywords[he]=מנהל קבצים
-X-KDE-Keywords[hu]=fájlkezelő
-X-KDE-Keywords[ia]=gerente de file
-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ų tvarkytuvė
-X-KDE-Keywords[lv]=datņu pārvaldnieks
-X-KDE-Keywords[ml]=ഫയൽ മാനേജർ
-X-KDE-Keywords[nb]=filbehandler
-X-KDE-Keywords[nl]=bestandsbeheerder
-X-KDE-Keywords[nn]=filhandsamar
-X-KDE-Keywords[pa]=ਫਾਇਲ ਮੈਨੇਜਰ
-X-KDE-Keywords[pl]=zarządzanie plikami
-X-KDE-Keywords[pt]=gestor de ficheiros
-X-KDE-Keywords[pt_BR]=gerenciador de arquivos
-X-KDE-Keywords[ro]=gestionar de fișiere
-X-KDE-Keywords[ru]=диспетчер файлов
-X-KDE-Keywords[sk]=správca súborov
-X-KDE-Keywords[sl]=upravljalnik datotek
-X-KDE-Keywords[sr]=file manager,менаџер фајлова
-X-KDE-Keywords[sr@ijekavian]=file manager,менаџер фајлова
-X-KDE-Keywords[sr@ijekavianlatin]=file manager,menadžer fajlova
-X-KDE-Keywords[sr@latin]=file manager,menadžer fajlova
-X-KDE-Keywords[sv]=filhanterare
-X-KDE-Keywords[tr]=dosya yöneticisi
-X-KDE-Keywords[uk]=менеджер,керування,файл,файли
-X-KDE-Keywords[vi]=file manager,trình quản lí tệp
-X-KDE-Keywords[x-test]=xxfile managerxx
-X-KDE-Keywords[zh_CN]=文件管理器
-X-KDE-Keywords[zh_TW]=檔案管理員
diff --git a/src/settings/kcm/kcmdolphinservices.h b/src/settings/kcm/kcmdolphinservices.h
deleted file mode 100644 (file)
index ea94a98..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2009 Peter Penz <peter.penz19@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef KCMDOLPHINSERVICES_H
-#define KCMDOLPHINSERVICES_H
-
-#include <KCModule>
-
-class ServicesSettingsPage;
-
-/**
- * @brief Allow to configure the Dolphin services.
- */
-class DolphinServicesConfigModule : public KCModule
-{
-    Q_OBJECT
-
-public:
-    DolphinServicesConfigModule(QWidget* parent, const QVariantList& args);
-    ~DolphinServicesConfigModule() override;
-
-    void save() override;
-    void defaults() override;
-
-private:
-    ServicesSettingsPage *m_services;
-};
-
-#endif
index 5ab53e9b9dd3d65e0735b972e95e65df2c02af80..fcd33a0f0f05bd71e498d32fec38d2300c3285b1 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <KLocalizedString>
 #include <KPluginFactory>
-#include <KPluginLoader>
 
 #include <QDBusConnection>
 #include <QDBusMessage>
index 41a39a537950bca7cd6a49ea2d4bbc2e1d312df6..11bc25f3b64fdd30332100b4b245dfe73d225ca4 100644 (file)
@@ -6,36 +6,48 @@
 
 #include "navigationsettingspage.h"
 
+#include "global.h"
 #include "dolphin_generalsettings.h"
 
 #include <KLocalizedString>
 
+#include <QButtonGroup>
 #include <QCheckBox>
+#include <QFormLayout>
+#include <QRadioButton>
 #include <QVBoxLayout>
 
 NavigationSettingsPage::NavigationSettingsPage(QWidget* parent) :
     SettingsPageBase(parent),
     m_openArchivesAsFolder(nullptr),
-    m_autoExpandFolders(nullptr)
+    m_autoExpandFolders(nullptr),
+    m_openNewTabAfterLastTab(nullptr),
+    m_openNewTabAfterCurrentTab(nullptr)
 {
-    QVBoxLayout* topLayout = new QVBoxLayout(this);
-    QWidget* vBox = new QWidget(this);
-    QVBoxLayout *vBoxLayout = new QVBoxLayout(vBox);
-    vBoxLayout->setContentsMargins(0, 0, 0, 0);
-    vBoxLayout->setAlignment(Qt::AlignTop);
+    QFormLayout* topLayout = new QFormLayout(this);
 
-    m_openArchivesAsFolder = new QCheckBox(i18nc("@option:check", "Open archives as folder"), vBox);
-    vBoxLayout->addWidget(m_openArchivesAsFolder);
+    // Tabs properties
+    m_openNewTabAfterCurrentTab = new QRadioButton(i18nc("option:radio", "After current tab"));
+    m_openNewTabAfterLastTab = new QRadioButton(i18nc("option:radio", "At end of tab bar"));
+    QButtonGroup* tabsBehaviorGroup = new QButtonGroup(this);
+    tabsBehaviorGroup->addButton(m_openNewTabAfterCurrentTab);
+    tabsBehaviorGroup->addButton(m_openNewTabAfterLastTab);
+    topLayout->addRow(i18nc("@title:group", "Open new tabs: "), m_openNewTabAfterCurrentTab);
+    topLayout->addRow(QString(), m_openNewTabAfterLastTab);
 
-    m_autoExpandFolders = new QCheckBox(i18nc("option:check", "Open folders during drag operations"), vBox);
-    vBoxLayout->addWidget(m_autoExpandFolders);
+    topLayout->addItem(new QSpacerItem(0, Dolphin::VERTICAL_SPACER_HEIGHT, QSizePolicy::Fixed, QSizePolicy::Fixed));
 
-    topLayout->addWidget(vBox);
+    m_openArchivesAsFolder = new QCheckBox(i18nc("@option:check", "Open archives as folder"));
+    m_autoExpandFolders = new QCheckBox(i18nc("option:check", "Open folders during drag operations"));
+    topLayout->addRow(i18nc("@title:group", "General: "), m_openArchivesAsFolder);
+    topLayout->addRow(QString(), m_autoExpandFolders);
 
     loadSettings();
 
     connect(m_openArchivesAsFolder, &QCheckBox::toggled, this, &NavigationSettingsPage::changed);
     connect(m_autoExpandFolders, &QCheckBox::toggled, this, &NavigationSettingsPage::changed);
+    connect(m_openNewTabAfterCurrentTab, &QRadioButton::toggled, this, &NavigationSettingsPage::changed);
+    connect(m_openNewTabAfterLastTab, &QRadioButton::toggled, this, &NavigationSettingsPage::changed);
 }
 
 NavigationSettingsPage::~NavigationSettingsPage()
@@ -47,6 +59,7 @@ void NavigationSettingsPage::applySettings()
     GeneralSettings* settings = GeneralSettings::self();
     settings->setBrowseThroughArchives(m_openArchivesAsFolder->isChecked());
     settings->setAutoExpandFolders(m_autoExpandFolders->isChecked());
+    settings->setOpenNewTabAfterLastTab(m_openNewTabAfterLastTab->isChecked());
 
     settings->save();
 }
@@ -63,5 +76,7 @@ void NavigationSettingsPage::loadSettings()
 {
     m_openArchivesAsFolder->setChecked(GeneralSettings::browseThroughArchives());
     m_autoExpandFolders->setChecked(GeneralSettings::autoExpandFolders());
+    m_openNewTabAfterLastTab->setChecked(GeneralSettings::openNewTabAfterLastTab());
+    m_openNewTabAfterCurrentTab->setChecked(!m_openNewTabAfterLastTab->isChecked());
 }
 
index 8b4781b44793c0a32263ed763ff5d16e1267985c..a0c75e7f5d229db785be2543c9d3542bda1757f4 100644 (file)
@@ -9,6 +9,7 @@
 #include "settings/settingspagebase.h"
 
 class QCheckBox;
+class QRadioButton;
 
 /**
  * @brief Page for the 'Navigation' settings of the Dolphin settings dialog.
@@ -33,6 +34,8 @@ private:
 private:
     QCheckBox* m_openArchivesAsFolder;
     QCheckBox* m_autoExpandFolders;
+    QRadioButton* m_openNewTabAfterLastTab;
+    QRadioButton* m_openNewTabAfterCurrentTab;
 };
 
 #endif
index 6c3f6bdadf9328149d918c43e3ed8a57447f0bdb..a7fcec4fa3320f818a0e7e1711d316b038941719 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <KLocalizedString>
 #include <KMessageBox>
+#include <KProtocolManager>
 
 #include <QButtonGroup>
 #include <QCheckBox>
@@ -138,11 +139,17 @@ void StartupSettingsPage::applySettings()
     GeneralSettings* settings = GeneralSettings::self();
 
     const QUrl url(QUrl::fromUserInput(m_homeUrl->text(), QString(), QUrl::AssumeLocalFile));
-    KFileItem fileItem(url);
-    if ((url.isValid() && fileItem.isDir()) || (url.scheme() == QLatin1String("timeline"))) {
-        settings->setHomeUrl(url.toDisplayString(QUrl::PreferLocalFile));
+    if (url.isValid() && KProtocolManager::supportsListing(url)) {
+        KIO::StatJob* job = KIO::statDetails(url, KIO::StatJob::SourceSide, KIO::StatDetail::StatBasic, KIO::JobFlag::HideProgressInfo);
+        connect(job, &KJob::result, this, [this, settings, url](KJob* job) {
+            if (job->error() == 0 && qobject_cast<KIO::StatJob*>(job)->statResult().isDir()) {
+                settings->setHomeUrl(url.toDisplayString(QUrl::PreferLocalFile));
+            } else {
+                showSetDefaultDirectoryError();
+            }
+        });
     } else {
-        KMessageBox::error(this, i18nc("@info", "The location for the home folder is invalid or does not exist, it will not be applied."));
+        showSetDefaultDirectoryError();
     }
 
     // Remove saved state if "remember open tabs" has been turned off
@@ -222,3 +229,8 @@ void StartupSettingsPage::loadSettings()
     m_showFullPathInTitlebar->setChecked(GeneralSettings::showFullPathInTitlebar());
     m_openExternallyCalledFolderInNewTab->setChecked(GeneralSettings::openExternallyCalledFolderInNewTab());
 }
+
+void StartupSettingsPage::showSetDefaultDirectoryError()
+{
+    KMessageBox::error(this, i18nc("@info", "The location for the home folder is invalid or does not exist, it will not be applied."));
+}
index ff3ffcb12916096d1814ff9d91f17cae3bfdeb02..1090e0822be4ddba2bcefc4cbcebf978faae2dba 100644 (file)
@@ -43,6 +43,7 @@ private slots:
 
 private:
     void loadSettings();
+    void showSetDefaultDirectoryError();
 
 private:
     QUrl m_url;
index cf8cd2810a9974caaa0a919ff3810dc663bd3342..0fd2dca3ac84a83000230a45b11b84705e9707ba 100644 (file)
@@ -14,6 +14,7 @@
 #include "views/zoomlevelinfo.h"
 
 #include <KLocalizedString>
+#include <KFormat>
 
 #include <QApplication>
 #include <QCheckBox>
@@ -34,7 +35,9 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) :
     m_widthBox(nullptr),
     m_maxLinesBox(nullptr),
     m_expandableFolders(nullptr),
-    m_recursiveDirectorySizeLimit(nullptr)
+    m_recursiveDirectorySizeLimit(nullptr),
+    m_useRelatetiveDates(nullptr),
+    m_useShortDates(nullptr)
 {
     QFormLayout* topLayout = new QFormLayout(this);
 
@@ -121,6 +124,25 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) :
         topLayout->addRow(i18nc("@title:group", "Folder size displays:"), m_numberOfItems);
         topLayout->addRow(QString(), contentsSizeLayout);
 #endif
+
+        QDateTime thirtyMinutesAgo = QDateTime::currentDateTime().addSecs(-30 * 60);
+        QLocale local;
+        KFormat formatter(local);
+
+        m_useRelatetiveDates = new QRadioButton(i18nc(
+            "option:radio as in relative date", "Relative (e.g. '%1')", formatter.formatRelativeDateTime(thirtyMinutesAgo, QLocale::ShortFormat))
+        );
+        m_useShortDates = new QRadioButton(
+            i18nc("option:radio as in absolute date", "Absolute (e.g. '%1')", local.toString(thirtyMinutesAgo, QLocale::ShortFormat))
+        );
+
+        QButtonGroup* dateFormatGroup = new QButtonGroup(this);
+        dateFormatGroup->addButton(m_useRelatetiveDates);
+        dateFormatGroup->addButton(m_useShortDates);
+
+        topLayout->addRow(i18nc("@title:group", "Date style:"), m_useRelatetiveDates);
+        topLayout->addRow(QString(), m_useShortDates);
+
         break;
     }
 
@@ -147,6 +169,8 @@ ViewSettingsTab::ViewSettingsTab(Mode mode, QWidget* parent) :
             m_recursiveDirectorySizeLimit->setEnabled(m_sizeOfContents->isChecked());
         });
 #endif
+        connect(m_useRelatetiveDates, &QRadioButton::toggled, this, &ViewSettingsTab::changed);
+        connect(m_useShortDates, &QRadioButton::toggled, this, &ViewSettingsTab::changed);
         break;
     default:
         break;
@@ -176,6 +200,7 @@ void ViewSettingsTab::applySettings()
         DetailsModeSettings::setDirectorySizeCount(m_numberOfItems->isChecked());
         DetailsModeSettings::setRecursiveDirectorySizeLimit(m_recursiveDirectorySizeLimit->value());
 #endif
+        DetailsModeSettings::setUseShortRelativeDates(m_useRelatetiveDates->isChecked());
         break;
     default:
         break;
@@ -234,6 +259,8 @@ void ViewSettingsTab::loadSettings()
             }
             m_recursiveDirectorySizeLimit->setValue(DetailsModeSettings::recursiveDirectorySizeLimit());
         #endif
+        m_useRelatetiveDates->setChecked(DetailsModeSettings::useShortRelativeDates());
+        m_useShortDates->setChecked(!DetailsModeSettings::useShortRelativeDates());
         break;
     default:
         break;
index 41b40b95e0978aae333d1a7cca62f8303c028938..d5756bb3aa917d595e02f21488664c5a56fe6b1a 100644 (file)
@@ -64,6 +64,8 @@ private:
     QRadioButton* m_numberOfItems;
     QRadioButton* m_sizeOfContents;
     QSpinBox* m_recursiveDirectorySizeLimit;
+    QRadioButton* m_useRelatetiveDates;
+    QRadioButton* m_useShortDates;
 };
 
 #endif
index c6dbc82b43f42d673e9eadc44dba4eedb1031521..82d182d1d00c8a9e8cc736c9df3428596d7f65c5 100644 (file)
@@ -64,7 +64,6 @@ ViewPropertiesDialog::ViewPropertiesDialog(DolphinView* dolphinView) :
     auto layout = new QFormLayout(this);
     // Otherwise the dialog won't resize when we collapse the KCollapsibleGroupBox.
     layout->setSizeConstraint(QLayout::SetFixedSize);
-    setLayout(layout);
 
     // create 'Properties' group containing view mode, sorting, sort order and show hidden files
     m_viewMode = new QComboBox();
@@ -89,7 +88,7 @@ ViewPropertiesDialog::ViewPropertiesDialog(DolphinView* dolphinView) :
 
     auto additionalInfoBox = new KCollapsibleGroupBox();
     additionalInfoBox->setTitle(i18nc("@title:group", "Additional Information"));
-    auto innerLayout = new QVBoxLayout();
+    auto innerLayout = new QVBoxLayout(additionalInfoBox);
 
     {
         QList<QByteArray> visibleRoles = m_viewProps->visibleRoles();
@@ -133,8 +132,6 @@ ViewPropertiesDialog::ViewPropertiesDialog(DolphinView* dolphinView) :
         innerLayout->addWidget(m_listWidget);
     }
 
-    additionalInfoBox->setLayout(innerLayout);
-
     QHBoxLayout* sortingLayout = new QHBoxLayout();
     sortingLayout->setContentsMargins(0, 0, 0, 0);
     sortingLayout->addWidget(m_sortOrder);
@@ -212,7 +209,7 @@ ViewPropertiesDialog::ViewPropertiesDialog(DolphinView* dolphinView) :
     layout->addWidget(buttonBox);
 
     auto okButton = buttonBox->button(QDialogButtonBox::Ok);
-    okButton->setShortcut(Qt::CTRL + Qt::Key_Return);
+    okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
     okButton->setDefault(true);
 
     auto applyButton = buttonBox->button(QDialogButtonBox::Apply);
index 57a00c2b1856ccc293da7b13e77ade855afeb4b0..cd4ff379ca7d3af215578f9249ea95a8fdebf309 100644 (file)
@@ -44,7 +44,6 @@ ViewPropsProgressInfo::ViewPropsProgressInfo(QWidget* parent,
     m_viewProps->setAutoSaveEnabled(false);
 
     auto layout = new QVBoxLayout(this);
-    setLayout(layout);
 
     m_label = new QLabel(i18nc("@info:progress", "Counting folders: %1", 0), this);
     layout->addWidget(m_label);
index ecdb8f0fa6548ece0769f7568de9b996dea1f77e..7cba8e346d60fd78a0b9ecbf1f1c5d38d57ddb9e 100644 (file)
@@ -34,6 +34,7 @@ DolphinStatusBar::DolphinStatusBar(QWidget* parent) :
     m_text(),
     m_defaultText(),
     m_label(nullptr),
+    m_zoomLabel(nullptr),
     m_spaceInfo(nullptr),
     m_zoomSlider(nullptr),
     m_progressBar(nullptr),
@@ -48,6 +49,9 @@ DolphinStatusBar::DolphinStatusBar(QWidget* parent) :
     m_label->setWordWrap(true);
     m_label->setTextFormat(Qt::PlainText);
 
+    // Initialize zoom slider's explanatory label
+    m_zoomLabel = new QLabel(i18nc("Used as a noun, i.e. 'Here is the zoom level:'","Zoom:"), this);
+
     // Initialize zoom widget
     m_zoomSlider = new QSlider(Qt::Horizontal, this);
     m_zoomSlider->setAccessibleName(i18n("Zoom"));
@@ -100,19 +104,20 @@ DolphinStatusBar::DolphinStatusBar(QWidget* parent) :
     m_label->setFixedHeight(contentHeight);
     m_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
 
-    m_zoomSlider->setMaximumWidth(fontMetrics.averageCharWidth() * 25);
+    m_zoomSlider->setMaximumWidth(fontMetrics.averageCharWidth() * 15);
 
     m_spaceInfo->setFixedHeight(contentHeight);
     m_spaceInfo->setMaximumWidth(fontMetrics.averageCharWidth() * 25);
     m_spaceInfo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
 
     m_progressBar->setFixedHeight(zoomSliderHeight);
-    m_progressBar->setMaximumWidth(fontMetrics.averageCharWidth() * 25);
+    m_progressBar->setMaximumWidth(fontMetrics.averageCharWidth() * 20);
 
     QHBoxLayout* topLayout = new QHBoxLayout(this);
     topLayout->setContentsMargins(2, 0, 2, 0);
     topLayout->setSpacing(4);
     topLayout->addWidget(m_label, 1);
+    topLayout->addWidget(m_zoomLabel);
     topLayout->addWidget(m_zoomSlider, 1);
     topLayout->addWidget(m_spaceInfo, 1);
     topLayout->addWidget(m_stopButton);
@@ -324,5 +329,6 @@ void DolphinStatusBar::setExtensionsVisible(bool visible)
     m_spaceInfo->setShown(showSpaceInfo);
     m_spaceInfo->setVisible(showSpaceInfo);
     m_zoomSlider->setVisible(showZoomSlider);
+    m_zoomLabel->setVisible(showZoomSlider);
 }
 
index b34f802036508147cde3617fafd85fa16262779f..30968be6e3fa818ed5a6a7fe04c8aaefca4f93da 100644 (file)
@@ -124,6 +124,7 @@ private:
     QString m_text;
     QString m_defaultText;
     KSqueezedTextLabel* m_label;
+    QLabel* m_zoomLabel;
     StatusBarSpaceInfo* m_spaceInfo;
 
     QSlider* m_zoomSlider;
index a6fbf7845c5ef0f487106de64a62444c61eee25a..82db749b5c3ab4d5d9c5bf451f7b2421b230d3f4 100644 (file)
@@ -74,11 +74,9 @@ LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
 ecm_add_test(draganddrophelpertest.cpp LINK_LIBRARIES dolphinprivate Qt5::Test)
 
 # PlacesItemModelTest
-if (KF5_VERSION VERSION_GREATER_EQUAL 5.63.0)
-    ecm_add_test(placesitemmodeltest.cpp
-    TEST_NAME placesitemmodeltest
-    LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
-endif()
+ecm_add_test(placesitemmodeltest.cpp
+TEST_NAME placesitemmodeltest
+LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test)
 
 find_gem(test-unit)
 set_package_properties(Gem:test-unit PROPERTIES
@@ -86,5 +84,5 @@ set_package_properties(Gem:test-unit PROPERTIES
     DESCRIPTION "Ruby gem 'test-unit' required for testing of servicemenu helpers.")
 if (Gem:test-unit_FOUND)
     add_test(NAME servicemenutest
-    COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../settings/services/test/test_run.rb)
+    COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../settings/contextmenu/test/test_run.rb)
 endif()
index 32e9624597211391484f05ba8d4a5902a542ef70..d03b75ddd8784224770a8ee16787728e4b6e990b 100644 (file)
@@ -48,7 +48,9 @@
 #include <QApplication>
 #include <QClipboard>
 #include <QDropEvent>
+#include <QGraphicsOpacityEffect>
 #include <QGraphicsSceneDragDropEvent>
+#include <QLabel>
 #include <QMenu>
 #include <QMimeDatabase>
 #include <QPixmapCache>
@@ -65,6 +67,7 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
     m_assureVisibleCurrentIndex(false),
     m_isFolderWritable(true),
     m_dragging(false),
+    m_loading(false),
     m_url(url),
     m_viewPropertiesContext(),
     m_mode(DolphinView::IconsView),
@@ -82,7 +85,8 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
     m_clearSelectionBeforeSelectingNewItems(false),
     m_markFirstNewlySelectedItemAsCurrent(false),
     m_versionControlObserver(nullptr),
-    m_twoClicksRenamingTimer(nullptr)
+    m_twoClicksRenamingTimer(nullptr),
+    m_placeholderLabel(nullptr)
 {
     m_topLayout = new QVBoxLayout(this);
     m_topLayout->setSpacing(0);
@@ -120,6 +124,28 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
     connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); });
     connect(m_container->verticalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); });
 
+    // Show some placeholder text for empty folders
+    // This is made using a heavily-modified QLabel rather than a KTitleWidget
+    // because KTitleWidget can't be told to turn off mouse-selectable text
+    m_placeholderLabel = new QLabel(this);
+    QFont placeholderLabelFont;
+    // To match the size of a level 2 Heading/KTitleWidget
+    placeholderLabelFont.setPointSize(qRound(placeholderLabelFont.pointSize() * 1.3));
+    m_placeholderLabel->setFont(placeholderLabelFont);
+    m_placeholderLabel->setTextInteractionFlags(Qt::NoTextInteraction);
+    m_placeholderLabel->setWordWrap(true);
+    m_placeholderLabel->setAlignment(Qt::AlignCenter);
+    // Match opacity of QML placeholder label component
+    auto *effect = new QGraphicsOpacityEffect(m_placeholderLabel);
+    effect->setOpacity(0.5);
+    m_placeholderLabel->setGraphicsEffect(effect);
+    // Set initial text and visibility
+    updatePlaceholderLabel();
+
+    auto *centeringLayout = new QVBoxLayout(m_container);
+    centeringLayout->addWidget(m_placeholderLabel);
+    centeringLayout->setAlignment(m_placeholderLabel, Qt::AlignCenter);
+
     controller->setSelectionBehavior(KItemListController::MultiSelection);
     connect(controller, &KItemListController::itemActivated, this, &DolphinView::slotItemActivated);
     connect(controller, &KItemListController::itemsActivated, this, &DolphinView::slotItemsActivated);
@@ -140,7 +166,7 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
 
     connect(m_model, &KFileItemModel::directoryLoadingStarted,       this, &DolphinView::slotDirectoryLoadingStarted);
     connect(m_model, &KFileItemModel::directoryLoadingCompleted,     this, &DolphinView::slotDirectoryLoadingCompleted);
-    connect(m_model, &KFileItemModel::directoryLoadingCanceled,      this, &DolphinView::directoryLoadingCanceled);
+    connect(m_model, &KFileItemModel::directoryLoadingCanceled,      this, &DolphinView::slotDirectoryLoadingCanceled);
     connect(m_model, &KFileItemModel::directoryLoadingProgress,   this, &DolphinView::directoryLoadingProgress);
     connect(m_model, &KFileItemModel::directorySortingProgress,   this, &DolphinView::directorySortingProgress);
     connect(m_model, &KFileItemModel::itemsChanged,
@@ -152,6 +178,9 @@ DolphinView::DolphinView(const QUrl& url, QWidget* parent) :
     connect(m_model, &KFileItemModel::directoryRedirection, this, &DolphinView::slotDirectoryRedirection);
     connect(m_model, &KFileItemModel::urlIsFileError,            this, &DolphinView::urlIsFileError);
 
+    connect(this, &DolphinView::itemCountChanged,
+            this, &DolphinView::updatePlaceholderLabel);
+
     m_view->installEventFilter(this);
     connect(m_view, &DolphinItemListView::sortOrderChanged,
             this, &DolphinView::slotSortOrderChangedByHeader);
@@ -915,7 +944,7 @@ void DolphinView::slotItemsActivated(const KItemSet& indexes)
         const QUrl& url = openItemAsFolderUrl(item);
 
         if (!url.isEmpty()) { // Open folders in new tabs
-            Q_EMIT tabRequested(url, DolphinTabWidget::AfterLastTab);
+            Q_EMIT tabRequested(url);
         } else {
             items.append(item);
         }
@@ -933,9 +962,9 @@ void DolphinView::slotItemMiddleClicked(int index)
     const KFileItem& item = m_model->fileItem(index);
     const QUrl& url = openItemAsFolderUrl(item);
     if (!url.isEmpty()) {
-        Q_EMIT tabRequested(url, DolphinTabWidget::AfterCurrentTab);
+        Q_EMIT tabRequested(url);
     } else if (isTabsForFilesEnabled()) {
-        Q_EMIT tabRequested(item.url(), DolphinTabWidget::AfterCurrentTab);
+        Q_EMIT tabRequested(item.url());
     }
 }
 
@@ -1594,6 +1623,9 @@ void DolphinView::slotRenamingResult(KJob* job)
 
 void DolphinView::slotDirectoryLoadingStarted()
 {
+    m_loading = true;
+    updatePlaceholderLabel();
+
     // Disable the writestate temporary until it can be determined in a fast way
     // in DolphinView::slotDirectoryLoadingCompleted()
     if (m_isFolderWritable) {
@@ -1606,15 +1638,30 @@ void DolphinView::slotDirectoryLoadingStarted()
 
 void DolphinView::slotDirectoryLoadingCompleted()
 {
+    m_loading = false;
+
     // Update the view-state. This has to be done asynchronously
     // because the view might not be in its final state yet.
     QTimer::singleShot(0, this, &DolphinView::updateViewState);
 
+    // Update the placeholder label in case we found that the folder was empty
+    // after loading it
+
     Q_EMIT directoryLoadingCompleted();
 
+    updatePlaceholderLabel();
     updateWritableState();
 }
 
+void DolphinView::slotDirectoryLoadingCanceled()
+{
+    m_loading = false;
+
+    updatePlaceholderLabel();
+
+    Q_EMIT directoryLoadingCanceled();
+}
+
 void DolphinView::slotItemsChanged()
 {
     m_assureVisibleCurrentIndex = false;
@@ -1976,3 +2023,35 @@ void DolphinView::slotSwipeUp()
 {
     Q_EMIT goUpRequested();
 }
+
+void DolphinView::updatePlaceholderLabel()
+{
+    if (m_loading || itemsCount() > 0) {
+        m_placeholderLabel->setVisible(false);
+        return;
+    }
+
+    if (!nameFilter().isEmpty()) {
+        m_placeholderLabel->setText(i18n("No items matching the filter"));
+    } else if (m_url.scheme() == QLatin1String("baloosearch") || m_url.scheme() == QLatin1String("filenamesearch")) {
+        m_placeholderLabel->setText(i18n("No items matching the search"));
+    } else if (m_url.scheme() == QLatin1String("trash")) {
+        m_placeholderLabel->setText(i18n("Trash is empty"));
+    } else if (m_url.scheme() == QLatin1String("tags")) {
+        m_placeholderLabel->setText(i18n("No tags"));
+    } else if (m_url.scheme() == QLatin1String("recentlyused")) {
+        m_placeholderLabel->setText(i18n("No recently used items"));
+    } else if (m_url.scheme() == QLatin1String("smb")) {
+        m_placeholderLabel->setText(i18n("No shared folders found"));
+    } else if (m_url.scheme() == QLatin1String("network")) {
+        m_placeholderLabel->setText(i18n("No relevant network resources found"));
+    } else if (m_url.scheme() == QLatin1String("mtp")) {
+        m_placeholderLabel->setText(i18n("No MTP-compatible devices found"));
+    } else if (m_url.scheme() == QLatin1String("bluetooth")) {
+        m_placeholderLabel->setText(i18n("No Bluetooth devices found"));
+    } else {
+        m_placeholderLabel->setText(i18n("Folder is empty"));
+    }
+
+    m_placeholderLabel->setVisible(true);
+}
index 1d0ebe0feb15e56747d90c86579bfee09ccc2868..d0285da85255a37cbf6c3be2591da599f7bd0c00 100644 (file)
@@ -32,6 +32,7 @@ class KItemSet;
 class ToolTipManager;
 class VersionControlObserver;
 class ViewProperties;
+class QLabel;
 class QGraphicsSceneDragDropEvent;
 class QRegularExpression;
 
@@ -432,7 +433,7 @@ signals:
     /**
      * Is emitted if a new tab should be opened for the URL \a url.
      */
-    void tabRequested(const QUrl& url, DolphinTabWidget::TabPlacement tabPlacement);
+    void tabRequested(const QUrl& url);
 
     /**
      * Is emitted if the view mode (IconsView, DetailsView,
@@ -688,6 +689,12 @@ private slots:
      */
     void slotDirectoryLoadingCompleted();
 
+    /**
+     * Invoked when the file item model indicates that the loading of a directory has
+     * been canceled.
+     */
+    void slotDirectoryLoadingCanceled();
+
     /**
      * Is invoked when items of KFileItemModel have been changed.
      */
@@ -804,6 +811,8 @@ private:
 
     void abortTwoClicksRenaming();
 
+    void updatePlaceholderLabel();
+
 private:
     void updatePalette();
 
@@ -813,6 +822,7 @@ private:
     bool m_isFolderWritable;
     bool m_dragging; // True if a dragging is done. Required to be able to decide whether a
                      // tooltip may be shown when hovering an item.
+    bool m_loading;
 
     QUrl m_url;
     QString m_viewPropertiesContext;
@@ -841,6 +851,7 @@ private:
 
     QTimer* m_twoClicksRenamingTimer;
     QUrl m_twoClicksRenamingItemUrl;
+    QLabel* m_placeholderLabel;
 
     // For unit tests
     friend class TestBase;
index f3e3f95a30cbf3751f99537555eca0e72d967dc1..14c1e96c22199988a89cec1ef61b1c3c33c9b607 100644 (file)
@@ -11,6 +11,7 @@
 #include "kitemviews/kfileitemmodel.h"
 #include "settings/viewpropertiesdialog.h"
 #include "views/zoomlevelinfo.h"
+#include "kconfig_version.h"
 
 #ifdef HAVE_BALOO
 #include <Baloo/IndexerConfig>
@@ -78,7 +79,7 @@ void DolphinViewActionHandler::createActions()
     // KNewFileMenu takes care of the GUI stuff.
     QAction* newDirAction = m_actionCollection->addAction(QStringLiteral("create_dir"));
     newDirAction->setText(i18nc("@action", "Create Folder..."));
-    m_actionCollection->setDefaultShortcut(newDirAction, Qt::Key_F10);
+    m_actionCollection->setDefaultShortcuts(newDirAction, KStandardShortcut::createFolder());
     newDirAction->setIcon(QIcon::fromTheme(QStringLiteral("folder-new")));
     newDirAction->setEnabled(false);    // Will be enabled in slotWriteStateChanged(bool) if the current URL is writable
     connect(newDirAction, &QAction::triggered, this, &DolphinViewActionHandler::createDirectoryTriggered);
@@ -139,7 +140,7 @@ void DolphinViewActionHandler::createActions()
         "You can configure advanced options there like managing "
         "read- and write-permissions."));
     propertiesAction->setIcon(QIcon::fromTheme(QStringLiteral("document-properties")));
-    m_actionCollection->setDefaultShortcuts(propertiesAction, {Qt::ALT + Qt::Key_Return, Qt::ALT + Qt::Key_Enter});
+    m_actionCollection->setDefaultShortcuts(propertiesAction, {Qt::ALT | Qt::Key_Return, Qt::ALT | Qt::Key_Enter});
     connect(propertiesAction, &QAction::triggered, this, &DolphinViewActionHandler::slotProperties);
 
     QAction *copyPathAction = m_actionCollection->addAction( QStringLiteral("copy_location") );
@@ -197,7 +198,7 @@ void DolphinViewActionHandler::createActions()
     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});
+    m_actionCollection->setDefaultShortcuts(zoomResetAction, {Qt::CTRL | Qt::Key_0});
     connect(zoomResetAction, &QAction::triggered, this, &DolphinViewActionHandler::zoomReset);
 
     QAction* zoomOutAction = KStandardAction::zoomOut(this,
@@ -567,7 +568,7 @@ KToggleAction* DolphinViewActionHandler::iconsModeAction()
     KToggleAction* iconsView = m_actionCollection->add<KToggleAction>(QStringLiteral("icons"));
     iconsView->setText(i18nc("@action:inmenu View Mode", "Icons"));
     iconsView->setToolTip(i18nc("@info", "Icons view mode"));
-    m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL + Qt::Key_1);
+    m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL | Qt::Key_1);
     iconsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-icons")));
     iconsView->setData(QVariant::fromValue(DolphinView::IconsView));
     return iconsView;
@@ -578,7 +579,7 @@ KToggleAction* DolphinViewActionHandler::compactModeAction()
     KToggleAction* iconsView = m_actionCollection->add<KToggleAction>(QStringLiteral("compact"));
     iconsView->setText(i18nc("@action:inmenu View Mode", "Compact"));
     iconsView->setToolTip(i18nc("@info", "Compact view mode"));
-    m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL + Qt::Key_2);
+    m_actionCollection->setDefaultShortcut(iconsView, Qt::CTRL | Qt::Key_2);
     iconsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-details"))); // TODO: discuss with Oxygen-team the wrong (?) name
     iconsView->setData(QVariant::fromValue(DolphinView::CompactView));
     return iconsView;
@@ -589,7 +590,7 @@ KToggleAction* DolphinViewActionHandler::detailsModeAction()
     KToggleAction* detailsView = m_actionCollection->add<KToggleAction>(QStringLiteral("details"));
     detailsView->setText(i18nc("@action:inmenu View Mode", "Details"));
     detailsView->setToolTip(i18nc("@info", "Details view mode"));
-    m_actionCollection->setDefaultShortcut(detailsView, Qt::CTRL + Qt::Key_3);
+    m_actionCollection->setDefaultShortcut(detailsView, Qt::CTRL | Qt::Key_3);
     detailsView->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree")));
     detailsView->setData(QVariant::fromValue(DolphinView::DetailsView));
     return detailsView;
index 2e1a4468b839b516b1fa2058fcdc295818601e3d..9cbf0eb5b63774c208a234e5e1cf897a938c9952 100644 (file)
@@ -15,3 +15,8 @@ KVersionControlPlugin::KVersionControlPlugin(QObject* parent) :
 KVersionControlPlugin::~KVersionControlPlugin()
 {
 }
+
+QString KVersionControlPlugin::localRepositoryRoot(const QString &/*directory*/) const
+{
+    return QString();
+}
index 0de305d14fc162033e4cfc29c8c44c4f830adb63..aeac5ad2905d84447dbbbdbff0bfd8e0b3d12f60 100644 (file)
@@ -143,6 +143,12 @@ public:
      */
     virtual QString fileName() const = 0;
 
+    /**
+     * Returns the path of the local repository root for the versionned directory
+     * Returns an emtpy QString when directory is not part of a working copy
+     */
+    virtual QString localRepositoryRoot(const QString& directory) const;
+
     /**
      * Is invoked whenever the version control
      * information will get retrieved for the directory
@@ -177,6 +183,7 @@ public:
      * @return List of actions that are available for the out of version control
      *         items \p items. It's opposed to the \p versionedActions. Common usage
      *         is for clone/checkout actions.
+     * @since 21.04
      */
     virtual QList<QAction*> outOfVersionControlActions(const KFileItemList& items) const = 0;
 
index c66c639c87fbdd86b92aec1edf01966d546c6fbb..cf5be3c9163355429d04a9870037e4ed2c8c7432 100644 (file)
@@ -21,7 +21,6 @@
 VersionControlObserver::VersionControlObserver(QObject* parent) :
     QObject(parent),
     m_pendingItemStatesUpdate(false),
-    m_versionedDirectory(false),
     m_silentUpdate(false),
     m_view(nullptr),
     m_model(nullptr),
@@ -113,8 +112,8 @@ QList<QAction*> VersionControlObserver::actions(const KFileItemList& items) cons
         return m_plugin->versionControlActions(items);
     } else {
         QList<QAction*> actions;
-        for (const auto &plugin : qAsConst(m_plugins)) {
-            actions << plugin.first->outOfVersionControlActions(items);
+        for (const QPointer<KVersionControlPlugin> &plugin : qAsConst(m_plugins)) {
+            actions << plugin->outOfVersionControlActions(items);
         }
         return actions;
     }
@@ -155,23 +154,23 @@ void VersionControlObserver::verifyDirectory()
         return;
     }
 
-    m_plugin = searchPlugin(rootItem.url());
-    if (m_plugin) {
-        if (!m_versionedDirectory) {
-            m_versionedDirectory = true;
+    if (m_plugin != nullptr) {
+        if (!rootItem.url().path().startsWith(m_localRepoRoot) || !QFile::exists(m_localRepoRoot + '/' + m_plugin->fileName())) {
+            m_plugin = nullptr;
 
-            // The directory is versioned. Assume that the user will further browse through
-            // versioned directories and decrease the verification timer.
-            m_dirVerificationTimer->setInterval(100);
+            // The directory is not versioned. Reset the verification timer to a higher
+            // value, so that browsing through non-versioned directories is not slown down
+            // by an immediate verification.
+            m_dirVerificationTimer->setInterval(500);
+        } else {
+            // View was versionned but should not be anymore
+            updateItemStates();
         }
+    } else if ((m_plugin = searchPlugin(rootItem.url()))) {
+        // The directory is versioned. Assume that the user will further browse through
+        // versioned directories and decrease the verification timer.
+        m_dirVerificationTimer->setInterval(100);
         updateItemStates();
-    } else if (m_versionedDirectory) {
-        m_versionedDirectory = false;
-
-        // The directory is not versioned. Reset the verification timer to a higher
-        // value, so that browsing through non-versioned directories is not slown down
-        // by an immediate verification.
-        m_dirVerificationTimer->setInterval(500);
     }
 }
 
@@ -273,7 +272,7 @@ int VersionControlObserver::createItemStatesList(QMap<QString, QVector<ItemState
     return index - firstIndex; // number of processed items
 }
 
-KVersionControlPlugin* VersionControlObserver::searchPlugin(const QUrl& directory)
+void VersionControlObserver::initPlugins()
 {
     if (!m_pluginsInitialized) {
         // No searching for plugins has been done yet. Query the KServiceTypeTrader for
@@ -294,65 +293,41 @@ KVersionControlPlugin* VersionControlObserver::searchPlugin(const QUrl& director
                     connect(plugin, &KVersionControlPlugin::operationCompletedMessage,
                             this, &VersionControlObserver::operationCompletedMessage);
 
-                    m_plugins.append( qMakePair(plugin, plugin->fileName()) );
+                    m_plugins.append(plugin);
                 }
             }
         }
         m_pluginsInitialized = true;
     }
+}
 
-    if (m_plugins.empty()) {
-        // A searching for plugins has already been done, but no
-        // plugins are installed
-        return nullptr;
-    }
+KVersionControlPlugin* VersionControlObserver::searchPlugin(const QUrl& directory)
+{
+    initPlugins();
 
-    // We use the number of upUrl() calls to find the best matching plugin
-    // for the given directory. The smaller value, the better it is (0 is best).
-    KVersionControlPlugin* bestPlugin = nullptr;
-    int bestScore = INT_MAX;
+    // Verify whether the current directory is under a version system
+    for (const QPointer<KVersionControlPlugin> &plugin : qAsConst(m_plugins)) {
+        if (!plugin) {
+            continue;
+        }
 
-    // Verify whether the current directory contains revision information
-    // like .svn, .git, ...
-    for (const auto &it : qAsConst(m_plugins)) {
-        const QString fileName = directory.path() + '/' + it.second;
+        // first naively check if we are at working copy root
+        const QString fileName = directory.path() + '/' + plugin->fileName();
         if (QFile::exists(fileName)) {
-            // The score of this plugin is 0 (best), so we can just return this plugin,
-            // instead of going through the plugin scoring procedure, we can't find a better one ;)
-            return it.first;
+            m_localRepoRoot = directory.path();
+            return plugin;
         }
-
-        // Version control systems like Git provide the version information
-        // file only in the root directory. Check whether the version information file can
-        // be found in one of the parent directories. For performance reasons this
-        // step is only done, if the previous directory was marked as versioned by
-        // m_versionedDirectory. Drawback: Until e. g. Git is recognized, the root directory
-        // must be shown at least once.
-        if (m_versionedDirectory) {
-            QUrl dirUrl(directory);
-            QUrl upUrl = KIO::upUrl(dirUrl);
-            int upUrlCounter = 1;
-            while ((upUrlCounter < bestScore) && (upUrl != dirUrl)) {
-                const QString fileName = dirUrl.path() + '/' + it.second;
-                if (QFile::exists(fileName)) {
-                    if (upUrlCounter < bestScore) {
-                        bestPlugin = it.first;
-                        bestScore = upUrlCounter;
-                    }
-                    break;
-                }
-                dirUrl = upUrl;
-                upUrl = KIO::upUrl(dirUrl);
-                ++upUrlCounter;
-            }
+        const QString root = plugin->localRepositoryRoot(directory.path());
+        if (!root.isEmpty()) {
+            m_localRepoRoot = root;
+            return plugin;
         }
     }
-
-    return bestPlugin;
+    return nullptr;
 }
 
 bool VersionControlObserver::isVersionControlled() const
 {
-    return m_versionedDirectory && m_plugin;
+    return m_plugin != nullptr;
 }
 
index 89c04714866a3a743c98f724717f921193e1dea9..5f425fe8523628320201f63ed7b2269229352beb 100644 (file)
@@ -101,7 +101,6 @@ private slots:
 
 private:
     typedef QPair<KFileItem, KVersionControlPlugin::ItemVersion> ItemState;
-    typedef QPair<KVersionControlPlugin*, QString> VCSPlugin;
 
     void updateItemStates();
 
@@ -133,10 +132,12 @@ private:
     bool isVersionControlled() const;
 
 private:
+    void initPlugins();
+
     bool m_pendingItemStatesUpdate;
-    bool m_versionedDirectory;
     bool m_silentUpdate; // if true, no messages will be send during the update
                          // of version states
+    QString m_localRepoRoot;
 
     DolphinView* m_view;
     KFileItemModel* m_model;
@@ -145,7 +146,7 @@ private:
 
     bool m_pluginsInitialized;
     KVersionControlPlugin* m_plugin;
-    QList<VCSPlugin> m_plugins;
+    QList<QPointer<KVersionControlPlugin>> m_plugins;
     UpdateItemStatesThread* m_updateItemStatesThread;
 
     friend class UpdateItemStatesThread;