Git commit 24b8f2f93e63207d47a4a22bf93961672d065ad2 by Ahmad Samir. Committed on 16/12/2020 at 21:25. Pushed by ahmadsamir into branch 'release/20.12'.
Set empty value for packagekit transaction flags Otherwise the value would be Trusted Only, which will forbid installing local packages A +3 -0 .gitlab-ci.yml M +16 -8 CMakeLists.txt M +38 -38 doc/index.docbook D +0 -3 org.kde.dolphin.FileManager1.service.in A +8 -0 plasma-dolphin.service.in M +4 -2 src/CMakeLists.txt M +47 -41 src/dolphincontextmenu.cpp M +7 -7 src/dolphincontextmenu.h M +55 -34 src/dolphinmainwindow.cpp M +1 -0 src/dolphinmainwindow.h M +1 -1 src/dolphinnavigatorswidgetaction.cpp M +9 -12 src/dolphinpart.cpp R +7 -2 src/dolphinpart.desktop.in [from: src/dolphinpart.desktop - 096% similarity] M +2 -4 src/dolphinpart.h M +4 -3 src/dolphinpart.rc M +7 -4 src/dolphinui.rc M +0 -1 src/dolphinviewcontainer.cpp M +54 -0 src/kitemviews/kitemlistview.cpp M +3 -0 src/kitemviews/kitemlistview.h M +1 -0 src/org.kde.dolphin.appdata.xml M +5 -6 src/search/dolphinsearchbox.cpp M +1 -2 src/settings/general/configurepreviewplugindialog.cpp M +0 -1 src/settings/kcm/kcmdolphingeneral.cpp M +0 -1 src/settings/kcm/kcmdolphinnavigation.cpp M +0 -1 src/settings/kcm/kcmdolphinservices.cpp M +0 -1 src/settings/kcm/kcmdolphinviewmodes.cpp M +2 -5 src/settings/viewpropertiesdialog.cpp M +0 -1 src/settings/viewpropsprogressinfo.cpp M +3 -5 src/tests/CMakeLists.txt M +70 -1 src/views/dolphinview.cpp M +4 -0 src/views/dolphinview.h M +8 -7 src/views/dolphinviewactionhandler.cpp https://invent.kde.org/system/dolphin/commit/24b8f2f93e63207d47a4a22bf93961672d065ad2 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..5dd9a93dc --- /dev/null +++ b/.gitlab-ci.yml @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index c86a14cb1..dc682e2fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 "0") +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,10 +168,16 @@ 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}) +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}) + install(FILES dolphin.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/doc/index.docbook b/doc/index.docbook index 50fc37d91..399729a09 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -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> @@ -775,6 +775,26 @@ current folder, &RMB; click in the work space and click </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"> <title>Finding Files and Searching in Files</title> <!-- FIXME search in hidden files + folders View -> Show Hidden Files has to be enabled ? --> @@ -912,26 +932,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> @@ -1327,8 +1327,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> @@ -1752,6 +1752,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 +2065,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/org.kde.dolphin.FileManager1.service.in b/org.kde.dolphin.FileManager1.service.in deleted file mode 100644 index c1258bb6b..000000000 --- a/org.kde.dolphin.FileManager1.service.in +++ /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 index 000000000..d4cdd694b --- /dev/null +++ b/plasma-dolphin.service.in @@ -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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1955ce558..87bc2d3c2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -176,6 +176,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 +187,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}) ########################################## diff --git a/src/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp index 283f52565..eabd81e22 100644 --- a/src/dolphincontextmenu.cpp +++ b/src/dolphincontextmenu.cpp @@ -61,6 +61,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() @@ -103,27 +105,34 @@ DolphinContextMenu::Command DolphinContextMenu::open() } else if (m_context & ItemContext) { openItemContextMenu(); } else { - Q_ASSERT(m_context == NoContext); openViewportContextMenu(); } 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() @@ -198,6 +207,7 @@ void DolphinContextMenu::addDirectoryItemContextMenu(KFileItemActions &fileItemA QMenu* menu = newFileMenu->menu(); menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New")); menu->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); + menu->setParent(this, Qt::Popup); addMenu(menu); addSeparator(); @@ -213,7 +223,7 @@ void DolphinContextMenu::openItemContextMenu() const KFileItemListProperties& selectedItemsProps = selectedItemsProperties(); KFileItemActions fileItemActions; - fileItemActions.setParentWidget(m_mainWindow); + fileItemActions.setParentWidget(this); fileItemActions.setItemListProperties(selectedItemsProps); if (m_selectedItems.count() == 1) { @@ -271,21 +281,7 @@ 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()) { @@ -347,14 +343,7 @@ void DolphinContextMenu::openViewportContextMenu() 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(); - + addAdditionalActions(fileItemActions, baseUrlProperties); addCustomActions(); addSeparator(); @@ -383,11 +372,20 @@ void DolphinContextMenu::insertDefaultItemActions(const KFileItemListProperties& } addAction(m_mainWindow->actionCollection()->action(QStringLiteral("duplicate"))); - addSeparator(); - // Insert 'Rename' addAction(collection->action(KStandardAction::name(KStandardAction::RenameFile))); + // 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(); + // Insert 'Move to Trash' and/or 'Delete' const bool showDeleteAction = (KSharedConfig::openConfig()->group("KDE").readEntry("ShowDeleteCommand", false) || !properties.isLocal()); @@ -485,8 +483,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()) { @@ -495,8 +506,3 @@ void DolphinContextMenu::addVersionControlPluginActions() } } -void DolphinContextMenu::addCustomActions() -{ - addActions(m_customActions); -} - diff --git a/src/dolphincontextmenu.h b/src/dolphincontextmenu.h index b93df2b61..7f0b6988a 100644 --- a/src/dolphincontextmenu.h +++ b/src/dolphincontextmenu.h @@ -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; diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index b72f2eb90..96ca3d448 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -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); @@ -383,8 +382,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() @@ -847,6 +846,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(); @@ -1083,7 +1091,7 @@ void DolphinMainWindow::handleUrl(const QUrl& url) } else { m_lastHandleUrlOpenJob = new KIO::OpenUrlJob(url); m_lastHandleUrlOpenJob->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); - m_lastHandleUrlOpenJob->setRunExecutables(true); + m_lastHandleUrlOpenJob->setShowOpenOrExecuteDialog(true); connect(m_lastHandleUrlOpenJob, &KIO::OpenUrlJob::mimeTypeFound, this, [this, url](const QString &mimetype) { @@ -1371,7 +1379,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")); @@ -1430,7 +1438,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")); @@ -1439,9 +1447,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")); @@ -1472,7 +1503,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 @@ -1487,7 +1518,7 @@ 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"))); @@ -1522,7 +1553,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 @@ -1556,7 +1587,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); @@ -1597,16 +1628,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"))); @@ -1619,7 +1640,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"))) { @@ -1628,15 +1649,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 } @@ -1668,10 +1689,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)); @@ -1689,7 +1710,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")); @@ -2032,8 +2053,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(); } diff --git a/src/dolphinmainwindow.h b/src/dolphinmainwindow.h index 8d5eae344..8e031fd03 100644 --- a/src/dolphinmainwindow.h +++ b/src/dolphinmainwindow.h @@ -312,6 +312,7 @@ private slots: void disableStopAction(); void showFilterBar(); + void toggleFilterBar(); /** * Toggles between edit and browse mode of the navigation bar. diff --git a/src/dolphinnavigatorswidgetaction.cpp b/src/dolphinnavigatorswidgetaction.cpp index b8c77c69b..cabeac4ed 100644 --- a/src/dolphinnavigatorswidgetaction.cpp +++ b/src/dolphinnavigatorswidgetaction.cpp @@ -266,5 +266,5 @@ 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)); } diff --git a/src/dolphinpart.cpp b/src/dolphinpart.cpp index 75784b522..00c99efd0 100644 --- a/src/dolphinpart.cpp +++ b/src/dolphinpart.cpp @@ -17,7 +17,7 @@ #include "views/dolphinview.h" #include "views/dolphinviewactionhandler.h" -#include <KAboutData> +#include <KPluginMetaData> #include <KActionCollection> #include <KAuthorized> #include <KConfigGroup> @@ -45,15 +45,17 @@ #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,11 +283,6 @@ void DolphinPart::updatePasteAction() Q_EMIT m_extension->setActionText( "paste", pasteInfo.second ); } -KAboutData* DolphinPart::createAboutData() -{ - return new KAboutData(QStringLiteral("dolphinpart"), i18nc("@title", "Dolphin Part"), QStringLiteral("0.1")); -} - bool DolphinPart::openUrl(const QUrl &url) { bool reload = arguments().reload(); diff --git a/src/dolphinpart.desktop b/src/dolphinpart.desktop.in similarity index 96% rename from src/dolphinpart.desktop rename to src/dolphinpart.desktop.in index 0e7efd8e3..71690ead9 100644 --- a/src/dolphinpart.desktop +++ b/src/dolphinpart.desktop.in @@ -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; diff --git a/src/dolphinpart.h b/src/dolphinpart.h index 3d613c276..16c49f96e 100644 --- a/src/dolphinpart.h +++ b/src/dolphinpart.h @@ -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. diff --git a/src/dolphinpart.rc b/src/dolphinpart.rc index df152fb20..a65cf685e 100644 --- a/src/dolphinpart.rc +++ b/src/dolphinpart.rc @@ -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>&Edit</text> <Action name="new_menu"/> @@ -64,4 +65,4 @@ <Action name="deletefile" /> </disable> </State> -</kpartgui> +</gui> diff --git a/src/dolphinui.rc b/src/dolphinui.rc index 6c51497b1..e749abae0 100644 --- a/src/dolphinui.rc +++ b/src/dolphinui.rc @@ -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"/> @@ -123,6 +124,7 @@ <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"/> @@ -140,5 +142,6 @@ <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> diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 8dd309314..7053c4a6b 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -638,7 +638,6 @@ void DolphinViewContainer::slotItemActivated(const KFileItem& item) } KIO::OpenUrlJob *job = new KIO::OpenUrlJob(item.targetUrl()); - job->setRunExecutables(true); job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this)); job->setShowOpenOrExecuteDialog(true); job->start(); diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index f6e5e666b..96c337de3 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -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; diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index df582aad0..e6bf5ad90 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -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; diff --git a/src/org.kde.dolphin.appdata.xml b/src/org.kde.dolphin.appdata.xml index 42e4104ae..a97eeeb46 100644 --- a/src/org.kde.dolphin.appdata.xml +++ b/src/org.kde.dolphin.appdata.xml @@ -615,6 +615,7 @@ <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> diff --git a/src/search/dolphinsearchbox.cpp b/src/search/dolphinsearchbox.cpp index 16f12b989..9143ddcb7 100644 --- a/src/search/dolphinsearchbox.cpp +++ b/src/search/dolphinsearchbox.cpp @@ -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); diff --git a/src/settings/general/configurepreviewplugindialog.cpp b/src/settings/general/configurepreviewplugindialog.cpp index d29b63b7d..26b7deb88 100644 --- a/src/settings/general/configurepreviewplugindialog.cpp +++ b/src/settings/general/configurepreviewplugindialog.cpp @@ -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); } diff --git a/src/settings/kcm/kcmdolphingeneral.cpp b/src/settings/kcm/kcmdolphingeneral.cpp index f2fb604b2..3a0aa779b 100644 --- a/src/settings/kcm/kcmdolphingeneral.cpp +++ b/src/settings/kcm/kcmdolphingeneral.cpp @@ -12,7 +12,6 @@ #include <KLocalizedString> #include <KPluginFactory> -#include <KPluginLoader> #include <kconfigwidgets_version.h> #include <QTabWidget> diff --git a/src/settings/kcm/kcmdolphinnavigation.cpp b/src/settings/kcm/kcmdolphinnavigation.cpp index 725fc83f0..74fce85c7 100644 --- a/src/settings/kcm/kcmdolphinnavigation.cpp +++ b/src/settings/kcm/kcmdolphinnavigation.cpp @@ -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 index 2a411f96a..583440d3e 100644 --- a/src/settings/kcm/kcmdolphinservices.cpp +++ b/src/settings/kcm/kcmdolphinservices.cpp @@ -10,7 +10,6 @@ #include <kconfigwidgets_version.h> #include <KPluginFactory> -#include <KPluginLoader> #include <QVBoxLayout> diff --git a/src/settings/kcm/kcmdolphinviewmodes.cpp b/src/settings/kcm/kcmdolphinviewmodes.cpp index 5ab53e9b9..fcd33a0f0 100644 --- a/src/settings/kcm/kcmdolphinviewmodes.cpp +++ b/src/settings/kcm/kcmdolphinviewmodes.cpp @@ -10,7 +10,6 @@ #include <KLocalizedString> #include <KPluginFactory> -#include <KPluginLoader> #include <QDBusConnection> #include <QDBusMessage> diff --git a/src/settings/viewpropertiesdialog.cpp b/src/settings/viewpropertiesdialog.cpp index c6dbc82b4..82d182d1d 100644 --- a/src/settings/viewpropertiesdialog.cpp +++ b/src/settings/viewpropertiesdialog.cpp @@ -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); diff --git a/src/settings/viewpropsprogressinfo.cpp b/src/settings/viewpropsprogressinfo.cpp index 57a00c2b1..cd4ff379c 100644 --- a/src/settings/viewpropsprogressinfo.cpp +++ b/src/settings/viewpropsprogressinfo.cpp @@ -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); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index a6fbf7845..ee0a1f3fd 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -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 diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 32e962459..71c16bf46 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -48,7 +48,9 @@ #include <QApplication> #include <QClipboard> #include <QDropEvent> +#include <QGraphicsOpacityEffect> #include <QGraphicsSceneDragDropEvent> +#include <QLabel> #include <QMenu> #include <QMimeDatabase> #include <QPixmapCache> @@ -82,7 +84,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 +123,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); @@ -152,6 +177,11 @@ 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); + connect(this, &DolphinView::urlChanged, + this, &DolphinView::updatePlaceholderLabel); + m_view->installEventFilter(this); connect(m_view, &DolphinItemListView::sortOrderChanged, this, &DolphinView::slotSortOrderChangedByHeader); @@ -1594,6 +1624,9 @@ void DolphinView::slotRenamingResult(KJob* job) void DolphinView::slotDirectoryLoadingStarted() { + // We don't want the placeholder label to flicker while the folder is loading + m_placeholderLabel->setVisible(false); + // Disable the writestate temporary until it can be determined in a fast way // in DolphinView::slotDirectoryLoadingCompleted() if (m_isFolderWritable) { @@ -1610,8 +1643,12 @@ void DolphinView::slotDirectoryLoadingCompleted() // 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(); } @@ -1976,3 +2013,35 @@ void DolphinView::slotSwipeUp() { Q_EMIT goUpRequested(); } + +void DolphinView::updatePlaceholderLabel() +{ + if (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); +} diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 1d0ebe0fe..cc3409732 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -32,6 +32,7 @@ class KItemSet; class ToolTipManager; class VersionControlObserver; class ViewProperties; +class QLabel; class QGraphicsSceneDragDropEvent; class QRegularExpression; @@ -804,6 +805,8 @@ private: void abortTwoClicksRenaming(); + void updatePlaceholderLabel(); + private: void updatePalette(); @@ -841,6 +844,7 @@ private: QTimer* m_twoClicksRenamingTimer; QUrl m_twoClicksRenamingItemUrl; + QLabel* m_placeholderLabel; // For unit tests friend class TestBase; diff --git a/src/views/dolphinviewactionhandler.cpp b/src/views/dolphinviewactionhandler.cpp index a2cb89a58..99148efe9 100644 --- a/src/views/dolphinviewactionhandler.cpp +++ b/src/views/dolphinviewactionhandler.cpp @@ -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") ); @@ -149,7 +150,7 @@ void DolphinViewActionHandler::createActions() )); copyPathAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); - m_actionCollection->setDefaultShortcuts(copyPathAction, {Qt::CTRL + Qt::SHIFT + Qt::Key_C}); + m_actionCollection->setDefaultShortcuts(copyPathAction, {Qt::CTRL | Qt::SHIFT | Qt::Key_C}); connect(copyPathAction, &QAction::triggered, this, &DolphinViewActionHandler::slotCopyPath); @@ -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;
