diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index d8d3044832..fcaa5d4a2f 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -125,7 +125,7 @@ DolphinMainWindow::DolphinMainWindow() : setComponentName(QStringLiteral("dolphin"), QGuiApplication::applicationDisplayName()); setObjectName(QStringLiteral("Dolphin#")); - // setStateConfigGroup("State"); + setStateConfigGroup("State"); connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage, this, &DolphinMainWindow::showErrorMessage); @@ -1675,8 +1675,7 @@ void DolphinMainWindow::setupActions() QAction *toggleSelectionModeAction = actionCollection()->addAction(QStringLiteral("toggle_selection_mode")); // i18n: This action toggles a selection mode. toggleSelectionModeAction->setText(i18nc("@action:inmenu", "Select Files and Folders")); - // i18n: Opens a selection mode for selecting files/folders and later selecting an action that acts on them. - // So in a way "Select" here is used to mean both "Select files" and also "Select what to do" but mostly the first. + // i18n: Opens a selection mode for selecting files/folders. // 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 only knows which files or folders should be acted on if they are" diff --git a/src/selectionmode/actiontexthelper.cpp b/src/selectionmode/actiontexthelper.cpp index 3eb868a8cd..1036042362 100644 --- a/src/selectionmode/actiontexthelper.cpp +++ b/src/selectionmode/actiontexthelper.cpp @@ -22,10 +22,13 @@ void ActionTextHelper::registerTextWhenNothingIsSelected(QAction *action, QStrin void ActionTextHelper::textsWhenNothingIsSelectedEnabled(bool enabled) { for (auto i = m_registeredActionTextChanges.begin(); i != m_registeredActionTextChanges.end(); ++i) { - if (!i->action) { + while (!i->action) { i = m_registeredActionTextChanges.erase(i); - continue; + if (i == m_registeredActionTextChanges.end()) { + break; + } } + if (enabled && i->textStateOfRegisteredText == TextWhenNothingIsSelected) { QString textWhenSomethingIsSelected = i->action->text(); i->action->setText(i->registeredText); diff --git a/src/selectionmode/actiontexthelper.h b/src/selectionmode/actiontexthelper.h index 8f7501fa4e..1b88403754 100644 --- a/src/selectionmode/actiontexthelper.h +++ b/src/selectionmode/actiontexthelper.h @@ -17,6 +17,11 @@ namespace SelectionMode /** * @brief Helps changing the texts of actions depending on the current selection. + * + * This is useful for actions that directly trigger a change when there is a selection and do something + * different when nothing is selected. For example should the copy action read "Copy" when items are + * selected but when no items are selected it can read "Copy…" since triggering it will enter selection + * mode and ask users to select the files they want to copy first. */ class ActionTextHelper : QObject { @@ -25,7 +30,7 @@ public: /** * Changes the text of \a action to \a text whenever textsWhenNothingIsSelectedEnabled(true) is called. - * The texts can be changed back by calling textsWhenNothingIsSelectedEnabled(false) is called. + * The texts can be changed back by calling textsWhenNothingIsSelectedEnabled(false). * @see textsWhenNothingIsSelectedEnabled() */ void registerTextWhenNothingIsSelected(QAction *action, QString registeredText); diff --git a/src/selectionmode/actionwithwidget.h b/src/selectionmode/actionwithwidget.h index cf7b8bc351..14db6df222 100644 --- a/src/selectionmode/actionwithwidget.h +++ b/src/selectionmode/actionwithwidget.h @@ -21,6 +21,9 @@ namespace SelectionMode * @brief Small wrapper/helper class that contains an action and its widget. * * This class takes neither the responsibility for deleting its action() nor its widget(). + * + * This class is only used from BottomBarContentsContainer currently. + * @see BottomBarContentsContainer */ class ActionWithWidget { @@ -28,9 +31,9 @@ public: ActionWithWidget(QAction *action); /** - * Connect @p action and @p button using copyActionDataToButton() and the - * wraps the two together in the ActionWithWidget object. - * ActionWithWidget doesn't take any ownership. + * Connect @p action and @p button using copyActionDataToButton() and + * wraps the two together in a ActionWithWidget object. + * ActionWithWidget doesn't take any ownership over the parameters. * * @see copyActionDataToButton() * @@ -38,7 +41,7 @@ public: */ ActionWithWidget(QAction *action, QAbstractButton *button); - /** @returns the action of this object. Crashes if that action has been deleted elsewhere in the meantime. */ + /** @returns the action of this object. */ inline QAction *action() { Q_CHECK_PTR(m_action); return m_action; @@ -69,7 +72,7 @@ private: /** * A small helper method. - * @return a button with the correct styling for the general mode of the SelectionModeBottomBar which can be added to its layout. + * @return a button with the correct styling for the general mode of the BottomBarContentsContainer which can be added to its layout. */ QAbstractButton *newButtonForAction(QAction *action, QWidget *parent); diff --git a/src/selectionmode/backgroundcolorhelper.cpp b/src/selectionmode/backgroundcolorhelper.cpp index 4477d0f2c1..fc54031525 100644 --- a/src/selectionmode/backgroundcolorhelper.cpp +++ b/src/selectionmode/backgroundcolorhelper.cpp @@ -54,9 +54,11 @@ void BackgroundColorHelper::slotPaletteChanged() { updateBackgroundColor(); for (auto i = m_colorControlledWidgets.begin(); i != m_colorControlledWidgets.end(); ++i) { - if (!*i) { + while (!*i) { i = m_colorControlledWidgets.erase(i); - continue; + if (i == m_colorControlledWidgets.end()) { + break; + } } setBackgroundColorForWidget(*i, m_backgroundColor); } @@ -83,7 +85,8 @@ void BackgroundColorHelper::updateBackgroundColor() } m_backgroundColor = QColor::fromHsv(newHue, - // Saturation should be closer to the active color because otherwise the selection mode color might overpower it. + // Saturation should be closer to the saturation of the active color + // because otherwise the selection mode color might overpower it. .7 * activeBackgroundColor.saturation() + .3 * positiveBackgroundColor.saturation(), (activeBackgroundColor.value() + positiveBackgroundColor.value()) / 2, (activeBackgroundColor.alpha() + positiveBackgroundColor.alpha()) / 2); diff --git a/src/selectionmode/backgroundcolorhelper.h b/src/selectionmode/backgroundcolorhelper.h index 8d2730fcf1..251c5eddf5 100644 --- a/src/selectionmode/backgroundcolorhelper.h +++ b/src/selectionmode/backgroundcolorhelper.h @@ -28,20 +28,30 @@ public: /** * Changes the background color of @p widget to a distinct color scheme matching color which makes it clear that the widget belongs to the selection mode. + * The background color of @p widget will from now on be updated automatically when the palette of the application changes. */ void controlBackgroundColor(QWidget *widget); private: BackgroundColorHelper(); + /** + * Called when the palette of the application changes. + * Triggers updateBackgroundColor() and the updates the background color of m_colorControlledWidgets. + * @see updateBackgroundColor + */ void slotPaletteChanged(); + /** Calculates a new m_colorControlledWidgets based on the current colour scheme of the application. */ void updateBackgroundColor(); private: + /// The widgets who have given up control over the background color to BackgroundColorHelper. std::vector> m_colorControlledWidgets; + /// The color to be used for the widgets' backgrounds. QColor m_backgroundColor; + /// Singleton object static BackgroundColorHelper *s_instance; }; diff --git a/src/selectionmode/bottombar.cpp b/src/selectionmode/bottombar.cpp index 999b24ae47..4ca184a6df 100644 --- a/src/selectionmode/bottombar.cpp +++ b/src/selectionmode/bottombar.cpp @@ -11,11 +11,6 @@ #include "backgroundcolorhelper.h" #include "global.h" -#include -#include -#include -#include - #include #include #include @@ -87,7 +82,6 @@ void BottomBar::setVisibleInternal(bool visible, Animated animated) 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) { @@ -166,7 +160,7 @@ void BottomBar::resizeEvent(QResizeEvent *resizeEvent) return QWidget::resizeEvent(resizeEvent); } - m_contentsContainer->updateForNewWidth(); + m_contentsContainer->adaptToNewBarWidth(width()); return QWidget::resizeEvent(resizeEvent); } diff --git a/src/selectionmode/bottombar.h b/src/selectionmode/bottombar.h index ff23b66998..ab29a85a5b 100644 --- a/src/selectionmode/bottombar.h +++ b/src/selectionmode/bottombar.h @@ -15,8 +15,6 @@ #include #include -#include - class KActionCollection; class KFileItemList; class QAction; @@ -30,7 +28,7 @@ namespace SelectionMode class BottomBarContentsContainer; /** - * A bar used in selection mode that serves various purposes depending on what the user is currently trying to do. + * @brief A bar used in selection mode that serves various purposes depending on what the user is currently trying to do. * * The Contents enum below gives a rough idea about the different states this bar might have. * The bar is notified of various changes that make changing or updating the content worthwhile. @@ -43,7 +41,7 @@ class BottomBar : public QWidget public: /** The different contents this bar can have. */ - enum Contents{ + enum Contents { CopyContents, CopyLocationContents, CopyToOtherViewContents, @@ -69,11 +67,20 @@ public: * * 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. + * + * This bar might also ignore a setVisible(false) call, if it has PasteContents because that bar is supposed to stay visible + * even outside of selection mode. + * + * @param visible Whether this bar is supposed to be visible long term + * @param animated Whether this should be animated. The animation is skipped if the users' settings are configured that way. + * * @see QWidget::setVisible() */ void setVisible(bool visible, Animated animated); - using QWidget::setVisible; // Makes sure that the setVisible() declaration above doesn't hide the one from QWidget. + /** + * Changes the contents of the bar to @p contents. + */ void resetContents(Contents contents); Contents contents() const; @@ -81,6 +88,7 @@ public: QSize sizeHint() const override; public Q_SLOTS: + /** Adapts the contents based on the selection in the related view. */ void slotSelectionChanged(const KFileItemList &selection, const QUrl &baseUrl); /** Used to notify the m_selectionModeBottomBar that there is no other ViewContainer in the tab. */ @@ -102,6 +110,8 @@ protected: void resizeEvent(QResizeEvent *resizeEvent) override; private: + using QWidget::setVisible; // Makes sure that the setVisible() declaration above doesn't hide the one from QWidget so we can still use it privately. + /** * Identical to SelectionModeBottomBar::setVisible() but doesn't change m_allowedToBeVisible. * @see SelectionModeBottomBar::setVisible() @@ -119,7 +129,7 @@ private: * 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() + /** @see SelectionModeBottomBar::setVisible() */ QPointer m_heightAnimation; }; diff --git a/src/selectionmode/bottombarcontentscontainer.cpp b/src/selectionmode/bottombarcontentscontainer.cpp index 04b52a60f1..2c924415ac 100644 --- a/src/selectionmode/bottombarcontentscontainer.cpp +++ b/src/selectionmode/bottombarcontentscontainer.cpp @@ -69,8 +69,10 @@ void BottomBarContentsContainer::resetContents(BottomBar::Contents contents) } } -void BottomBarContentsContainer::updateForNewWidth() +void BottomBarContentsContainer::adaptToNewBarWidth(int newBarWidth) { + m_barWidth = newBarWidth; + if (m_contents == BottomBar::GeneralContents) { Q_ASSERT(m_overflowButton); if (unusedSpace() < 0) { @@ -94,7 +96,7 @@ void BottomBarContentsContainer::updateForNewWidth() } } } else { - // We have some unusedSpace(). Let's check if we can maybe add more of the contextual action's widgets. + // We have some unusedSpace(). Let's check if we can maybe add more of the contextual actions' widgets. for (auto i = m_generalBarActions.begin(); i != m_generalBarActions.end(); ++i) { if (i->isWidgetVisible()) { continue; @@ -130,6 +132,7 @@ void BottomBarContentsContainer::slotSelectionChanged(const KFileItemList &selec auto contextActions = contextActionsFor(selection, baseUrl); m_generalBarActions.clear(); if (contextActions.empty()) { + // We have nothing to show Q_ASSERT(qobject_cast(parentWidget()->parentWidget()->parentWidget())); if (isVisibleTo(parentWidget()->parentWidget()->parentWidget()->parentWidget())) { // is the bar visible Q_EMIT barVisibilityChangeRequested(false); @@ -162,7 +165,7 @@ void BottomBarContentsContainer::addCopyContents() // We claim to have PasteContents already so triggering the copy action next won't instantly hide the bottom bar. connect(copyButton, &QAbstractButton::clicked, [this]() { if (GeneralSettings::showPasteBarAfterCopying()) { - m_contents = BottomBar::Contents::PasteContents; + m_contents = BottomBar::Contents::PasteContents; // prevents hiding } }); // Connect the copy action as a second step. @@ -232,7 +235,7 @@ void BottomBarContentsContainer::addCutContents() // We claim to have PasteContents already so triggering the cut action next won't instantly hide the bottom bar. connect(cutButton, &QAbstractButton::clicked, [this]() { if (GeneralSettings::showPasteBarAfterCopying()) { - m_contents = BottomBar::Contents::PasteContents; + m_contents = BottomBar::Contents::PasteContents; // prevents hiding } }); // Connect the cut action as a second step. @@ -400,9 +403,9 @@ void BottomBarContentsContainer::addPasteContents() vBoxLayout->addWidget(pasteButton); auto *dismissButton = new QToolButton(this); - dismissButton->setText(i18nc("@action Dismisses a bar explaining how to use the Paste action", "Dismiss this Reminder")); + dismissButton->setText(i18nc("@action Dismisses a bar explaining how to use the Paste action", "Dismiss This Reminder")); connect(dismissButton, &QAbstractButton::clicked, this, actuallyLeaveSelectionMode); - auto *dontRemindAgainAction = new QAction(i18nc("@action Dismisses an explanatory area and never shows it again", "Don't remind me again"), this); + auto *dontRemindAgainAction = new QAction(i18nc("@action Dismisses an explanatory area and never shows it again", "Don't Remind Me Again"), this); connect(dontRemindAgainAction, &QAction::triggered, this, []() { GeneralSettings::setShowPasteBarAfterCopying(false); }); @@ -516,9 +519,7 @@ int BottomBarContentsContainer::unusedSpace() const } sumOfPreferredWidths += m_layout->itemAt(i)->sizeHint().width() + m_layout->spacing(); } - Q_ASSERT(qobject_cast(parentWidget()->parentWidget()->parentWidget())); - const int totalBarWidth = parentWidget()->parentWidget()->parentWidget()->width(); - return totalBarWidth - sumOfPreferredWidths - 20; // We consider all space used when there are only 20 pixels left + return m_barWidth - 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. } @@ -535,7 +536,7 @@ void BottomBarContentsContainer::updateExplanatoryLabelVisibility() } } -void BottomBarContentsContainer::updateMainActionButton(const KFileItemList& selection) +void BottomBarContentsContainer::updateMainActionButton(const KFileItemList& selectedItems) { if (!m_mainAction.widget()) { return; @@ -543,45 +544,69 @@ void BottomBarContentsContainer::updateMainActionButton(const KFileItemList& sel Q_ASSERT(qobject_cast(m_mainAction.widget())); // Users are nudged towards selecting items by having the button disabled when nothing is selected. - m_mainAction.widget()->setEnabled(selection.count() > 0 && m_mainAction.action()->isEnabled()); + m_mainAction.widget()->setEnabled(selectedItems.count() > 0 && m_mainAction.action()->isEnabled()); QFontMetrics fontMetrics = m_mainAction.widget()->fontMetrics(); QString buttonText; switch (m_contents) { case BottomBar::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(), - fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); + // i18n: A more elaborate and clearly worded version of the Copy action + // %2 is a textual representation of the currently selected files or folders. This can be the name of + // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders". + // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes) + // and a fallback will be used. + buttonText = i18ncp("@action", "Copy %2 to the Clipboard", "Copy %2 to the Clipboard", selectedItems.count(), fileItemListToString(selectedItems, fontMetrics.averageCharWidth() * 20, fontMetrics)); + // All these long lines can not be broken up with line breaks becaue the i18n call should be completely + // in the line following the "i18n:" comment without any line breaks within the i18n call + // or the comment might not be correctly extracted. See: https://commits.kde.org/kxmlgui/a31135046e1b3335b5d7bbbe6aa9a883ce3284c1 break; case BottomBar::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(), - fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); + // i18n: A more elaborate and clearly worded version of the Copy Location action + // %2 is a textual representation of the currently selected files or folders. This can be the name of + // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders". + // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes) + // and a fallback will be used. + buttonText = i18ncp("@action", "Copy the Location of %2 to the Clipboard", "Copy the Location of %2 to the Clipboard", selectedItems.count(), fileItemListToString(selectedItems, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; case BottomBar::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(), - fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); + // i18n: A more elaborate and clearly worded version of the Cut action + // %2 is a textual representation of the currently selected files or folders. This can be the name of + // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders". + // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes) + // and a fallback will be used. + buttonText = i18ncp("@action", "Cut %2 to the Clipboard", "Cut %2 to the Clipboard", selectedItems.count(), fileItemListToString(selectedItems, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; case BottomBar::DeleteContents: - buttonText = i18ncp("@action A more elaborate and clearly worded version of the Delete action", - "Permanently Delete %2", "Permanently Delete %2", selection.count(), - fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); + // i18n: A more elaborate and clearly worded version of the Delete action + // %2 is a textual representation of the currently selected files or folders. This can be the name of + // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders". + // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes) + // and a fallback will be used. + buttonText = i18ncp("@action", "Permanently Delete %2", "Permanently Delete %2", selectedItems.count(), fileItemListToString(selectedItems, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; case BottomBar::DuplicateContents: - buttonText = i18ncp("@action A more elaborate and clearly worded version of the Duplicate action", - "Duplicate %2", "Duplicate %2", selection.count(), - fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); + // i18n: A more elaborate and clearly worded version of the Duplicate action + // %2 is a textual representation of the currently selected files or folders. This can be the name of + // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders". + // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes) + // and a fallback will be used. + buttonText = i18ncp("@action", "Duplicate %2", "Duplicate %2", selectedItems.count(), fileItemListToString(selectedItems, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; case BottomBar::MoveToTrashContents: - buttonText = i18ncp("@action A more elaborate and clearly worded version of the Trash action", - "Move %2 to the Trash", "Move %2 to the Trash", selection.count(), - fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); + // i18n: A more elaborate and clearly worded version of the Trash action + // %2 is a textual representation of the currently selected files or folders. This can be the name of + // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders". + // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes) + // and a fallback will be used. + buttonText = i18ncp("@action", "Move %2 to the Trash", "Move %2 to the Trash", selectedItems.count(), fileItemListToString(selectedItems, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; case BottomBar::RenameContents: - buttonText = i18ncp("@action A more elaborate and clearly worded version of the Rename action", - "Rename %2", "Rename %2", selection.count(), - fileItemListToString(selection, fontMetrics.averageCharWidth() * 20, fontMetrics)); + // i18n: A more elaborate and clearly worded version of the Rename action + // %2 is a textual representation of the currently selected files or folders. This can be the name of + // the file/files like "file1" or "file1, file2 and file3" or an aggregate like "8 Selected Folders". + // If this sort of word puzzle can not be correctly translated in your language, translate it as "NULL" (without the quotes) + // and a fallback will be used. + buttonText = i18ncp("@action", "Rename %2", "Rename %2", selectedItems.count(), fileItemListToString(selectedItems, fontMetrics.averageCharWidth() * 20, fontMetrics)); break; default: return; diff --git a/src/selectionmode/bottombarcontentscontainer.h b/src/selectionmode/bottombarcontentscontainer.h index 6255ff987c..b9d7947ae3 100644 --- a/src/selectionmode/bottombarcontentscontainer.h +++ b/src/selectionmode/bottombarcontentscontainer.h @@ -43,6 +43,9 @@ public: */ explicit BottomBarContentsContainer(KActionCollection *actionCollection, QWidget *parent); + /** + * @param contents The kind of contents that should be contained instead. + */ void resetContents(BottomBar::Contents contents); inline BottomBar::Contents contents() const { @@ -53,9 +56,14 @@ public: return contents() != BottomBar::GeneralContents || m_internalContextMenu; } - void updateForNewWidth(); + /** + * Is called when the BottomBar resizes to let this ContentsContainer know that it should adapt its contents to the new width. + * Adapting is done by showing or hiding labels or buttons. + */ + void adaptToNewBarWidth(int newBarWidth); public Q_SLOTS: + /** Adapts the contents based on the selection in the related view. */ void slotSelectionChanged(const KFileItemList &selection, const QUrl &baseUrl); Q_SIGNALS: @@ -65,8 +73,8 @@ Q_SIGNALS: void error(const QString &errorMessage); /** - * Sometimes the contents see no reason to be visible and request the bar to be hidden instead which emits this signal. - * This can later change e.g. because the user selected items. Then this signal is used to request showing of the bar. + * When it does not make sense to show any specific contents, this signal is emitted and the receiver hides the bar. + * Later it might sense to show it again e.g. because the user selected items. Then this signal is used to request showing of the bar. */ void barVisibilityChangeRequested(bool visible); @@ -90,15 +98,15 @@ private: void addRenameContents(); /** - * Deletes all visible widgets and layouts from the bar. + * Deletes every child layout and child widget of this container. */ void emptyBarContents(); /** - * @returns A vector containing contextual actions for the given \a selection in the \a baseUrl. + * @returns A vector containing contextual actions for the given \a selectedItems in the \a baseUrl. * Cut, Copy, Rename and MoveToTrash are always added. Any further contextual actions depend on - * \a selection and \a baseUrl. \a selection and \a baseUrl can be empty/default constructed if - * no item- or view-specific actions should be added aside from Cut, Copy, Rename, MoveToTrash. + * \a selectedItems and \a baseUrl. + * If there are no \a selectedItems, an empty vector is returned and m_internalContextMenu is deleted. * @param selectedItems The selected items for which contextual actions should be displayed. * @param baseUrl Base URL of the viewport the contextual actions apply to. */ @@ -107,7 +115,7 @@ private: /** * @returns the amount of pixels that can be spared to add more widgets. A negative value might * be returned which signifies that some widgets should be hidden or removed from this bar to - * make sure that this SelectionModeBottomBar won't stretch the width of its parent. + * make sure that this BottomBarContentsContainer can fully fit on the BottomBar. */ int unusedSpace() const; @@ -118,12 +126,12 @@ private: void updateExplanatoryLabelVisibility(); /** - * Changes the text and enabled state of the main action button - * based on the amount of currently selected items and the state of the current m_mainAction. + * Changes the text and enabled state of the main action button based on the amount of currently + * selected items and the state of the current m_mainAction. * The current main action depends on the current barContents. - * @param selection the currently selected fileItems. + * @param selectedItems the currently selected fileItems. */ - void updateMainActionButton(const KFileItemList &selection); + void updateMainActionButton(const KFileItemList &selectedItems); private: /// All the actions that should be available from this bar when in general mode. @@ -141,11 +149,12 @@ private: KActionCollection *m_actionCollection; /// Describes the current contents of the bar. BottomBar::Contents m_contents; - /** The layout all the buttons and labels are added to. - * Do not confuse this with layout() because we do have a QScrollView in between this widget and m_layout. */ + /// The main layout of this ContentsContainer that all the buttons and labels are added to. QHBoxLayout *m_layout; - /// The info label used for some of the BarContents. Is hidden for narrow widths. + /// Caches the totalBarWidth as set in adaptToNewWidth(newBarWidth). */ + int m_barWidth = 0; + /// The info label used for some of the Contents. Is hidden for narrow widths. QPointer m_explanatoryLabel; }; diff --git a/src/selectionmode/topbar.cpp b/src/selectionmode/topbar.cpp index d783c76caa..51467cd99b 100644 --- a/src/selectionmode/topbar.cpp +++ b/src/selectionmode/topbar.cpp @@ -42,7 +42,7 @@ TopBar::TopBar(QWidget *parent) : fillParentLayout->setContentsMargins(0, 0, 0, 0); // Put the contents into a QScrollArea. This prevents increasing the view width - // in case that not enough width for the contents is available. (this trick is also used in selectionmodebottombar.cpp.) + // in case that not enough width for the contents is available. (this trick is also used in bottombar.cpp.) auto scrollArea = new QScrollArea(this); fillParentLayout->addWidget(scrollArea); scrollArea->setFrameShape(QFrame::NoFrame); @@ -111,9 +111,10 @@ void TopBar::setVisible(bool visible, Animated animated) m_heightAnimation->start(QAbstractAnimation::DeleteWhenStopped); } -void TopBar::resizeEvent(QResizeEvent */* resizeEvent */) +void TopBar::resizeEvent(QResizeEvent *resizeEvent) { updateLabelString(); + return QWidget::resizeEvent(resizeEvent); } void TopBar::updateLabelString() diff --git a/src/selectionmode/topbar.h b/src/selectionmode/topbar.h index e0cd34935d..10a65cba07 100644 --- a/src/selectionmode/topbar.h +++ b/src/selectionmode/topbar.h @@ -40,15 +40,17 @@ public: * @see QWidget::setVisible() */ void setVisible(bool visible, Animated animated); - using QWidget::setVisible; // Makes sure that the setVisible() declaration above doesn't hide the one from QWidget. Q_SIGNALS: void leaveSelectionModeRequested(); protected: - void resizeEvent(QResizeEvent */* resizeEvent */) override; + /** Calls updateLabelString() */ + void resizeEvent(QResizeEvent *resizeEvent) override; private: + using QWidget::setVisible; // Makes sure that the setVisible() declaration above doesn't hide the one from QWidget so we can still use it privately. + /** Decides whether the m_fullLabelString or m_shortLabelString should be used based on available width. */ void updateLabelString(); diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index f235efffe2..0566dbf842 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -301,7 +301,6 @@ bool DolphinView::selectionMode() const return m_container->controller()->selectionMode(); } - void DolphinView::setPreviewsShown(bool show) { if (previewsShown() == show) { diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 37af971379..9b0dee62e4 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -112,6 +112,9 @@ public: void setViewMode(Mode mode); Mode viewMode() const; + /** + * Enables or disables a mode for quick and easy selection of items. + */ void setSelectionMode(bool enabled); bool selectionMode() const; diff --git a/src/views/dolphinviewactionhandler.cpp b/src/views/dolphinviewactionhandler.cpp index ef30e91c9f..e6c3fc083a 100644 --- a/src/views/dolphinviewactionhandler.cpp +++ b/src/views/dolphinviewactionhandler.cpp @@ -166,6 +166,7 @@ void DolphinViewActionHandler::createActions(SelectionMode::ActionTextHelper *ac connect(copyPathAction, &QAction::triggered, this, &DolphinViewActionHandler::slotCopyPath); if (actionTextHelper) { + // The "…" at the end make clear that they won't trigger their respective actions directly. actionTextHelper->registerTextWhenNothingIsSelected(trashAction, i18nc("@action:inmenu File", "Move to Trash…")); actionTextHelper->registerTextWhenNothingIsSelected(deleteAction, i18nc("@action:inmenu File", "Delete…")); actionTextHelper->registerTextWhenNothingIsSelected(duplicateAction, i18nc("@action:inmenu File", "Duplicate Here…")); @@ -438,6 +439,7 @@ void DolphinViewActionHandler::slotRename() } else { Q_EMIT actionBeingHandled(); m_currentView->renameSelectedItems(); + // We don't exit selectionMode here because users might want to rename more items. } }