diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/dolphinviewcontainer.cpp | 13 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistcontroller.cpp | 1 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistcontroller.h | 7 | ||||
| -rw-r--r-- | src/statusbar/dolphinstatusbar.cpp | 101 | ||||
| -rw-r--r-- | src/statusbar/dolphinstatusbar.h | 42 | ||||
| -rw-r--r-- | src/views/dolphinview.cpp | 19 | ||||
| -rw-r--r-- | src/views/dolphinview.h | 5 |
7 files changed, 121 insertions, 67 deletions
diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 3db6ca553..968919b63 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -149,10 +149,10 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent) m_statusBar->setZoomLevel(m_view->zoomLevel()); connect(m_view, &DolphinView::urlChanged, m_statusBar, &DolphinStatusBar::setUrl); connect(m_view, &DolphinView::zoomLevelChanged, m_statusBar, &DolphinStatusBar::setZoomLevel); - connect(m_view, &DolphinView::infoMessage, m_statusBar, &DolphinStatusBar::setText); - connect(m_view, &DolphinView::operationCompletedMessage, m_statusBar, &DolphinStatusBar::setText); + connect(m_view, &DolphinView::infoMessage, m_statusBar, &DolphinStatusBar::setTemporaryRichText); + connect(m_view, &DolphinView::operationCompletedMessage, m_statusBar, &DolphinStatusBar::setTemporaryRichText); + connect(m_view, &DolphinView::showTypeAheadFeedback, m_statusBar, &DolphinStatusBar::setTemporaryRichText); connect(m_view, &DolphinView::statusBarTextChanged, m_statusBar, &DolphinStatusBar::setDefaultText); - connect(m_view, &DolphinView::statusBarTextChanged, m_statusBar, &DolphinStatusBar::resetToDefaultText); connect(m_view, &DolphinView::directoryLoadingProgress, m_statusBar, [this](int percent) { m_statusBar->showProgress(i18nc("@info:progress", "Loading folder…"), percent); }); @@ -696,7 +696,7 @@ void DolphinViewContainer::slotDirectoryLoadingCompleted() if (isSearchUrl(url()) && m_view->itemsCount() == 0) { // The dir lister has been completed on a Baloo-URI and no items have been found. Instead // of showing the default status bar information ("0 items") a more helpful information is given: - m_statusBar->setText(i18nc("@info:status", "No items found.")); + m_statusBar->setDefaultText(i18nc("@info:status", "No items found.")); } else { updateStatusBar(); } @@ -720,7 +720,6 @@ void DolphinViewContainer::slotDirectoryLoadingCompleted() void DolphinViewContainer::slotDirectoryLoadingCanceled() { m_statusBar->showProgress(QString(), 100); - m_statusBar->setText(QString()); } void DolphinViewContainer::slotUrlIsFileError(const QUrl &url) @@ -839,9 +838,9 @@ void DolphinViewContainer::slotItemsActivated(const KFileItemList &items) void DolphinViewContainer::showItemInfo(const KFileItem &item) { if (item.isNull()) { - m_statusBar->resetToDefaultText(); + m_statusBar->setHoveredItemText(QString()); } else { - m_statusBar->setText(item.getStatusBarInfo()); + m_statusBar->setHoveredItemText(item.getStatusBarInfo()); } } diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index ef0f9dc14..e87ed3c18 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -547,6 +547,7 @@ void KItemListController::slotChangeCurrentItem(const QString &text, bool search m_view->scrollToItem(index, KItemListView::ViewItemPosition::Beginning); *found = true; } + Q_EMIT typeAheadUsed(text, index >= 0 ? std::make_optional<int>(index) : std::nullopt); } void KItemListController::slotAutoActivationTimeout() diff --git a/src/kitemviews/kitemlistcontroller.h b/src/kitemviews/kitemlistcontroller.h index 48a518610..6379acbd8 100644 --- a/src/kitemviews/kitemlistcontroller.h +++ b/src/kitemviews/kitemlistcontroller.h @@ -190,6 +190,13 @@ Q_SIGNALS: void aboveItemDropEvent(int index, QGraphicsSceneDragDropEvent *event); /** + * Emits the keys the user typed for searching so they can be displayed back to the user. + * @param typedString A string of basic interpretation of key presses e.g. "qwert". + * @param foundIndex The index of the item that was marked as current in response to this search. + */ + void typeAheadUsed(const QString &typedString, std::optional<int> foundIndex); + + /** * Is emitted if the Escape key is pressed. */ void escapePressed(); diff --git a/src/statusbar/dolphinstatusbar.cpp b/src/statusbar/dolphinstatusbar.cpp index 5d7e8e674..4b2bb6f0f 100644 --- a/src/statusbar/dolphinstatusbar.cpp +++ b/src/statusbar/dolphinstatusbar.cpp @@ -24,17 +24,24 @@ #include <QProgressBar> #include <QSlider> #include <QStyleOption> +#include <QTextDocumentFragment> #include <QTimer> #include <QToolButton> +#include <chrono> + +using namespace std::chrono_literals; + namespace { -const int UpdateDelay = 50; +constexpr std::chrono::milliseconds minimumTimeBetweenTextChanges = 50ms; +constexpr std::chrono::seconds temporaryRichTextTimeout = 1s; } DolphinStatusBar::DolphinStatusBar(QWidget *parent) : AnimatedHeightWidget(parent) - , m_text() + , m_temporaryRichText() + , m_hoveredItemText() , m_defaultText() , m_label(nullptr) , m_zoomLabel(nullptr) @@ -44,8 +51,8 @@ DolphinStatusBar::DolphinStatusBar(QWidget *parent) , m_stopButton(nullptr) , m_progress(100) , m_showProgressBarTimer(nullptr) - , m_delayUpdateTimer(nullptr) - , m_textTimestamp() + , m_clearTemporaryRichTextTimer(nullptr) + , m_updateLabelTextTimer(nullptr) { setProperty("_breeze_statusbar_separator", true); @@ -53,7 +60,7 @@ DolphinStatusBar::DolphinStatusBar(QWidget *parent) contentsContainer->setContentsMargins(0, 0, 0, 0); // Initialize text label - m_label = new KSqueezedTextLabel(m_text, contentsContainer); + m_label = new KSqueezedTextLabel{contentsContainer}; m_label->setTextFormat(Qt::PlainText); m_label->setTextInteractionFlags(Qt::TextBrowserInteraction | Qt::TextSelectableByKeyboard); // for accessibility but also to allow copy-pasting this text. @@ -101,11 +108,16 @@ DolphinStatusBar::DolphinStatusBar(QWidget *parent) m_showProgressBarTimer->setSingleShot(true); connect(m_showProgressBarTimer, &QTimer::timeout, this, &DolphinStatusBar::updateProgressInfo); - // initialize text updater delay timer - m_delayUpdateTimer = new QTimer(this); - m_delayUpdateTimer->setInterval(UpdateDelay); - m_delayUpdateTimer->setSingleShot(true); - connect(m_delayUpdateTimer, &QTimer::timeout, this, &DolphinStatusBar::updateLabelText); + // initialize timers for delayed replacing which text is shown + m_clearTemporaryRichTextTimer = new QTimer(this); + m_clearTemporaryRichTextTimer->setInterval(temporaryRichTextTimeout); + m_clearTemporaryRichTextTimer->setSingleShot(true); + connect(m_clearTemporaryRichTextTimer, &QTimer::timeout, this, &DolphinStatusBar::clearTemporaryRichText); + + m_updateLabelTextTimer = new QTimer(this); + m_updateLabelTextTimer->setInterval(minimumTimeBetweenTextChanges); + m_updateLabelTextTimer->setSingleShot(true); + connect(m_updateLabelTextTimer, &QTimer::timeout, this, &DolphinStatusBar::updateLabelText); // Initialize top layout and size policies const int fontHeight = QFontMetrics(m_label->font()).height(); @@ -153,24 +165,6 @@ DolphinStatusBar::DolphinStatusBar(QWidget *parent) DolphinStatusBar::~DolphinStatusBar() = default; -void DolphinStatusBar::setText(const QString &text) -{ - if (m_text == text) { - return; - } - - m_textTimestamp = QTime::currentTime(); - - m_text = text; - // will update status bar text in 50ms - m_delayUpdateTimer->start(); -} - -QString DolphinStatusBar::text() const -{ - return m_text; -} - void DolphinStatusBar::showProgress(const QString ¤tlyRunningTaskTitle, int progressPercent, CancelLoading cancelLoading) { m_cancelLoading = cancelLoading; @@ -215,27 +209,28 @@ int DolphinStatusBar::progress() const return m_progress; } -void DolphinStatusBar::resetToDefaultText() +void DolphinStatusBar::setTemporaryRichText(const QString &temporaryRichText) { - m_text.clear(); - - QTime currentTime; - if (currentTime.msecsTo(m_textTimestamp) < UpdateDelay) { - m_delayUpdateTimer->start(); - } else { - updateLabelText(); + if (m_temporaryRichText == temporaryRichText) { + return; } + + m_temporaryRichText = temporaryRichText; + updateLabelText(); // Show the text instantly because we only show it temporarily anyway. + m_clearTemporaryRichTextTimer->start(); } -void DolphinStatusBar::setDefaultText(const QString &text) +void DolphinStatusBar::setHoveredItemText(const QString &hoveredItemText) { - m_defaultText = text; - updateLabelText(); + m_hoveredItemText = hoveredItemText; + m_updateLabelTextTimer->start(); } -QString DolphinStatusBar::defaultText() const +void DolphinStatusBar::setDefaultText(const QString &text) { - return m_defaultText; + m_defaultText = text; + m_hoveredItemText.clear(); // We want to show the new default text instead of whatever was hovered. + m_updateLabelTextTimer->start(); } void DolphinStatusBar::setUrl(const QUrl &url) @@ -280,7 +275,9 @@ void DolphinStatusBar::updateWidthToContent() QStyleOptionSlider opt; opt.initFrom(this); opt.orientation = Qt::Vertical; - const QSize labelSize = QFontMetrics(font()).size(Qt::TextSingleLine, m_label->fullText()); + const QSize labelSize = m_label->textFormat() == Qt::PlainText + ? QFontMetrics(font()).size(Qt::TextSingleLine, m_label->fullText()) + : QFontMetrics(font()).size(Qt::TextSingleLine, QTextDocumentFragment::fromHtml(m_label->fullText()).toPlainText()); // Make sure minimum height takes clipping into account. setMinimumHeight(m_label->height() + clippingAmount()); const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent, &opt, this); @@ -389,10 +386,26 @@ void DolphinStatusBar::updateProgressInfo() updateWidthToContent(); } +void DolphinStatusBar::clearTemporaryRichText() +{ + if (m_clearTemporaryRichTextTimer->isActive()) { + return; + } + m_temporaryRichText.clear(); + m_updateLabelTextTimer->start(); +} + void DolphinStatusBar::updateLabelText() { - const QString text = m_text.isEmpty() ? m_defaultText : m_text; - m_label->setText(text); + if (!m_temporaryRichText.isEmpty()) { + m_label->setTextFormat(Qt::RichText); + m_label->setTextElideMode(Qt::ElideNone); + m_label->setText(m_temporaryRichText); + } else { + m_label->setTextFormat(Qt::PlainText); + m_label->setTextElideMode(Qt::ElideMiddle); + m_label->setText(m_hoveredItemText.isEmpty() ? m_defaultText : m_hoveredItemText); + } updateWidthToContent(); } diff --git a/src/statusbar/dolphinstatusbar.h b/src/statusbar/dolphinstatusbar.h index b4ddcd95e..232a4ba07 100644 --- a/src/statusbar/dolphinstatusbar.h +++ b/src/statusbar/dolphinstatusbar.h @@ -11,8 +11,6 @@ #include <KMessageWidget> -#include <QTime> - class QUrl; class StatusBarSpaceInfo; class QLabel; @@ -37,8 +35,6 @@ public: explicit DolphinStatusBar(QWidget *parent); ~DolphinStatusBar() override; - QString text() const; - enum class CancelLoading { Allowed, Disallowed @@ -62,18 +58,21 @@ public: int progress() const; /** - * Replaces the text set by setText() by the text that - * has been set by setDefaultText(). DolphinStatusBar::text() - * will return an empty string after the reset has been done. + * Sets a text that is shown with priority as a Qt::RichText for a short amount of time. */ - void resetToDefaultText(); - + void setTemporaryRichText(const QString &temporaryRichText); + /** + * Sets a text describing the hovered item. This text is immediately shown if no m_temporaryRichText is currently shown. + * When no item is hovered, call this method with an empty string so the m_defaultText is shown. + * @see setTemporaryRichText() + * @see setDefaultText() + */ + void setHoveredItemText(const QString &hoveredItemText); /** - * Sets the default text, which is shown if the status bar - * is rest by DolphinStatusBar::resetToDefaultText(). + * Sets the default text. This text is immediately shown if no m_temporaryRichText is currently shown. + * @see setTemporaryRichText() */ void setDefaultText(const QString &text); - QString defaultText() const; QUrl url() const; int zoomLevel() const; @@ -105,7 +104,6 @@ public: int clippingAmount() const; public Q_SLOTS: - void setText(const QString &text); void setUrl(const QUrl &url); void setZoomLevel(int zoomLevel); @@ -147,6 +145,12 @@ private Q_SLOTS: void updateProgressInfo(); /** + * Replaces the text set by setTemporaryRichText() by the text set by setHoveredItemText() or setDefaultText(). + * Is only called when m_clearTemporaryRichTextTimer times out. + */ + void clearTemporaryRichText(); + + /** * Updates the text for m_label and does an eliding in * case if the text does not fit into the available width. */ @@ -173,7 +177,11 @@ private: int preferredHeight() const override; private: - QString m_text; + /** @see setTemporaryRichText() */ + QString m_temporaryRichText; + /** @see setHoveredItemText() */ + QString m_hoveredItemText; + /** @see setDefaultText() */ QString m_defaultText; KSqueezedTextLabel *m_label; QLabel *m_zoomLabel; @@ -188,8 +196,10 @@ private: int m_progress; QTimer *m_showProgressBarTimer; - QTimer *m_delayUpdateTimer; - QTime m_textTimestamp; + /** Clears the temporary rich text from the status bar and shows a non-temporary text instead. */ + QTimer *m_clearTemporaryRichTextTimer; + /** Very frequent updates to the status bar text look ugly. Most updates go through this timer to avoid this. */ + QTimer *m_updateLabelTextTimer; QHBoxLayout *m_topLayout; }; diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 794223861..3c973618c 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -130,6 +130,25 @@ DolphinView::DolphinView(const QUrl &url, QWidget *parent) KItemListController *controller = new KItemListController(m_model, m_view, this); controller->setAutoActivationEnabled(GeneralSettings::autoExpandFolders()); connect(controller, &KItemListController::doubleClickViewBackground, this, &DolphinView::doubleClickViewBackground); + connect(controller, &KItemListController::typeAheadUsed, this, [this](const QString &typedString, std::optional<int> foundIndex) { + if (foundIndex.has_value()) { + const KFileItem item = m_model->fileItem(foundIndex.value()); + if (item.isNull()) { + return; + } + const KColorScheme colorScheme = KColorScheme(QPalette::Normal, KColorScheme::Tooltip); + const QColor autoCompleteTextColor = colorScheme.foreground(KColorScheme::InactiveText).color(); + + Q_EMIT showTypeAheadFeedback(QStringLiteral("%1<font color=\"%2\">%3</font>") + .arg(typedString.toHtmlEscaped()) + .arg(autoCompleteTextColor.name()) + .arg(item.name().toHtmlEscaped().mid(typedString.size()))); + } else { + const KColorScheme colorScheme = KColorScheme(QPalette::Normal, KColorScheme::Tooltip); + const QColor noMatchTextColor = colorScheme.foreground(KColorScheme::NegativeText).color(); + Q_EMIT showTypeAheadFeedback(QStringLiteral("<font color=\"%1\">%2</font>").arg(noMatchTextColor.name()).arg(typedString.toHtmlEscaped())); + } + }); // The EnlargeSmallPreviews setting can only be changed after the model // has been set in the view by KItemListController. diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 6aa5b595d..9b068f92e 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -635,6 +635,11 @@ Q_SIGNALS: void operationCompletedMessage(const QString &msg); /** + * Is emitted so the \a typeAheadFeedback is displayed to the user. Beware: \a typeAheadFeedback is HTML-escaped rich text. + */ + void showTypeAheadFeedback(const QString &typeAheadFeedback); + + /** * Is emitted after DolphinView::setUrl() has been invoked and * the current directory is loaded. If this signal is emitted, * it is assured that the view contains already the correct root |
