From: Felix Ernst Date: Sun, 24 Apr 2022 00:34:43 +0000 (+0200) Subject: Keep working towards a reviewable state X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/402b4a5698f3d12d1848b298c38828d509abfd0d Keep working towards a reviewable state - Various code improvements - Smoother animations - The bottom bar in General Mode only becomes visible if items are currently selected - Removed the selection mode action from the default toolbar since it can already be toggled in various ways - More documentation - Some cleaning --- diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index aea0d31ad..fae30761e 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -83,8 +83,6 @@ #include #include -#include - namespace { // Used for GeneralSettings::version() to determine whether // an updated version of Dolphin is running, so as to migrate @@ -126,7 +124,7 @@ DolphinMainWindow::DolphinMainWindow() : setComponentName(QStringLiteral("dolphin"), QGuiApplication::applicationDisplayName()); setObjectName(QStringLiteral("Dolphin#")); - //setStateConfigGroup("State"); // TODO: Don't leave this as a comment. + setStateConfigGroup("State"); connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage, this, &DolphinMainWindow::showErrorMessage); @@ -195,7 +193,6 @@ DolphinMainWindow::DolphinMainWindow() : auto hamburgerMenu = static_cast(actionCollection()->action( KStandardAction::name(KStandardAction::HamburgerMenu))); - hamburgerMenu->icon(); hamburgerMenu->setMenuBar(menuBar()); hamburgerMenu->setShowMenuBarAction(showMenuBarAction); connect(hamburgerMenu, &KHamburgerMenu::aboutToShowMenu, @@ -1331,7 +1328,7 @@ void DolphinMainWindow::updateHamburgerMenu() menu->addMenu(m_newFileMenu->menu()); if (!toolBar()->isVisible() - || !toolbarActions.contains(ac->action(QStringLiteral("toggle_selection_mode_with_popup"))) + || !toolbarActions.contains(ac->action(QStringLiteral("toggle_selection_mode_tool_bar"))) ) { menu->addAction(ac->action(QStringLiteral("toggle_selection_mode"))); } @@ -1676,10 +1673,10 @@ void DolphinMainWindow::setupActions() // So in a way "Select" here is used to mean both "Select files" and also "Select what to do" but mostly the first. // The text is kept so unspecific because it will be shown on the toolbar where space is at a premium. toggleSelectionModeAction->setIconText(i18nc("@action:intoolbar", "Select")); - toggleSelectionModeAction->setWhatsThis(xi18nc("@info:whatsthis", "This application doesn't know which files or folders should be acted on, " - "unless they are selected first. Press this to toggle the Selection Mode which makes selecting and deselecting as " - "easy as pressing an item once.While in this mode, a quick access bar at the bottom shows all the available actions for the current " - "selection of items.")); + toggleSelectionModeAction->setWhatsThis(xi18nc("@info:whatsthis", "This application only knows which files or folders should be acted on if they are" + " selected first. Press this to toggle a Selection Mode which makes selecting and deselecting as easy as " + "pressing an item once.While in this mode, a quick access bar at the bottom shows available actions for the currently selected items." + "")); toggleSelectionModeAction->setIcon(QIcon::fromTheme(QStringLiteral("quickwizard"))); toggleSelectionModeAction->setCheckable(true); actionCollection()->setDefaultShortcut(toggleSelectionModeAction, Qt::Key_Space ); @@ -1690,7 +1687,7 @@ void DolphinMainWindow::setupActions() auto *toggleSelectionModeToolBarAction = new KToolBarPopupAction(toggleSelectionModeAction->icon(), toggleSelectionModeAction->iconText(), actionCollection()); toggleSelectionModeToolBarAction->setToolTip(toggleSelectionModeAction->text()); toggleSelectionModeToolBarAction->setWhatsThis(toggleSelectionModeAction->whatsThis()); - actionCollection()->addAction(QStringLiteral("toggle_selection_mode_with_popup"), toggleSelectionModeToolBarAction); + actionCollection()->addAction(QStringLiteral("toggle_selection_mode_tool_bar"), toggleSelectionModeToolBarAction); toggleSelectionModeToolBarAction->setCheckable(true); toggleSelectionModeToolBarAction->setPopupMode(QToolButton::DelayedPopup); connect(toggleSelectionModeToolBarAction, &QAction::triggered, toggleSelectionModeAction, &QAction::trigger); diff --git a/src/dolphinui.rc b/src/dolphinui.rc index a23912608..0eca6b8fe 100644 --- a/src/dolphinui.rc +++ b/src/dolphinui.rc @@ -113,7 +113,6 @@ - diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index dd72a6d66..d45096d0b 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -42,8 +42,6 @@ #include #include -#include - // An overview of the widgets contained by this ViewContainer struct LayoutStructure { int searchBox = 0; @@ -377,7 +375,6 @@ void DolphinViewContainer::disconnectUrlNavigator() void DolphinViewContainer::setSelectionModeEnabled(bool enabled, KActionCollection *actionCollection, SelectionModeBottomBar::Contents bottomBarContents) { - std::cout << "DolphinViewContainer::setSelectionModeEnabled(" << enabled << ", " << bottomBarContents << ")\n"; const bool wasEnabled = m_view->selectionMode(); m_view->setSelectionMode(enabled); @@ -410,7 +407,6 @@ void DolphinViewContainer::setSelectionModeEnabled(bool enabled, KActionCollecti connect(m_view, &DolphinView::selectionChanged, this, [this](const KFileItemList &selection) { m_selectionModeBottomBar->slotSelectionChanged(selection, m_view->url()); }); - connect(m_selectionModeBottomBar, &SelectionModeBottomBar::error, this, [this](const QString &errorMessage) { showErrorMessage(errorMessage); }); @@ -434,8 +430,15 @@ void DolphinViewContainer::setSelectionModeEnabled(bool enabled, KActionCollecti bool DolphinViewContainer::isSelectionModeEnabled() const { const bool isEnabled = m_view->selectionMode(); - Q_ASSERT( !isEnabled // We cannot assert the invisibility of the bars because of the hide animation. - || ( isEnabled && m_selectionModeTopBar && m_selectionModeTopBar->isVisible() && m_selectionModeBottomBar && m_selectionModeBottomBar->isVisible())); + Q_ASSERT((!isEnabled + // We can't assert that the bars are invisible only because the selection mode is disabled because the hide animation might still be playing. + && (!m_selectionModeBottomBar || !m_selectionModeBottomBar->isEnabled() || + !m_selectionModeBottomBar->isVisible() || m_selectionModeBottomBar->contents() == SelectionModeBottomBar::PasteContents)) + || ( isEnabled + && m_selectionModeTopBar && m_selectionModeTopBar->isVisible() + // The bottom bar is either visible or was hidden because it has nothing to show in GeneralContents mode e.g. because no items are selected. + && m_selectionModeBottomBar + && (m_selectionModeBottomBar->isVisible() || m_selectionModeBottomBar->contents() == SelectionModeBottomBar::GeneralContents))); return isEnabled; } diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index 03ee5cfe6..cc58ed06c 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -1546,7 +1546,8 @@ bool KItemListController::onPress(const QPoint& screenPos, const QPointF& pos, c } const bool shiftPressed = modifiers & Qt::ShiftModifier; - const bool controlPressed = (modifiers & Qt::ControlModifier) || m_selectionMode; + const bool controlPressed = (modifiers & Qt::ControlModifier) || m_selectionMode; // Keeping selectionMode similar to pressing control will hopefully + // simplify the overall logic and possibilities both for users and devs. const bool leftClick = buttons & Qt::LeftButton; const bool rightClick = buttons & Qt::RightButton; diff --git a/src/selectionmode/actionwithwidget.cpp b/src/selectionmode/actionwithwidget.cpp index 8e82a37bf..e9823af7c 100644 --- a/src/selectionmode/actionwithwidget.cpp +++ b/src/selectionmode/actionwithwidget.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/actionwithwidget.h b/src/selectionmode/actionwithwidget.h index 722fdf284..62dad0fc1 100644 --- a/src/selectionmode/actionwithwidget.h +++ b/src/selectionmode/actionwithwidget.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/backgroundcolorhelper.cpp b/src/selectionmode/backgroundcolorhelper.cpp index 8a7d69758..ca110e762 100644 --- a/src/selectionmode/backgroundcolorhelper.cpp +++ b/src/selectionmode/backgroundcolorhelper.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/backgroundcolorhelper.h b/src/selectionmode/backgroundcolorhelper.h index 0e8a61b34..013d33685 100644 --- a/src/selectionmode/backgroundcolorhelper.h +++ b/src/selectionmode/backgroundcolorhelper.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/selectionmodebottombar.cpp b/src/selectionmode/selectionmodebottombar.cpp index 5bf19295a..d10a8581b 100644 --- a/src/selectionmode/selectionmodebottombar.cpp +++ b/src/selectionmode/selectionmodebottombar.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -37,7 +37,7 @@ #include #include -#include + SelectionModeBottomBar::SelectionModeBottomBar(KActionCollection *actionCollection, QWidget *parent) : QWidget{parent}, m_actionCollection{actionCollection} @@ -73,44 +73,50 @@ SelectionModeBottomBar::SelectionModeBottomBar(KActionCollection *actionCollecti void SelectionModeBottomBar::setVisible(bool visible, Animated animated) { - Q_ASSERT_X(animated == WithAnimation, "SelectionModeBottomBar::setVisible", "This wasn't implemented."); + m_allowedToBeVisible = visible; + setVisibleInternal(visible, animated); +} +void SelectionModeBottomBar::setVisibleInternal(bool visible, Animated animated) +{ + Q_ASSERT_X(animated == WithAnimation, "SelectionModeBottomBar::setVisible", "This wasn't implemented."); if (!visible && m_contents == PasteContents) { return; // The bar with PasteContents should not be hidden or users might not know how to paste what they just copied. // Set m_contents to anything else to circumvent this prevention mechanism. } + if (visible && m_contents == GeneralContents && !m_internalContextMenu) { + return; // There is nothing on the bar that we want to show. We keep it invisible and only show it when the selection or the contents change. + } - if (!m_heightAnimation) { - m_heightAnimation = new QPropertyAnimation(this, "maximumHeight"); + setEnabled(visible); + if (m_heightAnimation) { + m_heightAnimation->stop(); // deletes because of QAbstractAnimation::DeleteWhenStopped. } - disconnect(m_heightAnimation, &QAbstractAnimation::finished, - this, nullptr); + m_heightAnimation = new QPropertyAnimation(this, "maximumHeight"); m_heightAnimation->setDuration(2 * style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) * GlobalConfig::animationDurationFactor()); + m_heightAnimation->setStartValue(height()); + m_heightAnimation->setEasingCurve(QEasingCurve::OutCubic); if (visible) { show(); - m_heightAnimation->setStartValue(0); m_heightAnimation->setEndValue(sizeHint().height()); - m_heightAnimation->setEasingCurve(QEasingCurve::OutCubic); connect(m_heightAnimation, &QAbstractAnimation::finished, this, [this](){ setMaximumHeight(sizeHint().height()); }); } else { - m_heightAnimation->setStartValue(height()); m_heightAnimation->setEndValue(0); - m_heightAnimation->setEasingCurve(QEasingCurve::OutCubic); connect(m_heightAnimation, &QAbstractAnimation::finished, this, &QWidget::hide); } - m_heightAnimation->start(); + m_heightAnimation->start(QAbstractAnimation::DeleteWhenStopped); } QSize SelectionModeBottomBar::sizeHint() const { - // 1 as width because this widget should never be the reason the DolphinViewContainer is made wider. return QSize{1, m_layout->parentWidget()->sizeHint().height()}; + // 1 as width because this widget should never be the reason the DolphinViewContainer is made wider. } void SelectionModeBottomBar::slotSelectionChanged(const KFileItemList &selection, const QUrl &baseUrl) @@ -118,10 +124,20 @@ void SelectionModeBottomBar::slotSelectionChanged(const KFileItemList &selection if (m_contents == GeneralContents) { auto contextActions = contextActionsFor(selection, baseUrl); m_generalBarActions.clear(); - for (auto i = contextActions.begin(); i != contextActions.end(); ++i) { - m_generalBarActions.emplace_back(ActionWithWidget{*i}); + if (contextActions.empty()) { + if (isVisibleTo(parentWidget())) { + setVisibleInternal(false, WithAnimation); + } + } else { + for (auto i = contextActions.begin(); i != contextActions.end(); ++i) { + m_generalBarActions.emplace_back(ActionWithWidget{*i}); + } + resetContents(GeneralContents); + + if (m_allowedToBeVisible) { + setVisibleInternal(true, WithAnimation); + } } - resetContents(GeneralContents); } updateMainActionButton(selection); } @@ -148,28 +164,42 @@ void SelectionModeBottomBar::resetContents(SelectionModeBottomBar::Contents cont m_contents = contents; switch (contents) { case CopyContents: - return addCopyContents(); + addCopyContents(); + break; case CopyLocationContents: - return addCopyLocationContents(); + addCopyLocationContents(); + break; case CopyToOtherViewContents: - return addCopyToOtherViewContents(); + addCopyToOtherViewContents(); + break; case CutContents: - return addCutContents(); + addCutContents(); + break; case DeleteContents: - return addDeleteContents(); + addDeleteContents(); + break; case DuplicateContents: - return addDuplicateContents(); + addDuplicateContents(); + break; case GeneralContents: - return addGeneralContents(); + addGeneralContents(); + break; case PasteContents: - return addPasteContents(); + addPasteContents(); + break; case MoveToOtherViewContents: - return addMoveToOtherViewContents(); + addMoveToOtherViewContents(); + break; case MoveToTrashContents: - return addMoveToTrashContents(); + addMoveToTrashContents(); + break; case RenameContents: return addRenameContents(); } + + if (m_allowedToBeVisible) { + setVisibleInternal(true, WithAnimation); + } } bool SelectionModeBottomBar::eventFilter(QObject *watched, QEvent *event) @@ -179,7 +209,12 @@ bool SelectionModeBottomBar::eventFilter(QObject *watched, QEvent *event) switch (event->type()) { case QEvent::ChildAdded: case QEvent::ChildRemoved: - QTimer::singleShot(0, this, [this](){ setMaximumHeight(sizeHint().height()); }); + QTimer::singleShot(0, this, [this]() { + // The necessary height might have changed because of the added/removed child so we change the height manually. + if (isVisibleTo(parentWidget()) && isEnabled() && (!m_heightAnimation || m_heightAnimation->state() != QAbstractAnimation::Running)) { + setMaximumHeight(sizeHint().height()); + } + }); // Fall through. default: return false; @@ -205,14 +240,12 @@ void SelectionModeBottomBar::resizeEvent(QResizeEvent *resizeEvent) i->widget()->setVisible(false); // Add the action to the overflow. - std::cout << "An Action is added to the m_overflowButton because of a resize: " << qPrintable(i->action()->text()) << "\n"; auto overflowMenu = m_overflowButton->menu(); if (overflowMenu->actions().isEmpty()) { overflowMenu->addAction(i->action()); } else { overflowMenu->insertAction(overflowMenu->actions().at(0), i->action()); } - std::cout << "The number of actions in the menu is now " << m_overflowButton->menu()->actions().count() << "\n."; m_overflowButton->setVisible(true); if (unusedSpace() >= 0) { break; // All widgets fit now. @@ -236,10 +269,8 @@ void SelectionModeBottomBar::resizeEvent(QResizeEvent *resizeEvent) i->widget()->setVisible(true); // Remove the action from the overflow. - std::cout << "An Action is removed from the m_overflowButton because of a resize: " << qPrintable(i->action()->text()) << "\n"; auto overflowMenu = m_overflowButton->menu(); overflowMenu->removeAction(i->action()); - std::cout << "The number of actions in the menu is now " << m_overflowButton->menu()->actions().count() << "\n."; if (overflowMenu->isEmpty()) { m_overflowButton->setVisible(false); } @@ -423,10 +454,8 @@ void SelectionModeBottomBar::addGeneralContents() m_layout->insertWidget(m_layout->count() - 1, i->widget()); // Insert before m_overflowButton } if (unusedSpace() < i->widget()->sizeHint().width()) { - std::cout << "The " << unusedSpace() << " is smaller than the button->sizeHint().width() of " << i->widget()->sizeHint().width() << " plus the m_layout->spacing() of " << m_layout->spacing() << " so the action " << qPrintable(i->action()->text()) << " doesn't get its own button.\n"; break; // The bar is too full already. We keep it invisible. } else { - std::cout << "The " << unusedSpace() << " is bigger than the button->sizeHint().width() of " << i->widget()->sizeHint().width() << " plus the m_layout->spacing() of " << m_layout->spacing() << " so the action " << qPrintable(i->action()->text()) << " was added as its own button/widget.\n"; i->widget()->setVisible(true); } } @@ -560,46 +589,51 @@ void SelectionModeBottomBar::emptyBarContents() std::vector SelectionModeBottomBar::contextActionsFor(const KFileItemList& selectedItems, const QUrl& baseUrl) { + if (selectedItems.isEmpty()) { + // There are no contextual actions to show for these items. + // We might even want to hide this bar in this case. To make this clear, we reset m_internalContextMenu. + m_internalContextMenu.release()->deleteLater(); + return std::vector{}; + } + std::vector contextActions; + + // We always want to show the most important actions at the beginning contextActions.emplace_back(m_actionCollection->action(KStandardAction::name(KStandardAction::Copy))); contextActions.emplace_back(m_actionCollection->action(KStandardAction::name(KStandardAction::Cut))); contextActions.emplace_back(m_actionCollection->action(KStandardAction::name(KStandardAction::RenameFile))); contextActions.emplace_back(m_actionCollection->action(KStandardAction::name(KStandardAction::MoveToTrash))); - if (!selectedItems.isEmpty()) { - // We are going to add the actions from the right-click context menu for the selected items. - auto *dolphinMainWindow = qobject_cast(window()); - Q_CHECK_PTR(dolphinMainWindow); - if (!m_fileItemActions) { - m_fileItemActions = new KFileItemActions(this); - m_fileItemActions->setParentWidget(dolphinMainWindow); - connect(m_fileItemActions, &KFileItemActions::error, this, &SelectionModeBottomBar::error); + // We are going to add the actions from the right-click context menu for the selected items. + auto *dolphinMainWindow = qobject_cast(window()); + Q_CHECK_PTR(dolphinMainWindow); + if (!m_fileItemActions) { + m_fileItemActions = new KFileItemActions(this); + m_fileItemActions->setParentWidget(dolphinMainWindow); + connect(m_fileItemActions, &KFileItemActions::error, this, &SelectionModeBottomBar::error); + } + m_internalContextMenu = std::make_unique(dolphinMainWindow, selectedItems.constFirst(), selectedItems, baseUrl, m_fileItemActions); + auto internalContextMenuActions = m_internalContextMenu->actions(); + + // There are some actions which we wouldn't want to add. We remember them in the actionsThatShouldntBeAdded set. + // We don't want to add the four basic actions again which were already added to the top. + std::unordered_set actionsThatShouldntBeAdded{contextActions.begin(), contextActions.end()}; + // "Delete" isn't really necessary to add because we have "Move to Trash" already. It is also more dangerous so let's exclude it. + actionsThatShouldntBeAdded.insert(m_actionCollection->action(KStandardAction::name(KStandardAction::DeleteFile))); + + // KHamburgerMenu would only be visible if there is no menu available anywhere on the user interface. This might be useful for recovery from + // such a situation in theory but a bar with context dependent actions doesn't really seem like the right place for it. + Q_ASSERT(internalContextMenuActions.first()->icon().name() == m_actionCollection->action(KStandardAction::name(KStandardAction::HamburgerMenu))->icon().name()); + internalContextMenuActions.removeFirst(); + + for (auto it = internalContextMenuActions.constBegin(); it != internalContextMenuActions.constEnd(); ++it) { + if (actionsThatShouldntBeAdded.count(*it)) { + continue; // Skip this action. } - m_internalContextMenu = std::make_unique(dolphinMainWindow, selectedItems.constFirst(), selectedItems, baseUrl, m_fileItemActions); - auto internalContextMenuActions = m_internalContextMenu->actions(); - - // There are some actions which we wouldn't want to add. We remember them in the actionsThatShouldntBeAdded set. - // We don't want to add the four basic actions again which were already added to the top. - std::unordered_set actionsThatShouldntBeAdded{contextActions.begin(), contextActions.end()}; - // "Delete" isn't really necessary to add because we have "Move to Trash" already. It is also more dangerous so let's exclude it. - actionsThatShouldntBeAdded.insert(m_actionCollection->action(KStandardAction::name(KStandardAction::DeleteFile))); - // "Open Terminal" isn't really context dependent and can therefore be opened from elsewhere instead. - actionsThatShouldntBeAdded.insert(m_actionCollection->action(QStringLiteral("open_terminal"))); - - // KHamburgerMenu would only be visible if there is no menu available anywhere on the user interface. This might be useful for recovery from - // such a situation in theory but a bar with context dependent actions doesn't really seem like the right place for it. - Q_ASSERT(internalContextMenuActions.first()->icon().name() == m_actionCollection->action(KStandardAction::name(KStandardAction::HamburgerMenu))->icon().name()); - internalContextMenuActions.removeFirst(); - - for (auto it = internalContextMenuActions.constBegin(); it != internalContextMenuActions.constEnd(); ++it) { - if (actionsThatShouldntBeAdded.count(*it)) { - continue; // Skip this action. - } - if (!qobject_cast(*it)) { // We already have a "Move to Trash" action so we don't want a DolphinRemoveAction. - // We filter duplicate separators here so we won't have to deal with them later. - if (!contextActions.back()->isSeparator() || !(*it)->isSeparator()) { - contextActions.emplace_back((*it)); - } + if (!qobject_cast(*it)) { // We already have a "Move to Trash" action so we don't want a DolphinRemoveAction. + // We filter duplicate separators here so we won't have to deal with them later. + if (!contextActions.back()->isSeparator() || !(*it)->isSeparator()) { + contextActions.emplace_back((*it)); } } } @@ -612,21 +646,13 @@ int SelectionModeBottomBar::unusedSpace() const if (m_overflowButton) { sumOfPreferredWidths += m_overflowButton->sizeHint().width(); } - std::cout << "These layout items should have sane width: "; for (int i = 0; i < m_layout->count(); ++i) { auto widget = m_layout->itemAt(i)->widget(); if (widget && !widget->isVisibleTo(widget->parentWidget())) { continue; // We don't count invisible widgets. } - std::cout << m_layout->itemAt(i)->sizeHint().width() << ", "; - if (m_layout->itemAt(i)->sizeHint().width() == 0) { - // One of the items reports an invalid width. We can't work with this so we report an unused space of 0 which should lead to as few changes to the - // layout as possible until the next resize event happens at a later point in time. - //return 0; - } sumOfPreferredWidths += m_layout->itemAt(i)->sizeHint().width() + m_layout->spacing(); } - std::cout << "leads to unusedSpace = " << width() << " - " << sumOfPreferredWidths - 20 << " = " << width() - sumOfPreferredWidths - 20 << "\n"; return width() - sumOfPreferredWidths - 20; // We consider all space used when there are only 20 pixels left // so there is some room to breath and not too much wonkyness while resizing. } @@ -636,7 +662,6 @@ void SelectionModeBottomBar::updateExplanatoryLabelVisibility() if (!m_explanatoryLabel) { return; } - std::cout << "label minimumSizeHint compared to width() :" << m_explanatoryLabel->sizeHint().width() << "/" << m_explanatoryLabel->width() << "; unusedSpace: " << unusedSpace() << "\n"; if (m_explanatoryLabel->isVisible()) { m_explanatoryLabel->setVisible(unusedSpace() > 0); } else { @@ -660,17 +685,17 @@ void SelectionModeBottomBar::updateMainActionButton(const KFileItemList& selecti switch (m_contents) { case CopyContents: buttonText = i18ncp("@action A more elaborate and clearly worded version of the Copy action", - "Copy %2 to the Clipboard", "Copy %2 to the Clipboard", selection.count(), + "Copy %2 to the Clipboard", "Copy %2 to the Clipboard", selection.count(), fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; case CopyLocationContents: buttonText = i18ncp("@action A more elaborate and clearly worded version of the Copy Location action", - "Copy the Location of %2 to the Clipboard", "Copy the Location of %2 to the Clipboard", selection.count(), + "Copy the Location of %2 to the Clipboard", "Copy the Location of %2 to the Clipboard", selection.count(), fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; case CutContents: buttonText = i18ncp("@action A more elaborate and clearly worded version of the Cut action", - "Cut %2 to the Clipboard", "Cut %2 to the Clipboard", selection.count(), + "Cut %2 to the Clipboard", "Cut %2 to the Clipboard", selection.count(), fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; case DeleteContents: diff --git a/src/selectionmode/selectionmodebottombar.h b/src/selectionmode/selectionmodebottombar.h index 61cb90334..89fd3c3a3 100644 --- a/src/selectionmode/selectionmodebottombar.h +++ b/src/selectionmode/selectionmodebottombar.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -66,6 +66,9 @@ public: /** * Plays a show or hide animation while changing visibility. * Therefore, if this method is used to hide this widget, the actual hiding will be postponed until the animation finished. + * + * This bar might also not show itself when setVisible(true), when context menu actions are supposed to be shown + * for the selected items but no items have been selected yet. In that case it will only show itself once items were selected. * @see QWidget::setVisible() */ void setVisible(bool visible, Animated animated); @@ -77,6 +80,7 @@ public: return m_contents; }; + /** @returns a width of 1 to make sure that this bar never causes side panels to shrink. */ QSize sizeHint() const override; public Q_SLOTS: @@ -96,9 +100,18 @@ Q_SIGNALS: protected: /** Is installed on an internal widget to make sure that the height of the bar is adjusted to its contents. */ bool eventFilter(QObject *watched, QEvent *event) override; + + /** Adapts the way the contents of this bar are displayed based on the available width. */ void resizeEvent(QResizeEvent *resizeEvent) override; private: + /** + * Identical to SelectionModeBottomBar::setVisible() but doesn't change m_allowedToBeVisible. + * @see SelectionModeBottomBar::setVisible() + * @see m_allowedToBeVisible + */ + void setVisibleInternal(bool visible, Animated animated); + void addCopyContents(); void addCopyLocationContents(); void addCopyToOtherViewContents(); @@ -171,6 +184,10 @@ private: * Do not confuse this with layout() because we do have a QScrollView in between this widget and m_layout. */ QHBoxLayout *m_layout; + /** Remembers if this bar was setVisible(true) or setVisible(false) the last time. + * This is necessary because this bar might have been setVisible(true) but there is no reason to show the bar currently so it was kept hidden. + * @see SelectionModeBottomBar::setVisible() */ + bool m_allowedToBeVisible = false; /// @see SelectionModeBottomBar::setVisible() QPointer m_heightAnimation; diff --git a/src/selectionmode/selectionmodetopbar.cpp b/src/selectionmode/selectionmodetopbar.cpp index 89a4aa03a..83aa8e849 100644 --- a/src/selectionmode/selectionmodetopbar.cpp +++ b/src/selectionmode/selectionmodetopbar.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -22,9 +22,6 @@ #include #include -#include -#include - SelectionModeTopBar::SelectionModeTopBar(QWidget *parent) : QWidget{parent} { @@ -90,29 +87,26 @@ void SelectionModeTopBar::setVisible(bool visible, Animated animated) { Q_ASSERT_X(animated == WithAnimation, "SelectionModeTopBar::setVisible", "This wasn't implemented."); - if (!m_heightAnimation) { - m_heightAnimation = new QPropertyAnimation(this, "maximumHeight"); + if (m_heightAnimation) { + m_heightAnimation->stop(); // deletes because of QAbstractAnimation::DeleteWhenStopped. } - disconnect(m_heightAnimation, &QAbstractAnimation::finished, - this, &QWidget::hide); + m_heightAnimation = new QPropertyAnimation(this, "maximumHeight"); m_heightAnimation->setDuration(2 * style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, this) * GlobalConfig::animationDurationFactor()); + m_heightAnimation->setStartValue(height()); + m_heightAnimation->setEasingCurve(QEasingCurve::OutCubic); if (visible) { show(); - m_heightAnimation->setStartValue(0); m_heightAnimation->setEndValue(m_preferredHeight); - m_heightAnimation->setEasingCurve(QEasingCurve::OutCubic); } else { - m_heightAnimation->setStartValue(height()); m_heightAnimation->setEndValue(0); - m_heightAnimation->setEasingCurve(QEasingCurve::OutCubic); connect(m_heightAnimation, &QAbstractAnimation::finished, this, &QWidget::hide); } - m_heightAnimation->start(); + m_heightAnimation->start(QAbstractAnimation::DeleteWhenStopped); } void SelectionModeTopBar::resizeEvent(QResizeEvent */* resizeEvent */) diff --git a/src/selectionmode/selectionmodetopbar.h b/src/selectionmode/selectionmodetopbar.h index fa829aef5..eb26a5c26 100644 --- a/src/selectionmode/selectionmodetopbar.h +++ b/src/selectionmode/selectionmodetopbar.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2022 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/selectionmode/singleclickselectionproxystyle.h b/src/selectionmode/singleclickselectionproxystyle.h index 9c185a85a..65117c56c 100644 --- a/src/selectionmode/singleclickselectionproxystyle.h +++ b/src/selectionmode/singleclickselectionproxystyle.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project - SPDX-FileCopyrightText: 2020 Felix Ernst + SPDX-FileCopyrightText: 2022 Felix Ernst SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ diff --git a/src/views/dolphinviewactionhandler.cpp b/src/views/dolphinviewactionhandler.cpp index a66d1f6dd..b2e45a5f6 100644 --- a/src/views/dolphinviewactionhandler.cpp +++ b/src/views/dolphinviewactionhandler.cpp @@ -29,8 +29,6 @@ #include #include -#include - DolphinViewActionHandler::DolphinViewActionHandler(KActionCollection* collection, QObject* parent) : QObject(parent), m_actionCollection(collection),