]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/util/fmtwidgetitem.cpp
bat: Use green/red bullet for InChanger in mediview
[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::setInChanger(int index, const QString &InChanger)
196 {
197    setPixmap(index, 
198              QPixmap(":images/inflag"+InChanger+".png"));
199    setSortValue(index, InChanger.toInt() );
200 }
201
202 void ItemFormatterBase::setTextFld(int index, const QString &fld, bool center)
203 {
204    setText(index, fld.trimmed());
205    if (center) {
206       setTextAlignment(index, Qt::AlignCenter);
207    }
208 }
209
210 void ItemFormatterBase::setRightFld(int index, const QString &fld)
211 {
212    setText(index, fld.trimmed());
213    setTextAlignment(index, Qt::AlignRight | Qt::AlignVCenter);
214 }
215
216 void ItemFormatterBase::setBoolFld(int index, const QString &fld, bool center)
217 {
218    if (fld.trimmed().toInt())
219      setTextFld(index, QObject::tr("Yes"), center);
220    else
221      setTextFld(index, QObject::tr("No"), center);
222 }
223
224 void ItemFormatterBase::setBoolFld(int index, int fld, bool center)
225 {
226    if (fld)
227      setTextFld(index, QObject::tr("Yes"), center);
228    else
229      setTextFld(index, QObject::tr("No"), center);
230 }
231
232 void ItemFormatterBase::setNumericFld(int index, const QString &fld)
233 {
234    setRightFld(index, fld.trimmed());
235    setSortValue(index, fld.toDouble() );
236 }
237
238 void ItemFormatterBase::setNumericFld(int index, const QString &fld, const QVariant &sortval)
239 {
240    setRightFld(index, fld.trimmed());
241    setSortValue(index, sortval );
242 }
243
244 void ItemFormatterBase::setBytesFld(int index, const QString &fld)
245 {
246    qint64 qfld = fld.trimmed().toLongLong();
247    QString msg;
248    switch (cnvFlag) {
249    case BYTES_CONVERSION_NONE:
250       msg = QString::number(qfld);
251       break;
252    case BYTES_CONVERSION_IEC:
253       msg = convertBytesIEC(qfld);
254       break;
255    case BYTES_CONVERSION_SI:
256       msg = convertBytesSI(qfld);
257       break;
258    }
259
260    setNumericFld(index, msg, qfld);
261 }
262
263 void ItemFormatterBase::setDurationFld(int index, const QString &fld)
264 {
265    static const qint64 HOUR = Q_INT64_C(3600);
266    static const qint64 DAY = HOUR * 24;
267    static const qint64 WEEK = DAY * 7;
268    static const qint64 MONTH = DAY * 30;
269    static const qint64 YEAR = DAY * 365;
270    static const qint64 divs[] = { YEAR, MONTH, WEEK, DAY, HOUR };
271    static const char sufs[] = { 'y', 'm', 'w', 'd', 'h', '\0' };
272
273    qint64 dfld = fld.trimmed().toLongLong();
274
275    char suffix = 's';
276    if (dfld) {
277       for (int pos = 0 ; sufs[pos] ; ++pos) {
278           if (dfld % divs[pos] == 0) {
279              dfld /= divs[pos];
280              suffix = sufs[pos];
281              break;
282           }
283       }
284    }
285    QString msg;
286    if (dfld < 100) {
287       msg = QString("%1%2").arg(dfld).arg(suffix);
288    } else {
289       /* previous check returned a number too big. The original specification perhaps
290          was mixed, like 1d 2h, so we try to match with this routine */
291       dfld = fld.trimmed().toLongLong();
292       msg = "";
293       for (int pos = 0 ; sufs[pos] ; ++pos) {
294           if (dfld / divs[pos] != 0) {
295              msg += QString(" %1%2").arg(dfld / divs[pos]).arg(sufs[pos]);
296              dfld %= divs[pos];
297           }
298       }
299       if (dfld)
300          msg += QString(" %1s").arg(dfld);
301    }
302
303    setNumericFld(index, msg, fld.trimmed().toLongLong());
304 }
305
306 void ItemFormatterBase::setVolStatusFld(int index, const QString &fld, bool center)
307 {
308   QString mp(fld.trimmed());
309    setTextFld(index, volume_status_to_str(mp.toUtf8()), center);
310
311    if (mp == "Append" ) {
312       setBackground(index, Qt::green);
313    } else if (mp == "Error") {
314       setBackground(index, Qt::red);
315    } else if (mp == "Used" || mp == "Full"){
316       setBackground(index, Qt::yellow);
317    } else if (mp == "Read-only" || mp == "Disabled"){
318       setBackground(index, Qt::lightGray);
319    }
320 }
321
322 void ItemFormatterBase::setJobStatusFld(int index, const QString &status, bool center)
323 {
324    /* C (created, not yet running) uses the default background */
325    static QString greenchars("TR");
326    static QString redchars("BEf");
327    static QString yellowchars("eDAFSMmsjdctp");
328
329    setTextFld(index, convertJobStatus(status), center);
330
331    QString st(status.trimmed());
332    if (greenchars.contains(st, Qt::CaseSensitive)) {
333       setBackground(index, Qt::green);
334    } else if (redchars.contains(st, Qt::CaseSensitive)) {
335       setBackground(index, Qt::red);
336    } else if (yellowchars.contains(st, Qt::CaseSensitive)){ 
337       setBackground(index, Qt::yellow);
338    }
339 }
340
341 void ItemFormatterBase::setJobTypeFld(int index, const QString &fld, bool center)
342 {
343    QByteArray jtype(fld.trimmed().toAscii());
344    if (jtype.size()) {
345       setTextFld(index, job_type_to_str(jtype[0]), center);
346    } else {
347       setTextFld(index, "", center);
348    }
349 }
350
351 void ItemFormatterBase::setJobLevelFld(int index, const QString &fld, bool center)
352 {
353    QByteArray lvl(fld.trimmed().toAscii());
354    if (lvl.size()) {
355       setTextFld(index, job_level_to_str(lvl[0]), center);
356    } else {
357       setTextFld(index, "", center);
358    }
359 }
360
361
362
363 /***********************************************
364  *
365  * treeitem formatting routines
366  *
367  ***********************************************/
368 TreeItemFormatter::TreeItemFormatter(QTreeWidgetItem &parent, int indent_level):
369 ItemFormatterBase(),
370 wdg(new QTreeWidgetItem(&parent)),
371 level(indent_level)
372 {
373 }
374
375 void TreeItemFormatter::setText(int index, const QString &fld)
376 {
377    wdg->setData(index, Qt::UserRole, level);
378    wdg->setText(index, fld);
379 }
380
381 void TreeItemFormatter::setTextAlignment(int index, int align)
382 {
383    wdg->setTextAlignment(index, align);
384 }
385
386 void TreeItemFormatter::setBackground(int index, const QBrush &qb)
387 {
388    wdg->setBackground(index, qb);
389 }
390
391 /* at this time we don't sort trees, so this method does nothing */
392 void TreeItemFormatter::setSortValue(int /* index */, const QVariant & /* value */)
393 {
394 }
395
396 void TreeItemFormatter::setPixmap(int index, const QPixmap &pix)
397 {
398    wdg->setIcon(index, QIcon(pix));
399 }
400
401 /***********************************************
402  *
403  * Specialized table widget used for sorting
404  *
405  ***********************************************/
406 TableItemFormatter::BatSortingTableItem::BatSortingTableItem():
407 QTableWidgetItem(1)
408 {
409 }
410
411 void TableItemFormatter::BatSortingTableItem::setSortData(const QVariant &d)
412 {
413    setData(SORTDATA_ROLE, d);
414 }
415
416 bool TableItemFormatter::BatSortingTableItem::operator< ( const QTableWidgetItem & o ) const 
417 {
418    QVariant my = data(SORTDATA_ROLE);
419    QVariant other = o.data(SORTDATA_ROLE);
420    if (!my.isValid() || !other.isValid() || my.type() != other.type())
421       return QTableWidgetItem::operator< (o); /* invalid combination, revert to default sorting */
422
423    /* 64bit integers must be handled separately, others can be converted to double */
424    if (QVariant::ULongLong == my.type()) {
425       return my.toULongLong() < other.toULongLong(); 
426    } else if (QVariant::LongLong == my.type()) {
427       return my.toLongLong() < other.toLongLong(); 
428    } else if (my.canConvert(QVariant::Double)) {
429       return my.toDouble() < other.toDouble(); 
430    } else {
431       return QTableWidgetItem::operator< (o); /* invalid combination, revert to default sorting */
432    }
433 }
434
435 /***********************************************
436  *
437  * tableitem formatting routines
438  *
439  ***********************************************/
440 TableItemFormatter::TableItemFormatter(QTableWidget &tparent, int trow):
441 ItemFormatterBase(),
442 parent(&tparent),
443 row(trow),
444 last(NULL)
445 {
446 }
447
448 void TableItemFormatter::setPixmap(int index, const QPixmap &pix)
449 {
450    last = new BatSortingTableItem;
451    parent->setItem(row, index, last);
452    last->setIcon(pix);
453 }
454
455 void TableItemFormatter::setText(int col, const QString &fld)
456 {
457    last = new BatSortingTableItem;
458    parent->setItem(row, col, last);
459    last->setText(fld);
460 }
461
462 void TableItemFormatter::setTextAlignment(int /*index*/, int align)
463 {
464    last->setTextAlignment(align);
465 }
466
467 void TableItemFormatter::setBackground(int /*index*/, const QBrush &qb)
468 {
469    last->setBackground(qb);
470 }
471
472 void TableItemFormatter::setSortValue(int /* index */, const QVariant &value )
473 {
474    last->setSortData(value);
475 }
476
477 QTableWidgetItem *TableItemFormatter::widget(int col)
478 {
479    return parent->item(row, col);
480 }
481
482 const QTableWidgetItem *TableItemFormatter::widget(int col) const
483 {
484    return parent->item(row, col);
485 }
486