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