]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/util/fmtwidgetitem.cpp
Merge branch 'master' into basejobv3
[bacula/bacula] / bacula / src / qt-console / util / fmtwidgetitem.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28  
29 /*
30  *   Version $Id$
31  *
32  *  Helper functions for tree widget formatting
33  *
34  *   Riccardo Ghetta, May 2008
35  *
36  */ 
37
38 #include "bat.h"
39 #include <QTreeWidgetItem>
40 #include <QTableWidget>
41 #include <QTableWidgetItem>
42 #include <QBrush>
43 #include <QString>
44 #include <QStringList>
45 #include <math.h>
46 #include "fmtwidgetitem.h"
47
48 /***********************************************
49  *
50  * common helpers
51  *
52  ***********************************************/
53
54 QString convertJobStatus(const QString &sts)
55 {
56    QString code( sts.trimmed() );
57    if ( code.size() != 1) {
58       return QObject::tr("Invalid job status %1").arg(sts);
59    }
60
61    char buf[256];
62    jobstatus_to_ascii_gui( code[0].toAscii(), buf, sizeof(buf));
63    return QString(buf);
64 }
65
66 /*
67  * disable widget updating
68  */
69 Freeze::Freeze(QWidget &q):
70 qw(&q)
71 {
72    qw->setUpdatesEnabled(false); 
73 }
74
75 Freeze::~Freeze()
76 {
77    if (qw) {
78       qw->setUpdatesEnabled(true); 
79       qw->update();
80    }
81 }
82
83 /***********************************************
84  *
85  * ItemFormatterBase static members
86  *
87  ***********************************************/
88
89 ItemFormatterBase::BYTES_CONVERSION ItemFormatterBase::cnvFlag(BYTES_CONVERSION_IEC);
90
91 QString convertBytesIEC(qint64 qfld)
92 {
93    static const qint64 KB = Q_INT64_C(1024);
94    static const qint64 MB = (KB * KB);
95    static const qint64 GB = (MB * KB);
96    static const qint64 TB = (GB * KB);
97    static const qint64 PB = (TB * KB);
98    static const qint64 EB = (PB * KB);
99
100    /* note: division is integer, so to have some decimals we divide for a
101       smaller unit (e.g. GB for a TB number and so on) */
102    char suffix;
103    if (qfld >= EB) {
104       qfld /= PB; 
105       suffix = 'E';
106    }
107    else if (qfld >= PB) {
108       qfld /= TB; 
109       suffix = 'P';
110    }
111    else if (qfld >= TB) {
112       qfld /= GB; 
113       suffix = 'T';
114    }
115    else if (qfld >= GB) {
116       qfld /= MB;
117       suffix = 'G';
118    }
119    else if (qfld >= MB) {
120       qfld /= KB;
121       suffix = 'M';
122    }
123    else if (qfld >= KB) {
124       suffix = 'K';
125    }
126    else  {
127       /* plain bytes, no need to reformat */
128       return QString("%1 B").arg(qfld); 
129    }
130
131    /* having divided for a smaller unit, now we can safely convert to double and
132       use the extra room for decimals */
133    return QString("%1 %2iB").arg(qfld / 1000.0, 0, 'f', 2).arg(suffix);
134 }
135
136 QString convertBytesSI(qint64 qfld)
137 {
138    static const qint64 KB = Q_INT64_C(1000);
139    static const qint64 MB = (KB * KB);
140    static const qint64 GB = (MB * KB);
141    static const qint64 TB = (GB * KB);
142    static const qint64 PB = (TB * KB);
143    static const qint64 EB = (PB * KB);
144
145    /* note: division is integer, so to have some decimals we divide for a
146       smaller unit (e.g. GB for a TB number and so on) */
147    char suffix;
148    if (qfld >= EB) {
149       qfld /= PB; 
150       suffix = 'E';
151    }
152    else if (qfld >= PB) {
153       qfld /= TB; 
154       suffix = 'P';
155    }
156    else if (qfld >= TB) {
157       qfld /= GB; 
158       suffix = 'T';
159    }
160    else if (qfld >= GB) {
161       qfld /= MB;
162       suffix = 'G';
163    }
164    else if (qfld >= MB) {
165       qfld /= KB;
166       suffix = 'M';
167    }
168    else if (qfld >= KB) {
169       suffix = 'k'; /* SI uses lowercase k */
170    }
171    else  {
172       /* plain bytes, no need to reformat */
173       return QString("%1 B").arg(qfld); 
174    }
175
176    /* having divided for a smaller unit, now we can safely convert to double and
177       use the extra room for decimals */
178    return QString("%1 %2B").arg(qfld / 1000.0, 0, 'f', 2).arg(suffix);
179 }
180
181 /***********************************************
182  *
183  * base formatting routines
184  *
185  ***********************************************/
186
187 ItemFormatterBase::ItemFormatterBase()
188 {
189 }
190
191 ItemFormatterBase::~ItemFormatterBase()
192 {
193 }
194
195 void ItemFormatterBase::setPercent(int index, float value)
196 {
197    char buf[100];
198    bsnprintf(buf, sizeof(buf), "%.2f%%", value);
199    QString val = buf;
200    QString pix;
201    if (value < 8) {
202       pix = ":images/0p.png";
203    } else if (value < 24) {
204       pix = ":images/16p.png";
205    } else if (value < 40) {
206       pix = ":images/32p.png";
207    } else if (value < 56) {
208       pix = ":images/48p.png";
209    } else if (value < 72) {
210       pix = ":images/64p.png";
211    } else if (value < 88) {
212       pix = ":images/80p.png";
213    } else {
214       pix = ":images/96p.png";
215    }
216    setPixmap(index, QPixmap(pix), val);
217    setSortValue(index, (int) value);
218 }
219
220 /* By default, the setPixmap implementation with tooltip don't implement
221  * the tooltip stuff
222  */
223 void ItemFormatterBase::setPixmap(int index, const QPixmap &pix, 
224                                   const QString &tip)
225 {
226    setPixmap(index, pix);
227 }
228
229 void ItemFormatterBase::setInChanger(int index, const QString &InChanger)
230 {
231    setPixmap(index, 
232              QPixmap(":images/inflag"+InChanger+".png"));
233    setSortValue(index, InChanger.toInt() );
234 }
235
236 void ItemFormatterBase::setTextFld(int index, const QString &fld, bool center)
237 {
238    setText(index, fld.trimmed());
239    if (center) {
240       setTextAlignment(index, Qt::AlignCenter);
241    }
242 }
243
244 void ItemFormatterBase::setRightFld(int index, const QString &fld)
245 {
246    setText(index, fld.trimmed());
247    setTextAlignment(index, Qt::AlignRight | Qt::AlignVCenter);
248 }
249
250 void ItemFormatterBase::setBoolFld(int index, const QString &fld, bool center)
251 {
252    if (fld.trimmed().toInt())
253      setTextFld(index, QObject::tr("Yes"), center);
254    else
255      setTextFld(index, QObject::tr("No"), center);
256 }
257
258 void ItemFormatterBase::setBoolFld(int index, int fld, bool center)
259 {
260    if (fld)
261      setTextFld(index, QObject::tr("Yes"), center);
262    else
263      setTextFld(index, QObject::tr("No"), center);
264 }
265
266 void ItemFormatterBase::setNumericFld(int index, const QString &fld)
267 {
268    setRightFld(index, fld.trimmed());
269    setSortValue(index, fld.toDouble() );
270 }
271
272 void ItemFormatterBase::setNumericFld(int index, const QString &fld, const QVariant &sortval)
273 {
274    setRightFld(index, fld.trimmed());
275    setSortValue(index, sortval );
276 }
277
278 void ItemFormatterBase::setBytesFld(int index, const QString &fld)
279 {
280    qint64 qfld = fld.trimmed().toLongLong();
281    QString msg;
282    switch (cnvFlag) {
283    case BYTES_CONVERSION_NONE:
284       msg = QString::number(qfld);
285       break;
286    case BYTES_CONVERSION_IEC:
287       msg = convertBytesIEC(qfld);
288       break;
289    case BYTES_CONVERSION_SI:
290       msg = convertBytesSI(qfld);
291       break;
292    }
293
294    setNumericFld(index, msg, qfld);
295 }
296
297 void ItemFormatterBase::setDurationFld(int index, const QString &fld)
298 {
299    static const qint64 HOUR = Q_INT64_C(3600);
300    static const qint64 DAY = HOUR * 24;
301    static const qint64 WEEK = DAY * 7;
302    static const qint64 MONTH = DAY * 30;
303    static const qint64 YEAR = DAY * 365;
304    static const qint64 divs[] = { YEAR, MONTH, WEEK, DAY, HOUR };
305    static const char sufs[] = { 'y', 'm', 'w', 'd', 'h', '\0' };
306
307    qint64 dfld = fld.trimmed().toLongLong();
308
309    char suffix = 's';
310    if (dfld) {
311       for (int pos = 0 ; sufs[pos] ; ++pos) {
312           if (dfld % divs[pos] == 0) {
313              dfld /= divs[pos];
314              suffix = sufs[pos];
315              break;
316           }
317       }
318    }
319    QString msg;
320    if (dfld < 100) {
321       msg = QString("%1%2").arg(dfld).arg(suffix);
322    } else {
323       /* previous check returned a number too big. The original specification perhaps
324          was mixed, like 1d 2h, so we try to match with this routine */
325       dfld = fld.trimmed().toLongLong();
326       msg = "";
327       for (int pos = 0 ; sufs[pos] ; ++pos) {
328           if (dfld / divs[pos] != 0) {
329              msg += QString(" %1%2").arg(dfld / divs[pos]).arg(sufs[pos]);
330              dfld %= divs[pos];
331           }
332       }
333       if (dfld)
334          msg += QString(" %1s").arg(dfld);
335    }
336
337    setNumericFld(index, msg, fld.trimmed().toLongLong());
338 }
339
340 void ItemFormatterBase::setVolStatusFld(int index, const QString &fld, bool center)
341 {
342   QString mp(fld.trimmed());
343    setTextFld(index, volume_status_to_str(mp.toUtf8()), center);
344
345    if (mp == "Append" ) {
346       setBackground(index, Qt::green);
347    } else if (mp == "Error") {
348       setBackground(index, Qt::red);
349    } else if (mp == "Used" || mp == "Full"){
350       setBackground(index, Qt::yellow);
351    } else if (mp == "Read-only" || mp == "Disabled"){
352       setBackground(index, Qt::lightGray);
353    }
354 }
355
356 void ItemFormatterBase::setJobStatusFld(int index, const QString &status, bool center)
357 {
358    /* C (created, not yet running) uses the default background */
359    static QString greenchars("TR");
360    static QString redchars("BEf");
361    static QString yellowchars("eDAFSMmsjdctp");
362
363    setTextFld(index, convertJobStatus(status), center);
364
365    QString st(status.trimmed());
366    if (greenchars.contains(st, Qt::CaseSensitive)) {
367       setBackground(index, Qt::green);
368    } else if (redchars.contains(st, Qt::CaseSensitive)) {
369       setBackground(index, Qt::red);
370    } else if (yellowchars.contains(st, Qt::CaseSensitive)){ 
371       setBackground(index, Qt::yellow);
372    }
373 }
374
375 void ItemFormatterBase::setJobTypeFld(int index, const QString &fld, bool center)
376 {
377    QByteArray jtype(fld.trimmed().toAscii());
378    if (jtype.size()) {
379       setTextFld(index, job_type_to_str(jtype[0]), center);
380    } else {
381       setTextFld(index, "", center);
382    }
383 }
384
385 void ItemFormatterBase::setJobLevelFld(int index, const QString &fld, bool center)
386 {
387    QByteArray lvl(fld.trimmed().toAscii());
388    if (lvl.size()) {
389       setTextFld(index, job_level_to_str(lvl[0]), center);
390    } else {
391       setTextFld(index, "", center);
392    }
393 }
394
395
396
397 /***********************************************
398  *
399  * treeitem formatting routines
400  *
401  ***********************************************/
402 TreeItemFormatter::TreeItemFormatter(QTreeWidgetItem &parent, int indent_level):
403 ItemFormatterBase(),
404 wdg(new QTreeWidgetItem(&parent)),
405 level(indent_level)
406 {
407 }
408
409 void TreeItemFormatter::setText(int index, const QString &fld)
410 {
411    wdg->setData(index, Qt::UserRole, level);
412    wdg->setText(index, fld);
413 }
414
415 void TreeItemFormatter::setTextAlignment(int index, int align)
416 {
417    wdg->setTextAlignment(index, align);
418 }
419
420 void TreeItemFormatter::setBackground(int index, const QBrush &qb)
421 {
422    wdg->setBackground(index, qb);
423 }
424
425 /* at this time we don't sort trees, so this method does nothing */
426 void TreeItemFormatter::setSortValue(int /* index */, const QVariant & /* value */)
427 {
428 }
429
430 void TreeItemFormatter::setPixmap(int index, const QPixmap &pix)
431 {
432    wdg->setIcon(index, QIcon(pix));
433 }
434
435 /***********************************************
436  *
437  * Specialized table widget used for sorting
438  *
439  ***********************************************/
440 TableItemFormatter::BatSortingTableItem::BatSortingTableItem():
441 QTableWidgetItem(1)
442 {
443 }
444
445 void TableItemFormatter::BatSortingTableItem::setSortData(const QVariant &d)
446 {
447    setData(SORTDATA_ROLE, d);
448 }
449
450 bool TableItemFormatter::BatSortingTableItem::operator< ( const QTableWidgetItem & o ) const 
451 {
452    QVariant my = data(SORTDATA_ROLE);
453    QVariant other = o.data(SORTDATA_ROLE);
454    if (!my.isValid() || !other.isValid() || my.type() != other.type())
455       return QTableWidgetItem::operator< (o); /* invalid combination, revert to default sorting */
456
457    /* 64bit integers must be handled separately, others can be converted to double */
458    if (QVariant::ULongLong == my.type()) {
459       return my.toULongLong() < other.toULongLong(); 
460    } else if (QVariant::LongLong == my.type()) {
461       return my.toLongLong() < other.toLongLong(); 
462    } else if (my.canConvert(QVariant::Double)) {
463       return my.toDouble() < other.toDouble(); 
464    } else {
465       return QTableWidgetItem::operator< (o); /* invalid combination, revert to default sorting */
466    }
467 }
468
469 /***********************************************
470  *
471  * tableitem formatting routines
472  *
473  ***********************************************/
474 TableItemFormatter::TableItemFormatter(QTableWidget &tparent, int trow):
475 ItemFormatterBase(),
476 parent(&tparent),
477 row(trow),
478 last(NULL)
479 {
480 }
481
482 void TableItemFormatter::setPixmap(int index, const QPixmap &pix)
483 {
484 // Centered, but not sortable !
485    QLabel *lbl = new QLabel();
486    lbl->setAlignment(Qt::AlignCenter);
487    lbl->setPixmap(pix);
488    parent->setCellWidget(row, index, lbl);
489 }
490
491 void TableItemFormatter::setPixmap(int index, const QPixmap &pix, 
492                                    const QString &tips)
493 {
494 // Centered, but not sortable !
495    QLabel *lbl = new QLabel();
496    lbl->setAlignment(Qt::AlignCenter);
497    lbl->setPixmap(pix);
498    if (!tips.isEmpty()) {
499       lbl->setToolTip(tips);
500    }
501    parent->setCellWidget(row, index, lbl);
502
503 //   last = new BatSortingTableItem;
504 //   parent->setItem(row, index, last);
505 //   last->setIcon(pix);
506 }
507
508 void TableItemFormatter::setText(int col, const QString &fld)
509 {
510    last = new BatSortingTableItem;
511    parent->setItem(row, col, last);
512    last->setText(fld);
513 }
514
515 void TableItemFormatter::setTextAlignment(int /*index*/, int align)
516 {
517    last->setTextAlignment(align);
518 }
519
520 void TableItemFormatter::setBackground(int /*index*/, const QBrush &qb)
521 {
522    last->setBackground(qb);
523 }
524
525 void TableItemFormatter::setSortValue(int /* index */, const QVariant &value )
526 {
527    last->setSortData(value);
528 }
529
530 QTableWidgetItem *TableItemFormatter::widget(int col)
531 {
532    return parent->item(row, col);
533 }
534
535 const QTableWidgetItem *TableItemFormatter::widget(int col) const
536 {
537    return parent->item(row, col);
538 }
539