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