]> cloud.milkyroute.net Git - dolphin.git/blob - src/statusbar/statusbarmessagelabel.cpp
Add progress-text label to the layout
[dolphin.git] / src / statusbar / statusbarmessagelabel.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz *
3 * peter.penz@gmx.at *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include "statusbarmessagelabel.h"
22
23 #include <kcolorscheme.h>
24 #include <kiconloader.h>
25 #include <kicon.h>
26 #include <klocale.h>
27
28 #include <QFontMetrics>
29 #include <QPainter>
30 #include <QKeyEvent>
31 #include <QPixmap>
32 #include <QToolButton>
33 #include <QTimer>
34
35 StatusBarMessageLabel::StatusBarMessageLabel(QWidget* parent) :
36 QWidget(parent),
37 m_type(DolphinStatusBar::Default),
38 m_state(Default),
39 m_illumination(0),
40 m_minTextHeight(-1),
41 m_timer(0),
42 m_closeButton(0)
43 {
44 setMinimumHeight(KIconLoader::SizeSmall);
45
46 m_timer = new QTimer(this);
47 connect(m_timer, SIGNAL(timeout()),
48 this, SLOT(timerDone()));
49
50 m_closeButton = new QToolButton(this);
51 m_closeButton->setAutoRaise(true);
52 m_closeButton->setIcon(KIcon("dialog-close"));
53 m_closeButton->setToolTip(i18nc("@info", "Close"));
54 m_closeButton->hide();
55 connect(m_closeButton, SIGNAL(clicked()),
56 this, SLOT(closeErrorMessage()));
57 }
58
59 StatusBarMessageLabel::~StatusBarMessageLabel()
60 {
61 }
62
63 void StatusBarMessageLabel::setMessage(const QString& text,
64 DolphinStatusBar::Type type)
65 {
66 if ((text == m_text) && (type == m_type)) {
67 return;
68 }
69
70 if (m_type == DolphinStatusBar::Error) {
71 if (type == DolphinStatusBar::Error) {
72 m_pendingMessages.insert(0, m_text);
73 } else if ((m_state != Default) || !m_pendingMessages.isEmpty()) {
74 // a non-error message should not be shown, as there
75 // are other pending error messages in the queue
76 return;
77 }
78 }
79
80 m_text = text;
81 m_type = type;
82
83 m_timer->stop();
84 m_illumination = 0;
85 m_state = Default;
86
87 const char* iconName = 0;
88 QPixmap pixmap;
89 switch (type) {
90 case DolphinStatusBar::OperationCompleted:
91 iconName = "dialog-ok";
92 // "ok" icon should probably be "dialog-success", but we don't have that icon in KDE 4.0
93 m_closeButton->hide();
94 break;
95
96 case DolphinStatusBar::Information:
97 iconName = "dialog-information";
98 m_closeButton->hide();
99 break;
100
101 case DolphinStatusBar::Error:
102 m_timer->start(100);
103 m_state = Illuminate;
104
105 updateCloseButtonPosition();
106 m_closeButton->show();
107 break;
108
109 case DolphinStatusBar::Default:
110 default:
111 m_closeButton->hide();
112 break;
113 }
114
115 m_pixmap = (iconName == 0) ? QPixmap() : SmallIcon(iconName);
116 QTimer::singleShot(GeometryTimeout, this, SLOT(assureVisibleText()));
117 update();
118 }
119
120 DolphinStatusBar::Type StatusBarMessageLabel::type() const
121 {
122 return m_type;
123 }
124
125 QString StatusBarMessageLabel::text() const
126 {
127 return m_text;
128 }
129
130 void StatusBarMessageLabel::setDefaultText(const QString& text)
131 {
132 m_defaultText = text;
133 }
134
135 QString StatusBarMessageLabel::defaultText() const
136 {
137 return m_defaultText;
138 }
139
140 void StatusBarMessageLabel::setMinimumTextHeight(int min)
141 {
142 if (min != m_minTextHeight) {
143 m_minTextHeight = min;
144 setMinimumHeight(min);
145 if (m_closeButton->height() > min) {
146 m_closeButton->setFixedHeight(min);
147 }
148 }
149 }
150
151 int StatusBarMessageLabel::minimumTextHeight() const
152 {
153 return m_minTextHeight;
154 }
155
156 int StatusBarMessageLabel::widthGap() const
157 {
158 QFontMetrics fontMetrics(font());
159 const int defaultGap = 10;
160 return fontMetrics.width(m_text) - availableTextWidth() + defaultGap;
161 }
162
163 void StatusBarMessageLabel::paintEvent(QPaintEvent* /* event */)
164 {
165 QPainter painter(this);
166
167 if (m_illumination > 0) {
168 // at this point, a: we are a second label being drawn over the already
169 // painted status area, so we can be translucent, and b: our palette's
170 // window color (bg only) seems to be wrong (always black)
171 KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window);
172 QColor backgroundColor = scheme.background(KColorScheme::NegativeBackground).color();
173 backgroundColor.setAlpha(qMin(255, m_illumination * 2));
174 painter.setBrush(backgroundColor);
175 painter.setPen(Qt::NoPen);
176 painter.drawRect(QRect(0, 0, width(), height()));
177 }
178
179 // draw pixmap
180 int x = BorderGap;
181 const int y = (m_minTextHeight - m_pixmap.height()) / 2;
182
183 if (!m_pixmap.isNull()) {
184 painter.drawPixmap(x, y, m_pixmap);
185 x += m_pixmap.width() + BorderGap;
186 }
187
188 // draw text
189 painter.setPen(palette().windowText().color());
190 int flags = Qt::AlignVCenter;
191 if (height() > m_minTextHeight) {
192 flags = flags | Qt::TextWordWrap;
193 }
194 painter.drawText(QRect(x, 0, availableTextWidth(), height()), flags, m_text);
195 painter.end();
196 }
197
198 void StatusBarMessageLabel::resizeEvent(QResizeEvent* event)
199 {
200 QWidget::resizeEvent(event);
201 updateCloseButtonPosition();
202 QTimer::singleShot(GeometryTimeout, this, SLOT(assureVisibleText()));
203 }
204
205 void StatusBarMessageLabel::timerDone()
206 {
207 switch (m_state) {
208 case Illuminate: {
209 // increase the illumination
210 const int illumination_max = 128;
211 if (m_illumination < illumination_max) {
212 m_illumination += 32;
213 if (m_illumination > illumination_max) {
214 m_illumination = illumination_max;
215 }
216 update();
217 } else {
218 m_state = Illuminated;
219 m_timer->start(5000);
220 }
221 break;
222 }
223
224 case Illuminated: {
225 // start desaturation
226 m_state = Desaturate;
227 m_timer->start(100);
228 break;
229 }
230
231 case Desaturate: {
232 // desaturate
233 if (m_illumination > 0) {
234 m_illumination -= 5;
235 update();
236 } else {
237 m_state = Default;
238 m_timer->stop();
239 }
240 break;
241 }
242
243 default:
244 break;
245 }
246 }
247
248 void StatusBarMessageLabel::assureVisibleText()
249 {
250 if (m_text.isEmpty()) {
251 return;
252 }
253
254 int requiredHeight = m_minTextHeight;
255 if (m_type != DolphinStatusBar::Default) {
256 // Calculate the required height of the widget thats
257 // needed for having a fully visible text. Note that for the default
258 // statusbar type (e. g. hover information) increasing the text height
259 // is not wanted, as this might rearrange the layout of items.
260
261 QFontMetrics fontMetrics(font());
262 const QRect bounds(fontMetrics.boundingRect(0, 0, availableTextWidth(), height(),
263 Qt::AlignVCenter | Qt::TextWordWrap, m_text));
264 requiredHeight = bounds.height();
265 if (requiredHeight < m_minTextHeight) {
266 requiredHeight = m_minTextHeight;
267 }
268 }
269
270 // Increase/decrease the current height of the widget to the
271 // required height. The increasing/decreasing is done in several
272 // steps to have an animation if the height is modified
273 // (see StatusBarMessageLabel::resizeEvent())
274 const int gap = m_minTextHeight / 2;
275 int minHeight = minimumHeight();
276 if (minHeight < requiredHeight) {
277 minHeight += gap;
278 if (minHeight > requiredHeight) {
279 minHeight = requiredHeight;
280 }
281 setMinimumHeight(minHeight);
282 updateGeometry();
283 } else if (minHeight > requiredHeight) {
284 minHeight -= gap;
285 if (minHeight < requiredHeight) {
286 minHeight = requiredHeight;
287 }
288 setMinimumHeight(minHeight);
289 updateGeometry();
290 }
291
292 updateCloseButtonPosition();
293 }
294
295 int StatusBarMessageLabel::availableTextWidth() const
296 {
297 const int buttonWidth = (m_type == DolphinStatusBar::Error) ?
298 m_closeButton->width() + BorderGap : 0;
299 return width() - m_pixmap.width() - (BorderGap * 4) - buttonWidth;
300 }
301
302 void StatusBarMessageLabel::updateCloseButtonPosition()
303 {
304 const int x = width() - m_closeButton->width() - BorderGap;
305 m_closeButton->move(x, 0);
306 }
307
308 void StatusBarMessageLabel::closeErrorMessage()
309 {
310 if (!showPendingMessage()) {
311 reset();
312 setMessage(m_defaultText, DolphinStatusBar::Default);
313 }
314 }
315
316 bool StatusBarMessageLabel::showPendingMessage()
317 {
318 if (!m_pendingMessages.isEmpty()) {
319 reset();
320 setMessage(m_pendingMessages.takeFirst(), DolphinStatusBar::Error);
321 return true;
322 }
323 return false;
324 }
325
326 void StatusBarMessageLabel::reset()
327 {
328 m_text.clear();
329 m_type = DolphinStatusBar::Default;
330 }
331
332 #include "statusbarmessagelabel.moc"