]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/util/fmtwidgetitem.cpp
Commit of patch by Riccardo.
[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 John Walker.
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 <QTreeWidgetItem>
39 #include <QTableWidget>
40 #include <QTableWidgetItem>
41 #include <QBrush>
42 #include <QString>
43 #include <QStringList>
44 #include <math.h>
45 #include "bat.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  *
68  * ItemFormatterBase static members
69  *
70  ***********************************************/
71
72 ItemFormatterBase::BYTES_CONVERSION ItemFormatterBase::cnvFlag(BYTES_CONVERSION_IEC);
73
74 QString ItemFormatterBase::convertBytesIEC(qint64 qfld)
75 {
76    static const qint64 KB = Q_INT64_C(1024);
77    static const qint64 MB = (KB * KB);
78    static const qint64 GB = (MB * KB);
79    static const qint64 TB = (GB * KB);
80    static const qint64 PB = (TB * KB);
81    static const qint64 EB = (PB * KB);
82
83    /* note: division is integer, so to have some decimals we divide for a
84       smaller unit (e.g. GB for a TB number and so on) */
85    char suffix;
86    if (qfld >= EB) {
87       qfld /= PB; 
88       suffix = 'E';
89    }
90    else if (qfld >= PB) {
91       qfld /= TB; 
92       suffix = 'P';
93    }
94    else if (qfld >= TB) {
95       qfld /= GB; 
96       suffix = 'T';
97    }
98    else if (qfld >= GB) {
99       qfld /= MB;
100       suffix = 'G';
101    }
102    else if (qfld >= MB) {
103       qfld /= KB;
104       suffix = 'M';
105    }
106    else if (qfld >= KB) {
107       suffix = 'K';
108    }
109    else  {
110       /* plain bytes, no need to reformat */
111       return QString("%1 B").arg(qfld); 
112    }
113
114    /* having divided for a smaller unit, now we can safely convert to double and
115       use the extra room for decimals */
116    return QString("%1 %2iB").arg(qfld / 1000.0, 0, 'f', 2).arg(suffix);
117 }
118
119 QString ItemFormatterBase::convertBytesSI(qint64 qfld)
120 {
121    static const qint64 KB = Q_INT64_C(1000);
122    static const qint64 MB = (KB * KB);
123    static const qint64 GB = (MB * KB);
124    static const qint64 TB = (GB * KB);
125    static const qint64 PB = (TB * KB);
126    static const qint64 EB = (PB * KB);
127
128    /* note: division is integer, so to have some decimals we divide for a
129       smaller unit (e.g. GB for a TB number and so on) */
130    char suffix;
131    if (qfld >= EB) {
132       qfld /= PB; 
133       suffix = 'E';
134    }
135    else if (qfld >= PB) {
136       qfld /= TB; 
137       suffix = 'P';
138    }
139    else if (qfld >= TB) {
140       qfld /= GB; 
141       suffix = 'T';
142    }
143    else if (qfld >= GB) {
144       qfld /= MB;
145       suffix = 'G';
146    }
147    else if (qfld >= MB) {
148       qfld /= KB;
149       suffix = 'M';
150    }
151    else if (qfld >= KB) {
152       suffix = 'k'; /* SI uses lowercase k */
153    }
154    else  {
155       /* plain bytes, no need to reformat */
156       return QString("%1 B").arg(qfld); 
157    }
158
159    /* having divided for a smaller unit, now we can safely convert to double and
160       use the extra room for decimals */
161    return QString("%1 %2B").arg(qfld / 1000.0, 0, 'f', 2).arg(suffix);
162 }
163
164 /***********************************************
165  *
166  * base formatting routines
167  *
168  ***********************************************/
169
170 ItemFormatterBase::ItemFormatterBase()
171 {
172 }
173
174 ItemFormatterBase::~ItemFormatterBase()
175 {
176 }
177
178 void ItemFormatterBase::setTextFld(int index, const QString &fld, bool center)
179 {
180    setText(index, fld.trimmed());
181    if (center) {
182       setTextAlignment(index, Qt::AlignCenter);
183    }
184 }
185
186 void ItemFormatterBase::setRightFld(int index, const QString &fld)
187 {
188    setText(index, fld.trimmed());
189    setTextAlignment(index, Qt::AlignRight | Qt::AlignVCenter);
190 }
191
192 void ItemFormatterBase::setBoolFld(int index, const QString &fld, bool center)
193 {
194    if (fld.trimmed().toInt())
195      setTextFld(index, QObject::tr("Yes"), center);
196    else
197      setTextFld(index, QObject::tr("No"), center);
198 }
199
200 void ItemFormatterBase::setBoolFld(int index, int fld, bool center)
201 {
202    if (fld)
203      setTextFld(index, QObject::tr("Yes"), center);
204    else
205      setTextFld(index, QObject::tr("No"), center);
206 }
207
208 void ItemFormatterBase::setNumericFld(int index, const QString &fld)
209 {
210    setRightFld(index, fld.trimmed());
211    setSortValue(index, fld.toDouble() );
212 }
213
214 void ItemFormatterBase::setNumericFld(int index, const QString &fld, const QVariant &sortval)
215 {
216    setRightFld(index, fld.trimmed());
217    setSortValue(index, sortval );
218 }
219
220 void ItemFormatterBase::setBytesFld(int index, const QString &fld)
221 {
222    qint64 qfld = fld.trimmed().toLongLong();
223    QString msg;
224    switch (cnvFlag) {
225    case BYTES_CONVERSION_NONE:
226       msg = QString::number(qfld);
227       break;
228    case BYTES_CONVERSION_IEC:
229       msg = convertBytesIEC(qfld);
230       break;
231    case BYTES_CONVERSION_SI:
232       msg = convertBytesSI(qfld);
233       break;
234    }
235
236    setNumericFld(index, msg, qfld);
237 }
238
239 void ItemFormatterBase::setDurationFld(int index, const QString &fld)
240 {
241    static const qint64 HOUR = Q_INT64_C(3600);
242    static const qint64 DAY = HOUR * 24;
243    static const qint64 WEEK = DAY * 7;
244    static const qint64 MONTH = DAY * 30;
245    static const qint64 YEAR = DAY * 365;
246    static const qint64 divs[] = { YEAR, MONTH, WEEK, DAY, HOUR };
247    static const char sufs[] = { 'y', 'm', 'w', 'd', 'h', '\0' };
248
249    qint64 dfld = fld.trimmed().toLongLong();
250
251    char suffix = 's';
252    if (dfld) {
253       for (int pos = 0 ; sufs[pos] ; ++pos) {
254           if (dfld % divs[pos] == 0) {
255              dfld /= divs[pos];
256              suffix = sufs[pos];
257              break;
258           }
259       }
260    }
261    QString msg;
262    if (dfld < 100) {
263       msg = QString("%1%2").arg(dfld).arg(suffix);
264    } else {
265       /* previous check returned a number too big. The original specification perhaps
266          was mixed, like 1d 2h, so we try to match with this routine */
267       dfld = fld.trimmed().toLongLong();
268       msg = "";
269       for (int pos = 0 ; sufs[pos] ; ++pos) {
270           if (dfld / divs[pos] != 0) {
271              msg += QString(" %1%2").arg(dfld / divs[pos]).arg(sufs[pos]);
272              dfld %= divs[pos];
273           }
274       }
275       if (dfld)
276          msg += QString(" %1s").arg(dfld);
277    }
278
279    setNumericFld(index, msg, fld.trimmed().toLongLong());
280 }
281
282 void ItemFormatterBase::setVolStatusFld(int index, const QString &fld, bool center)
283 {
284   QString mp(fld.trimmed());
285    setTextFld(index, volume_status_to_str(mp.toUtf8()), center);
286
287    if (mp == "Append" ) {
288       setBackground(index, Qt::green);
289    } else if (mp == "Error") {
290       setBackground(index, Qt::red);
291    } else if (mp == "Used" || mp == "Full"){
292       setBackground(index, Qt::yellow);
293    } else if (mp == "Read-only" || mp == "Disabled"){
294       setBackground(index, Qt::lightGray);
295    }
296 }
297
298 void ItemFormatterBase::setJobStatusFld(int index, const QString &status, bool center)
299 {
300    /* C (created, not yet running) uses the default background */
301    static QString greenchars("TR");
302    static QString redchars("BEf");
303    static QString yellowchars("eDAFSMmsjdctp");
304
305    setTextFld(index, convertJobStatus(status), center);
306
307    QString st(status.trimmed());
308    if (greenchars.contains(st, Qt::CaseSensitive)) {
309       setBackground(index, Qt::green);
310    } else if (redchars.contains(st, Qt::CaseSensitive)) {
311       setBackground(index, Qt::red);
312    } else if (yellowchars.contains(st, Qt::CaseSensitive)){ 
313       setBackground(index, Qt::yellow);
314    }
315 }
316
317 void ItemFormatterBase::setJobTypeFld(int index, const QString &fld, bool center)
318 {
319    QByteArray jtype(fld.trimmed().toAscii());
320    if (jtype.size()) {
321       setTextFld(index, job_type_to_str(jtype[0]), center);
322    } else {
323       setTextFld(index, "", center);
324    }
325 }
326
327 void ItemFormatterBase::setJobLevelFld(int index, const QString &fld, bool center)
328 {
329    QByteArray lvl(fld.trimmed().toAscii());
330    if (lvl.size()) {
331       setTextFld(index, job_level_to_str(lvl[0]), center);
332    } else {
333       setTextFld(index, "", center);
334    }
335 }
336
337
338
339 /***********************************************
340  *
341  * treeitem formatting routines
342  *
343  ***********************************************/
344 TreeItemFormatter::TreeItemFormatter(QTreeWidgetItem &parent, int indent_level):
345 ItemFormatterBase(),
346 wdg(new QTreeWidgetItem(&parent)),
347 level(indent_level)
348 {
349 }
350
351 void TreeItemFormatter::setText(int index, const QString &fld)
352 {
353    wdg->setData(index, Qt::UserRole, level);
354    wdg->setText(index, fld);
355 }
356
357 void TreeItemFormatter::setTextAlignment(int index, int align)
358 {
359    wdg->setTextAlignment(index, align);
360 }
361
362 void TreeItemFormatter::setBackground(int index, const QBrush &qb)
363 {
364    wdg->setBackground(index, qb);
365 }
366
367 /* at this time we don't sort trees, so this method does nothing */
368 void TreeItemFormatter::setSortValue(int /* index */, const QVariant & /* value */)
369 {
370 }
371
372 /***********************************************
373  *
374  * Specialized table widget used for sorting
375  *
376  ***********************************************/
377 TableItemFormatter::BatSortingTableItem::BatSortingTableItem():
378 QTableWidgetItem(1)
379 {
380 }
381
382 void TableItemFormatter::BatSortingTableItem::setSortData(const QVariant &d)
383 {
384    setData(SORTDATA_ROLE, d);
385 }
386
387 bool TableItemFormatter::BatSortingTableItem::operator< ( const QTableWidgetItem & o ) const 
388 {
389    QVariant my = data(SORTDATA_ROLE);
390    QVariant other = o.data(SORTDATA_ROLE);
391    if (!my.isValid() || !other.isValid() || my.type() != other.type())
392       return QTableWidgetItem::operator< (o); /* invalid combination, revert to default sorting */
393
394    /* 64bit integers must be handled separately, others can be converted to double */
395    if (QVariant::ULongLong == my.type()) {
396       return my.toULongLong() < other.toULongLong(); 
397    } else if (QVariant::LongLong == my.type()) {
398       return my.toLongLong() < other.toLongLong(); 
399    } else if (my.canConvert(QVariant::Double)) {
400       return my.toDouble() < other.toDouble(); 
401    } else {
402       return QTableWidgetItem::operator< (o); /* invalid combination, revert to default sorting */
403    }
404 }
405
406 /***********************************************
407  *
408  * tableitem formatting routines
409  *
410  ***********************************************/
411 TableItemFormatter::TableItemFormatter(QTableWidget &tparent, int trow):
412 ItemFormatterBase(),
413 parent(&tparent),
414 row(trow),
415 last(NULL)
416 {
417 }
418
419 void TableItemFormatter::setText(int col, const QString &fld)
420 {
421    last = new BatSortingTableItem;
422    parent->setItem(row, col, last);
423    last->setText(fld);
424 }
425
426 void TableItemFormatter::setTextAlignment(int /*index*/, int align)
427 {
428    last->setTextAlignment(align);
429 }
430
431 void TableItemFormatter::setBackground(int /*index*/, const QBrush &qb)
432 {
433    last->setBackground(qb);
434 }
435
436 void TableItemFormatter::setSortValue(int /* index */, const QVariant &value )
437 {
438    last->setSortData(value);
439 }
440
441 QTableWidgetItem *TableItemFormatter::widget(int col)
442 {
443    return parent->item(row, col);
444 }
445
446 const QTableWidgetItem *TableItemFormatter::widget(int col) const
447 {
448    return parent->item(row, col);
449 }
450