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