diff options
| -rw-r--r-- | .gitlab-ci.yml | 3 | ||||
| -rw-r--r-- | CMakeLists.txt | 24 | ||||
| -rw-r--r-- | org.kde.dolphin.FileManager1.service.in | 3 | ||||
| -rw-r--r-- | plasma-dolphin.service.in | 8 | ||||
| -rw-r--r-- | src/dolphincontextmenu.cpp | 85 | ||||
| -rw-r--r-- | src/dolphincontextmenu.h | 14 | ||||
| -rw-r--r-- | src/dolphinmainwindow.cpp | 2 | ||||
| -rw-r--r-- | src/dolphinnavigatorswidgetaction.cpp | 2 | ||||
| -rw-r--r-- | src/dolphinpart.rc | 7 | ||||
| -rw-r--r-- | src/dolphinui.rc | 7 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistview.cpp | 54 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistview.h | 3 | ||||
| -rw-r--r-- | src/settings/kcm/kcmdolphingeneral.cpp | 1 | ||||
| -rw-r--r-- | src/settings/kcm/kcmdolphinnavigation.cpp | 1 | ||||
| -rw-r--r-- | src/settings/kcm/kcmdolphinservices.cpp | 1 | ||||
| -rw-r--r-- | src/settings/kcm/kcmdolphinviewmodes.cpp | 1 | ||||
| -rw-r--r-- | src/views/dolphinview.cpp | 72 | ||||
| -rw-r--r-- | src/views/dolphinview.h | 4 | ||||
| -rw-r--r-- | src/views/dolphinviewactionhandler.cpp | 3 |
19 files changed, 224 insertions, 71 deletions
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 831f620e6..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 "11") -set (RELEASE_SERVICE_VERSION_MICRO "90") +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/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/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp index 283f52565..925951bbf 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() @@ -110,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() @@ -198,6 +208,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(); @@ -271,21 +282,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 +344,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 +373,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 +484,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 +507,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(); @@ -108,17 +108,17 @@ 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. */ 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..64268542d 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -1628,7 +1628,7 @@ void DolphinMainWindow::setupActions() openTerminal->setWhatsThis(xi18nc("@info:whatsthis", "<para>This opens a <emphasis>terminal</emphasis> application for the viewed location.</para>" "<para>To learn more about terminals use the help in the terminal application.</para>")); - openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("dialog-scripts"))); + openTerminal->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); actionCollection()->setDefaultShortcut(openTerminal, Qt::SHIFT + Qt::Key_F4); connect(openTerminal, &QAction::triggered, this, &DolphinMainWindow::openTerminal); 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.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..01458f2c6 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" /> @@ -141,4 +142,4 @@ <Action priority="0" name="edit_paste"/> <Action priority="0" name="toggle_search"/> </ActionProperties> -</kpartgui> +</gui> 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/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/views/dolphinview.cpp b/src/views/dolphinview.cpp index 32e962459..ef346b3e4 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,29 @@ 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(); + // Add a new layout to hold it and put it in the layout + auto *centeringLayout = new QVBoxLayout(this); + m_container->setLayout(centeringLayout); + 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 +178,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 +1625,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 +1644,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 +2014,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..610b768c1 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); |
