diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/dolphincontextmenu.cpp | 85 | ||||
| -rw-r--r-- | src/dolphincontextmenu.h | 14 | ||||
| -rw-r--r-- | src/dolphinmainwindow.cpp | 56 | ||||
| -rw-r--r-- | src/dolphinmainwindow.h | 1 | ||||
| -rw-r--r-- | src/dolphinnavigatorswidgetaction.cpp | 2 | ||||
| -rw-r--r-- | src/dolphinpart.rc | 7 | ||||
| -rw-r--r-- | src/dolphinui.rc | 11 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistview.cpp | 54 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistview.h | 3 | ||||
| -rw-r--r-- | src/search/dolphinsearchbox.cpp | 11 | ||||
| -rw-r--r-- | src/settings/general/configurepreviewplugindialog.cpp | 1 | ||||
| -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/settings/viewpropertiesdialog.cpp | 5 | ||||
| -rw-r--r-- | src/settings/viewpropsprogressinfo.cpp | 1 | ||||
| -rw-r--r-- | src/tests/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | src/views/dolphinview.cpp | 71 | ||||
| -rw-r--r-- | src/views/dolphinview.h | 4 | ||||
| -rw-r--r-- | src/views/dolphinviewactionhandler.cpp | 3 |
21 files changed, 247 insertions, 94 deletions
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..636a8e1a9 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -173,8 +173,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 +383,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 +847,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(); @@ -1442,6 +1451,29 @@ void DolphinMainWindow::setupActions() 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")); @@ -1597,16 +1629,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"))); @@ -1628,7 +1650,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); @@ -2032,8 +2054,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.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/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/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..4d7ee589a 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(); 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..2bf317440 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); 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..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); |
