Commit 402b4a56 authored by Felix Ernst's avatar Felix Ernst 🇺🇦
Browse files

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
parent 3b7c05b3
......@@ -83,8 +83,6 @@
#include <QToolButton>
#include <QWhatsThisClickedEvent>
#include <iostream>
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<KHamburgerMenu *>(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", "<para>This application doesn't know which files or folders should be acted on, "
"unless they are <emphasis>selected</emphasis> first. Press this to toggle the <emphasis>Selection Mode</emphasis> which makes selecting and deselecting as "
"easy as pressing an item once.</para><para>While in this mode, a quick access bar at the bottom shows all the available actions for the current "
"selection of items.</para>"));
toggleSelectionModeAction->setWhatsThis(xi18nc("@info:whatsthis", "<para>This application only knows which files or folders should be acted on if they are"
" <emphasis>selected</emphasis> first. Press this to toggle a <emphasis>Selection Mode</emphasis> which makes selecting and deselecting as easy as "
"pressing an item once.</para><para>While in this mode, a quick access bar at the bottom shows available actions for the currently selected items."
"</para>"));
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);
......
......@@ -113,7 +113,6 @@
<Action name="split_view" />
<Action name="split_stash" />
<Action name="toggle_search" />
<Action name="toggle_selection_mode_with_popup" />
<Action name="hamburger_menu" />
</ToolBar>
<ActionProperties scheme="Default">
......
......@@ -42,8 +42,6 @@
#include <QUrl>
#include <QDesktopServices>
#include <iostream>
// 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;
}
......
......@@ -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;
......
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2022 Felix Ernst <fe.a.ernst@gmail.com>
SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
......
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2022 Felix Ernst <fe.a.ernst@gmail.com>
SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
......
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2022 Felix Ernst <fe.a.ernst@gmail.com>
SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
......
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2022 Felix Ernst <fe.a.ernst@gmail.com>
SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
......
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2022 Felix Ernst <fe.a.ernst@gmail.com>
SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
......@@ -37,7 +37,7 @@
#include <QVBoxLayout>
#include <unordered_set>
#include <iostream>
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<QAction *> 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<QAction *>{};
}
std::vector<QAction *> 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<DolphinMainWindow *>(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<DolphinMainWindow *>(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<DolphinContextMenu>(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<QAction *> 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<DolphinContextMenu>(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<QAction *> 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<DolphinRemoveAction *>(*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<DolphinRemoveAction *>(*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:
......
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2022 Felix Ernst <fe.a.ernst@gmail.com>
SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
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<QPropertyAnimation> m_heightAnimation;
......
/*
This file is part of the KDE project
SPDX-FileCopyrightText: 2022 Felix Ernst <fe.a.ernst@gmail.com>
SPDX-FileCopyrightText: 2022 Felix Ernst <felixernst@zohomail.eu>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
......@@ -22,9 +22,6 @@
#include <QStyle>
#include <QtGlobal>
#include <type_traits>
#include <iostream>
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);
}