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