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