2 * SPDX-FileCopyrightText: 2006-2012 Peter Penz <peter.penz19@gmail.com>
4 * SPDX-License-Identifier: GPL-2.0-or-later
7 #include "dolphinstatusbar.h"
9 #include "dolphin_generalsettings.h"
10 #include "statusbarspaceinfo.h"
11 #include "views/dolphinview.h"
12 #include "views/zoomlevelinfo.h"
14 #include <KLocalizedString>
15 #include <KSqueezedTextLabel>
17 #include <QApplication>
18 #include <QHBoxLayout>
23 #include <QPainterPath>
24 #include <QProgressBar>
26 #include <QStyleOption>
28 #include <QToolButton>
32 const int UpdateDelay
= 50;
35 DolphinStatusBar::DolphinStatusBar(QWidget
*parent
)
36 : AnimatedHeightWidget(parent
)
40 , m_zoomLabel(nullptr)
41 , m_spaceInfo(nullptr)
42 , m_zoomSlider(nullptr)
43 , m_progressBar(nullptr)
44 , m_stopButton(nullptr)
46 , m_showProgressBarTimer(nullptr)
47 , m_delayUpdateTimer(nullptr)
50 setProperty("_breeze_statusbar_separator", true);
52 QWidget
*contentsContainer
= prepareContentsContainer();
54 // Initialize text label
55 m_label
= new KSqueezedTextLabel(m_text
, contentsContainer
);
56 m_label
->setTextFormat(Qt::PlainText
);
57 m_label
->setTextInteractionFlags(Qt::TextBrowserInteraction
| Qt::TextSelectableByKeyboard
); // for accessibility but also to allow copy-pasting this text.
59 // Initialize zoom slider's explanatory label
60 m_zoomLabel
= new KSqueezedTextLabel(i18nc("Used as a noun, i.e. 'Here is the zoom level:'", "Zoom:"), contentsContainer
);
62 // Initialize zoom widget
63 m_zoomSlider
= new QSlider(Qt::Horizontal
, contentsContainer
);
64 m_zoomSlider
->setAccessibleName(i18n("Zoom"));
65 m_zoomSlider
->setAccessibleDescription(i18nc("Description for zoom-slider (accessibility)", "Sets the size of the file icons."));
66 m_zoomSlider
->setPageStep(1);
67 m_zoomSlider
->setRange(ZoomLevelInfo::minimumLevel(), ZoomLevelInfo::maximumLevel());
69 connect(m_zoomSlider
, &QSlider::valueChanged
, this, &DolphinStatusBar::zoomLevelChanged
);
70 connect(m_zoomSlider
, &QSlider::valueChanged
, this, &DolphinStatusBar::updateZoomSliderToolTip
);
71 connect(m_zoomSlider
, &QSlider::sliderMoved
, this, &DolphinStatusBar::showZoomSliderToolTip
);
73 // Initialize space information
74 m_spaceInfo
= new StatusBarSpaceInfo(contentsContainer
);
75 connect(m_spaceInfo
, &StatusBarSpaceInfo::showMessage
, this, &DolphinStatusBar::showMessage
);
77 &StatusBarSpaceInfo::showInstallationProgress
,
79 [this](const QString
¤tlyRunningTaskTitle
, int installationProgressPercent
) {
80 showProgress(currentlyRunningTaskTitle
, installationProgressPercent
, CancelLoading::Disallowed
);
83 // Initialize progress information
84 m_stopButton
= new QToolButton(contentsContainer
);
85 m_stopButton
->setIcon(QIcon::fromTheme(QStringLiteral("process-stop")));
86 m_stopButton
->setAccessibleName(i18n("Stop"));
87 m_stopButton
->setAutoRaise(true);
88 m_stopButton
->setToolTip(i18nc("@tooltip", "Stop loading"));
90 connect(m_stopButton
, &QToolButton::clicked
, this, &DolphinStatusBar::stopPressed
);
92 m_progressTextLabel
= new QLabel(contentsContainer
);
93 m_progressTextLabel
->hide();
95 m_progressBar
= new QProgressBar(contentsContainer
);
96 m_progressBar
->hide();
98 m_showProgressBarTimer
= new QTimer(this);
99 m_showProgressBarTimer
->setInterval(500);
100 m_showProgressBarTimer
->setSingleShot(true);
101 connect(m_showProgressBarTimer
, &QTimer::timeout
, this, &DolphinStatusBar::updateProgressInfo
);
103 // initialize text updater delay timer
104 m_delayUpdateTimer
= new QTimer(this);
105 m_delayUpdateTimer
->setInterval(UpdateDelay
);
106 m_delayUpdateTimer
->setSingleShot(true);
107 connect(m_delayUpdateTimer
, &QTimer::timeout
, this, &DolphinStatusBar::updateLabelText
);
109 // Initialize top layout and size policies
110 const int fontHeight
= QFontMetrics(m_label
->font()).height();
111 const int zoomSliderHeight
= m_zoomSlider
->minimumSizeHint().height();
112 const int buttonHeight
= m_stopButton
->height();
113 const int contentHeight
= qMax(qMax(fontHeight
, zoomSliderHeight
), buttonHeight
);
115 QFontMetrics
fontMetrics(m_label
->font());
117 m_label
->setFixedHeight(contentHeight
);
118 m_label
->setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Fixed
);
120 m_zoomSlider
->setMaximumWidth(fontMetrics
.averageCharWidth() * 15);
122 m_spaceInfo
->setFixedHeight(contentHeight
);
123 m_spaceInfo
->setMaximumWidth(fontMetrics
.averageCharWidth() * 25);
124 m_spaceInfo
->setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Fixed
);
126 m_progressBar
->setFixedHeight(zoomSliderHeight
);
127 m_progressBar
->setMaximumWidth(fontMetrics
.averageCharWidth() * 20);
129 m_topLayout
= new QHBoxLayout(contentsContainer
);
130 updateContentsMargins();
131 m_topLayout
->setSpacing(4);
132 m_topLayout
->addWidget(m_label
, 1);
133 m_topLayout
->addWidget(m_zoomLabel
);
134 m_topLayout
->addWidget(m_zoomSlider
, 1);
135 m_topLayout
->addWidget(m_spaceInfo
, 1);
136 m_topLayout
->addWidget(m_stopButton
);
137 m_topLayout
->addWidget(m_progressTextLabel
);
138 m_topLayout
->addWidget(m_progressBar
);
141 setWhatsThis(xi18nc("@info:whatsthis Statusbar",
143 "the <emphasis>Statusbar</emphasis>. It contains three elements "
144 "by default (left to right):<list><item>A <emphasis>text field"
145 "</emphasis> that displays the size of selected items. If only "
146 "one item is selected the name and type is shown as well.</item>"
147 "<item>A <emphasis>zoom slider</emphasis> that allows you "
148 "to adjust the size of the icons in the view.</item>"
149 "<item><emphasis>Space information</emphasis> about the "
150 "current storage device.</item></list></para>"));
153 DolphinStatusBar::~DolphinStatusBar()
157 void DolphinStatusBar::setText(const QString
&text
)
159 if (m_text
== text
) {
163 m_textTimestamp
= QTime::currentTime();
166 // will update status bar text in 50ms
167 m_delayUpdateTimer
->start();
170 QString
DolphinStatusBar::text() const
175 void DolphinStatusBar::showProgress(const QString
¤tlyRunningTaskTitle
, int progressPercent
, CancelLoading cancelLoading
)
177 m_cancelLoading
= cancelLoading
;
179 // Show a busy indicator if a value < 0 is provided:
180 m_progressBar
->setMaximum((progressPercent
< 0) ? 0 : 100);
182 progressPercent
= qBound(0, progressPercent
, 100);
183 if (!m_progressBar
->isVisible()) {
184 // Show the progress bar delayed: In the case if 100 % are reached within
185 // a short time, no progress bar will be shown at all.
186 if (!m_showProgressBarTimer
->isActive()) {
187 m_showProgressBarTimer
->start();
189 // The timer is already running. Should we restart it or keep it running?
190 if (m_progressTextLabel
->text() != currentlyRunningTaskTitle
|| (progressPercent
< 100 && progressPercent
< m_progress
)) {
191 m_showProgressBarTimer
->start();
195 m_progress
= progressPercent
;
197 m_progressBar
->setValue(m_progress
);
198 if (progressPercent
== 100) {
199 // The end of the progress has been reached. Assure that the progress bar
200 // gets hidden and the extensions widgets get visible again.
201 m_showProgressBarTimer
->stop();
202 updateProgressInfo();
205 m_progressTextLabel
->setText(currentlyRunningTaskTitle
);
206 updateWidthToContent();
209 QString
DolphinStatusBar::progressText() const
211 return m_progressTextLabel
->text();
214 int DolphinStatusBar::progress() const
219 void DolphinStatusBar::resetToDefaultText()
224 if (currentTime
.msecsTo(m_textTimestamp
) < UpdateDelay
) {
225 m_delayUpdateTimer
->start();
231 void DolphinStatusBar::setDefaultText(const QString
&text
)
233 m_defaultText
= text
;
237 QString
DolphinStatusBar::defaultText() const
239 return m_defaultText
;
242 void DolphinStatusBar::setUrl(const QUrl
&url
)
244 if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth
&& m_spaceInfo
&& m_spaceInfo
->url() != url
) {
245 m_spaceInfo
->setUrl(url
);
250 QUrl
DolphinStatusBar::url() const
252 return m_spaceInfo
->url();
255 void DolphinStatusBar::setZoomLevel(int zoomLevel
)
257 if (zoomLevel
!= m_zoomSlider
->value()) {
258 m_zoomSlider
->setValue(zoomLevel
);
262 int DolphinStatusBar::zoomLevel() const
264 return m_zoomSlider
->value();
267 void DolphinStatusBar::readSettings()
270 setExtensionsVisible(true);
273 void DolphinStatusBar::updateSpaceInfo()
275 m_spaceInfo
->update();
278 void DolphinStatusBar::updateWidthToContent()
280 if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small
) {
281 QStyleOptionSlider opt
;
283 opt
.orientation
= Qt::Vertical
;
284 const QSize labelSize
= QFontMetrics(font()).size(Qt::TextSingleLine
, m_label
->fullText());
285 // Make sure minimum height takes clipping into account.
286 setMinimumHeight(m_label
->height() + clippingAmount());
287 const int scrollbarWidth
= style()->pixelMetric(QStyle::PM_ScrollBarExtent
, &opt
, this);
288 // Make sure maximumViewWidth does not go below 0.
289 const int maximumViewWidth
= qMax(0, parentWidget()->width() - scrollbarWidth
);
290 if (m_stopButton
->isVisible() || m_progressTextLabel
->isVisible() || m_progressBar
->isVisible()) {
291 // Use maximum width when interactable elements are shown, to keep them
292 // from "jumping around" when user tries to interact with them.
293 setFixedWidth(maximumViewWidth
);
295 const int contentWidth
= labelSize
.width() + 15;
296 setFixedWidth(qMin(contentWidth
, maximumViewWidth
));
298 Q_EMIT
widthUpdated();
301 setFixedWidth(QWIDGETSIZE_MAX
);
302 Q_EMIT
widthUpdated();
306 int DolphinStatusBar::clippingAmount() const
310 // Add 2 for extra padding due to how QRect coordinates work.
311 const int val
= 2 + style()->pixelMetric(QStyle::PM_SplitterWidth
, &opt
, this) * 2;
315 void DolphinStatusBar::updateMode()
317 switch (GeneralSettings::showStatusBar()) {
318 case GeneralSettings::EnumShowStatusBar::Small
:
320 m_spaceInfo
->setShown(false);
321 m_zoomSlider
->setVisible(false);
322 m_zoomLabel
->setVisible(false);
323 setVisible(true, WithAnimation
);
325 case GeneralSettings::EnumShowStatusBar::FullWidth
:
327 m_spaceInfo
->setShown(true);
328 setVisible(true, WithAnimation
);
330 case GeneralSettings::EnumShowStatusBar::Disabled
:
332 setVisible(false, WithoutAnimation
);
335 Q_EMIT
modeUpdated();
336 updateWidthToContent();
339 void DolphinStatusBar::contextMenuEvent(QContextMenuEvent
*event
)
343 // Do not show the context menu on small statusbar.
344 if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small
) {
350 QAction
*showZoomSliderAction
= menu
.addAction(i18nc("@action:inmenu", "Show Zoom Slider"));
351 showZoomSliderAction
->setCheckable(true);
352 showZoomSliderAction
->setChecked(GeneralSettings::showZoomSlider());
354 const QAction
*action
= menu
.exec(event
->reason() == QContextMenuEvent::Reason::Mouse
? QCursor::pos() : mapToGlobal(QPoint(width() / 2, height() / 2)));
355 if (action
== showZoomSliderAction
) {
356 const bool visible
= showZoomSliderAction
->isChecked();
357 GeneralSettings::setShowZoomSlider(visible
);
358 m_zoomSlider
->setVisible(visible
);
359 m_zoomLabel
->setVisible(visible
);
361 updateContentsMargins();
364 void DolphinStatusBar::showZoomSliderToolTip(int zoomLevel
)
366 updateZoomSliderToolTip(zoomLevel
);
368 QPoint global
= m_zoomSlider
->rect().topLeft();
369 global
.ry() += m_zoomSlider
->height() / 2;
370 QHelpEvent
toolTipEvent(QEvent::ToolTip
, QPoint(0, 0), m_zoomSlider
->mapToGlobal(global
));
371 QApplication::sendEvent(m_zoomSlider
, &toolTipEvent
);
374 void DolphinStatusBar::updateProgressInfo()
376 if (m_progress
< 100) {
377 // Show the progress information and hide the extensions
378 m_stopButton
->setVisible(m_cancelLoading
== CancelLoading::Allowed
);
379 m_progressTextLabel
->show();
380 m_progressBar
->show();
381 setExtensionsVisible(false);
383 // Hide the progress information and show the extensions
384 m_stopButton
->hide();
385 m_progressTextLabel
->hide();
386 m_progressBar
->hide();
387 setExtensionsVisible(true);
389 updateWidthToContent();
392 void DolphinStatusBar::updateLabelText()
394 const QString text
= m_text
.isEmpty() ? m_defaultText
: m_text
;
395 m_label
->setText(text
);
396 updateWidthToContent();
399 void DolphinStatusBar::updateZoomSliderToolTip(int zoomLevel
)
401 const int size
= ZoomLevelInfo::iconSizeForZoomLevel(zoomLevel
);
402 m_zoomSlider
->setToolTip(i18ncp("@info:tooltip", "Size: 1 pixel", "Size: %1 pixels", size
));
405 void DolphinStatusBar::setExtensionsVisible(bool visible
)
407 bool showZoomSlider
= visible
;
409 showZoomSlider
= GeneralSettings::showZoomSlider() && GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth
;
412 m_zoomSlider
->setVisible(showZoomSlider
);
413 m_zoomLabel
->setVisible(showZoomSlider
);
414 updateContentsMargins();
417 void DolphinStatusBar::updateContentsMargins()
419 if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth
) {
420 // We reduce the outside margin for the flat button so it visually has the same margin as the status bar text label on the other end of the bar.
421 m_topLayout
->setContentsMargins(6, 0, 2, 0);
423 // Add extra margins to toplayout to avoid clipping too early.
424 m_topLayout
->setContentsMargins(clippingAmount() * 2, 0, clippingAmount(), clippingAmount());
426 setContentsMargins(0, 0, 0, 0);
429 void DolphinStatusBar::paintEvent(QPaintEvent
*paintEvent
)
435 // Draw statusbar only if there is text.
436 if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small
) {
437 if (m_label
&& !m_label
->fullText().isEmpty()) {
438 opt
.state
= QStyle::State_Sunken
;
440 // Clip the left and bottom border off.
442 if (layoutDirection() == Qt::RightToLeft
) {
443 clipRect
= QRect(opt
.rect
.topLeft(), opt
.rect
.bottomRight()).adjusted(0, 0, -clippingAmount(), -clippingAmount());
445 clipRect
= QRect(opt
.rect
.topLeft(), opt
.rect
.bottomRight()).adjusted(clippingAmount(), 0, 0, -clippingAmount());
447 path
.addRect(clipRect
);
449 opt
.palette
.setColor(QPalette::Base
, palette().window().color());
450 style()->drawPrimitive(QStyle::PE_Frame
, &opt
, &p
, this);
453 // Draw regular statusbar.
455 style()->drawPrimitive(QStyle::PE_PanelStatusBar
, &opt
, &p
, this);
459 int DolphinStatusBar::preferredHeight() const
461 return m_spaceInfo
->height();
464 #include "moc_dolphinstatusbar.cpp"