OSDN Git Service

kdeplasma-addons: QPainter runtime warning fix
[kde/kde-extraapps.git] / kdeplasma-addons / applets / weatherstation / lcd.cpp
1 /*
2  *   Copyright (C) 2007, 2008 Petri Damsten <damu@iki.fi>
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU Library General Public License as
6  *   published by the Free Software Foundation; either version 2, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details
13  *
14  *   You should have received a copy of the GNU Library General Public
15  *   License along with this program; if not, write to the
16  *   Free Software Foundation, Inc.,
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19
20 #include "lcd.h"
21 #include <QPainter>
22 #include <QDir>
23 #include <QGraphicsLinearLayout>
24 #include <QtGui/qgraphicssceneevent.h>
25
26 #include <QtXml/qdom.h>
27 #include <QCursor>
28 #include <KDebug>
29 #include <KDecompressor>
30 #include <Plasma/Theme>
31 #include <Plasma/Svg>
32
33 class LCD::Private
34 {
35     public:
36         LCD* l;
37         QString content;
38         Plasma::Svg svg;
39         bool dirty;
40         QPixmap img;
41         QStringList items;
42         QMap<QString, QStringList> groups;
43         QHash<QString, QDomText> texts;
44         QStringList clickable;
45         QDomDocument doc;
46
47         static const QString A;
48         static const QString B;
49         static const QString C;
50         static const QString D;
51         static const QString E;
52         static const QString F;
53         static const QString G;
54         static const QString DP;
55         static QMap<QChar, QStringList> sevenSegmentDigits;
56         qreal xScale;
57         qreal yScale;
58
59         Private(LCD* lcd) : l(lcd), dirty(false), xScale(1.0), yScale(1.0)
60         {
61             // http://en.wikipedia.org/wiki/Seven-segment_display_character_representations
62             if (sevenSegmentDigits.isEmpty()) {
63                 sevenSegmentDigits[' '] = QStringList();
64                 sevenSegmentDigits['-'] = QStringList() << G;
65                 sevenSegmentDigits['0'] = QStringList() << A << B << C << D << E << F;
66                 sevenSegmentDigits['1'] = QStringList() << B << C;
67                 sevenSegmentDigits['2'] = QStringList() << A << B << D << E << G;
68                 sevenSegmentDigits['3'] = QStringList() << A << B << C << D << G;
69                 sevenSegmentDigits['4'] = QStringList() << B << C << F << G;
70                 sevenSegmentDigits['5'] = QStringList() << A << C << D << F << G;
71                 sevenSegmentDigits['6'] = QStringList() << A << C << D << E << F << G;
72                 sevenSegmentDigits['7'] = QStringList() << A << B << C;
73                 sevenSegmentDigits['8'] = QStringList() << A << B << C << D << E << F << G;
74                 sevenSegmentDigits['9'] = QStringList() << A << B << C << D << F << G;
75                 sevenSegmentDigits['A'] = QStringList() << A << B << C << E << F << G;
76                 sevenSegmentDigits['B'] = QStringList() << A << B << C << D << E << F << G;
77                 sevenSegmentDigits['C'] = QStringList() << A << D << E << F;
78                 sevenSegmentDigits['D'] = QStringList() << A << B << C << D << E << F;
79                 sevenSegmentDigits['E'] = QStringList() << A << D << E << F << G;
80                 sevenSegmentDigits['F'] = QStringList() << A << E << F << G;
81                 sevenSegmentDigits['G'] = QStringList() << A << C << D << E << F;
82                 sevenSegmentDigits['H'] = QStringList() << B << C << E << F << G;
83                 sevenSegmentDigits['I'] = QStringList() << B << C;
84                 sevenSegmentDigits['J'] = QStringList() << B << C << D << E;
85                 sevenSegmentDigits['K'] = QStringList() << E << F << G;
86                 sevenSegmentDigits['L'] = QStringList() << D << E << F;
87                 sevenSegmentDigits['M'] = QStringList() << A << B << D << F;
88                 sevenSegmentDigits['N'] = QStringList() << A << B << C << E << F;
89                 sevenSegmentDigits['O'] = QStringList() << A << B << C << D << E << F;
90                 sevenSegmentDigits['P'] = QStringList() << A << B << E << F << G;
91                 sevenSegmentDigits['Q'] = QStringList() << A << B << D << F << G;
92                 sevenSegmentDigits['R'] = QStringList() << A << E << F;
93                 sevenSegmentDigits['S'] = QStringList() << A << C << D << F << G;
94                 sevenSegmentDigits['T'] = QStringList() << A << E << F;
95                 sevenSegmentDigits['U'] = QStringList() << B << C << D << E << F;
96                 sevenSegmentDigits['V'] = QStringList() << B << C << D << E << F;
97                 sevenSegmentDigits['W'] = QStringList() << B << D << F << G;
98                 sevenSegmentDigits['X'] = QStringList() << B << C << E << F << G;
99                 sevenSegmentDigits['Y'] = QStringList() << B << C << F << G;
100                 sevenSegmentDigits['Z'] = QStringList() << A << B << D << E << G;
101                 sevenSegmentDigits['a'] = QStringList() << A << B << C << D << E << G;
102                 sevenSegmentDigits['b'] = QStringList() << C << D << E << F << G;
103                 sevenSegmentDigits['c'] = QStringList() << D << E << G;
104                 sevenSegmentDigits['d'] = QStringList() << B << C << D << E << G;
105                 sevenSegmentDigits['e'] = QStringList() << A << B << E << F << G;
106                 sevenSegmentDigits['f'] = QStringList() << A << E << F << G;
107                 sevenSegmentDigits['g'] = QStringList() << A << B << C << D << F << G;
108                 sevenSegmentDigits['h'] = QStringList() << C << E << F << G;
109                 sevenSegmentDigits['i'] = QStringList() << C;
110                 sevenSegmentDigits['j'] = QStringList() << C << D;
111                 sevenSegmentDigits['k'] = QStringList() << A << C << E << F << G;
112                 sevenSegmentDigits['l'] = QStringList() << E << F;
113                 sevenSegmentDigits['m'] = QStringList() << A << C << E << G;
114                 sevenSegmentDigits['n'] = QStringList() << C << E << G;
115                 sevenSegmentDigits[QChar(0x00F1)] = QStringList() << A << C << E << G; // ñ
116                 sevenSegmentDigits['o'] = QStringList() << C << D << E << G;
117                 sevenSegmentDigits['p'] = QStringList() << A << B << E << F << G;
118                 sevenSegmentDigits['q'] = QStringList() << A << B << C << F << G;
119                 sevenSegmentDigits['r'] = QStringList() << E << G;
120                 sevenSegmentDigits['s'] = QStringList() << E << G;
121                 sevenSegmentDigits['t'] = QStringList() << D << E << F << G;
122                 sevenSegmentDigits['u'] = QStringList() << C << D << E;
123                 sevenSegmentDigits['v'] = QStringList() << E << G;
124                 sevenSegmentDigits['w'] = QStringList() << E << G;
125                 sevenSegmentDigits['x'] = QStringList() << E << G;
126                 sevenSegmentDigits['y'] = QStringList() << E << G;
127                 sevenSegmentDigits['z'] = QStringList() << E << G;
128                 sevenSegmentDigits[QChar(0x00F6)] = QStringList() << A << C << D << E << G; // ö
129             }
130         }
131
132         int digits(const QString& name)
133         {
134             return groups[name].count();
135         }
136
137         void paint(QPainter* p, const QString& item)
138         {
139             QRectF r = svg.elementRect(item);
140             svg.paint(p, r, item);
141         }
142
143         QRectF scaledRect(const QString& item)
144         {
145             QRectF r = svg.elementRect(item);
146             r.setRect(r.x() * xScale, r.y() * yScale, r.width() * xScale, r.height() * yScale);
147             return r;
148         }
149
150         void checkIfDirty()
151         {
152             const QSize lsize = l->size().toSize();
153             if ((dirty || lsize != img.size()) && lsize != QSize(0, 0)) {
154                 // kDebug() << "Making bitmap" << l->size();
155                 if (lsize != img.size()) {
156                     img = QPixmap(lsize);
157                 }
158                 img.fill(Qt::transparent);
159
160                 QPainter p(&img);
161
162                 xScale = l->size().width() / svg.size().width();
163                 yScale = l->size().height() / svg.size().height();
164                 p.setRenderHint(QPainter::TextAntialiasing, true);
165                 p.setRenderHint(QPainter::Antialiasing, true);
166                 p.setRenderHint(QPainter::SmoothPixmapTransform, true);
167
168                 p.save();
169                 p.scale(l->size().width() / svg.size().width(),
170                         l->size().height() / svg.size().height());
171
172                 foreach (const QString& item, items) {
173                     paint(&p, item);
174                 }
175                 p.restore();
176                 dirty = false;
177             }
178         }
179
180         void parseXml()
181         {
182             // kDebug() << content;
183             KDecompressor kdecompressor;
184             if (!kdecompressor.setType(KDecompressor::TypeGZip)) {
185                 kWarning() << "Could not set decompressor type" << kdecompressor.errorString();
186                 return;
187             }
188
189             QFile contentFile(content);
190             if (!contentFile.open(QFile::ReadOnly)) {
191                 kWarning() << "Could open content file" << content << contentFile.errorString();
192                 return;
193             }
194
195             if (!kdecompressor.process(contentFile.readAll())) {
196                 kWarning() << "Could not decompress content" << kdecompressor.errorString();
197                 return;
198             }
199
200             doc.setContent(kdecompressor.result());
201             QList<QDomNodeList> lists;
202             int pos;
203             lists << doc.elementsByTagName("g");
204             lists << doc.elementsByTagName("path");
205             lists << doc.elementsByTagName("rect");
206             foreach (const QDomNodeList& list, lists) {
207                 for (int i = 0; i < list.count(); ++i) {
208                     QDomElement element = list.item(i).toElement();
209                     QString id = element.attribute("id");
210                     if ((pos = id.lastIndexOf(':')) > -1) {
211                         groups[id.left(pos)] << id.mid(pos + 1);
212                     }
213                 }
214             }
215             QDomNodeList list = doc.elementsByTagName("text");
216             for (int i = 0; i < list.count(); ++i) {
217                 QDomElement element = list.item(i).toElement();
218                 QDomNodeList l = element.elementsByTagName("tspan");
219                 QDomElement e = l.item(0).toElement();
220                 for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
221                     QDomText t = n.toText();
222                     if (!t.isNull()) {
223                         texts[element.attribute("id")] = t;
224                     }
225                 }
226             }
227
228             // kDebug() << groups;
229         }
230 };
231
232 QMap<QChar, QStringList> LCD::Private::sevenSegmentDigits;
233 const QString LCD::Private::A("A");
234 const QString LCD::Private::B("B");
235 const QString LCD::Private::C("C");
236 const QString LCD::Private::D("D");
237 const QString LCD::Private::E("E");
238 const QString LCD::Private::F("F");
239 const QString LCD::Private::G("G");
240 const QString LCD::Private::DP("DP");
241
242 LCD::LCD(QGraphicsItem *parent) :
243         QGraphicsWidget(parent),
244         d(new Private(this))
245 {
246     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
247 }
248
249 LCD::~LCD()
250 {
251     delete d;
252 }
253
254 QString LCD::svg() const
255 {
256     return d->content;
257 }
258
259 void LCD::setSvg(const QString &svg)
260 {
261     d->content = Plasma::Theme::defaultTheme()->imagePath(svg);
262     d->svg.setImagePath(d->content);
263     d->parseXml();
264     d->dirty = true;
265     update();
266 }
267
268 QStringList LCD::groupItems(const QString &name)
269 {
270     return d->groups[name];
271 }
272
273 void LCD::paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget)
274 {
275     Q_UNUSED(option)
276     Q_UNUSED(widget)
277
278     d->checkIfDirty();
279     p->drawPixmap(0, 0, d->img);
280 }
281
282 void LCD::setDigit(const QString &name, QChar digit, bool dot)
283 {
284     QStringList segments;
285
286     // kDebug() << name << digit << dot;
287     if (d->sevenSegmentDigits.keys().contains(digit)) {
288         segments = d->sevenSegmentDigits[digit];
289     }
290     if (dot) {
291         segments << d->DP;
292     }
293     setGroup(name, segments);
294 }
295
296 void LCD::setNumber(const QString &name, const QString& number)
297 {
298     int j = 0;
299     int digits = d->digits(name);
300     bool dot = false;
301
302     // kDebug() << name << number << digits;
303     for (int i = number.length() - 1; i >= 0; --i) {
304         if (number[i] == '.') {
305             dot = true;
306         } else {
307             setDigit(name + QString(":%1").arg(j++), number[i], dot);
308             dot = false;
309         }
310         if (j >= digits) {
311             break;
312         }
313     }
314     for (int i = j; i < digits; ++i) {
315         setDigit(name + QString(":%1").arg(i), ' ', false);
316     }
317 }
318
319 void LCD::setGroup(const QString &name, const QStringList& on)
320 {
321     QStringList all = d->groups[name];
322     foreach (const QString& item, all) {
323         if (on.contains(item)) {
324             setItemOn(name + ':' + item);
325         } else {
326             setItemOff(name + ':' + item);
327         }
328     }
329 }
330
331 void LCD::clear()
332 {
333     d->items.clear();
334 }
335
336 void LCD::setItemOn(const QString &name)
337 {
338     if (!d->items.contains(name)) {
339         // kDebug() << "++++++++++" << name;
340         d->items << name;
341         d->dirty = true;
342         update();
343     }
344 }
345
346 void LCD::setItemOff(const QString &name)
347 {
348     if (d->items.contains(name)) {
349         // kDebug() << "----------" << name;
350         d->items.removeAll(name);
351         d->dirty = true;
352         update();
353     }
354 }
355
356 void LCD::setLabel(const QString &name, const QString &text)
357 {
358     if (d->texts[name].data() != text) {
359         d->texts[name].setData(text);
360     }
361 }
362
363 QString LCD::label(const QString &name) const
364 {
365     return d->texts[name].data();
366 }
367
368 QPixmap LCD::toPixmap()
369 {
370     d->checkIfDirty();
371     return d->img;
372 }
373
374 void LCD::setItemClickable(const QString &name, bool clickable)
375 {
376     d->clickable.removeAll(name);
377     if (clickable) {
378         setAcceptHoverEvents(true);
379         d->clickable << name;
380     }
381 }
382
383 void LCD::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
384 {
385     foreach (const QString& name, d->clickable) {
386         if (d->scaledRect(name).contains(event->pos())) {
387             setCursor(QCursor(Qt::PointingHandCursor));
388             return;
389         }
390     }
391     unsetCursor();
392 }
393
394 void LCD::mousePressEvent(QGraphicsSceneMouseEvent* event)
395 {
396     foreach (const QString& name, d->clickable) {
397         if (d->scaledRect(name).contains(event->pos())) {
398             emit clicked(name);
399         }
400     }
401 }
402
403 QSizeF LCD::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
404 {
405     QSizeF s = QGraphicsWidget::sizeHint(which, constraint);
406     d->checkIfDirty();
407     if (which == Qt::PreferredSize) {
408         s = d->svg.size();
409     } else if (which == Qt::MinimumSize) {
410         s = d->svg.size() / 2;
411     } else {
412         s = QGraphicsWidget::sizeHint(which, constraint);
413     }
414     return s;
415 }
416
417 #include "moc_lcd.cpp"