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