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