]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/util/fmtwidgetitem.cpp
Split messages line by line before sending it to syslog() fix #3325
[bacula/bacula] / bacula / src / qt-console / util / fmtwidgetitem.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2010 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 three of the GNU Affero 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 Affero 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  *
31  *  Helper functions for tree widget formatting
32  *
33  *   Riccardo Ghetta, May 2008
34  *
35  */ 
36
37 #include "bat.h"
38 #include <QTreeWidgetItem>
39 #include <QTableWidget>
40 #include <QTableWidgetItem>
41 #include <QBrush>
42 #include <QString>
43 #include <QStringList>
44 #include <math.h>
45 #include "fmtwidgetitem.h"
46
47 /***********************************************
48  *
49  * common helpers
50  *
51  ***********************************************/
52
53 QString convertJobStatus(const QString &sts)
54 {
55    QString code( sts.trimmed() );
56    if ( code.size() != 1) {
57       return QObject::tr("Invalid job status %1").arg(sts);
58    }
59
60    char buf[256];
61    jobstatus_to_ascii_gui( code[0].toAscii(), buf, sizeof(buf));
62    return QString(buf);
63 }
64
65 /*
66  * disable widget updating
67  */
68 Freeze::Freeze(QWidget &q):
69 qw(&q)
70 {
71    qw->setUpdatesEnabled(false); 
72 }
73
74 Freeze::~Freeze()
75 {
76    if (qw) {
77       qw->setUpdatesEnabled(true); 
78       qw->update();
79    }
80 }
81
82 /***********************************************
83  *
84  * ItemFormatterBase static members
85  *
86  ***********************************************/
87
88 ItemFormatterBase::BYTES_CONVERSION ItemFormatterBase::cnvFlag(BYTES_CONVERSION_IEC);
89
90 /* String to Electronic value based on K=1024 */
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 /* String to human value based on k=1000 */
137 QString 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::setPercent(int index, float value)
197 {
198    char buf[100];
199    bsnprintf(buf, sizeof(buf), "%.2f%%", value);
200    QString val = buf;
201    QString pix;
202    if (value < 8) {
203       pix = ":images/0p.png";
204    } else if (value < 24) {
205       pix = ":images/16p.png";
206    } else if (value < 40) {
207       pix = ":images/32p.png";
208    } else if (value < 56) {
209       pix = ":images/48p.png";
210    } else if (value < 72) {
211       pix = ":images/64p.png";
212    } else if (value < 88) {
213       pix = ":images/80p.png";
214    } else {
215       pix = ":images/96p.png";
216    }
217    setPixmap(index, QPixmap(pix), val);
218    //setSortValue(index, (int) value);
219    //setBackground(index, Qt::green);
220 }
221
222 /* By default, the setPixmap implementation with tooltip don't implement
223  * the tooltip stuff
224  */
225 void ItemFormatterBase::setPixmap(int index, const QPixmap &pix, 
226                                   const QString & /* tip */)
227 {
228    setPixmap(index, pix);
229 }
230
231 void ItemFormatterBase::setInChanger(int index, const QString &InChanger)
232 {
233    setPixmap(index, QPixmap(":images/inflag"+InChanger+".png"));
234    //setSortValue(index, InChanger.toInt() );
235 }
236
237 void ItemFormatterBase::setFileType(int index, const QString &type)
238 {
239    setPixmap(index, QPixmap(":images/"+type+".png"));
240    //setSortValue(index, InChanger.toInt() );
241 }
242
243 void ItemFormatterBase::setTextFld(int index, const QString &fld, bool center)
244 {
245    setText(index, fld.trimmed());
246    if (center) {
247       setTextAlignment(index, Qt::AlignCenter);
248    }
249 }
250
251 void ItemFormatterBase::setDateFld(int index, utime_t fld, bool center)
252 {
253    char buf[200];
254    bstrutime(buf, sizeof(buf), fld);
255    setText(index, QString(buf).trimmed());
256    if (center) {
257       setTextAlignment(index, Qt::AlignCenter);
258    }
259 }
260
261 void ItemFormatterBase::setRightFld(int index, const QString &fld)
262 {
263    setText(index, fld.trimmed());
264    setTextAlignment(index, Qt::AlignRight | Qt::AlignVCenter);
265 }
266
267 void ItemFormatterBase::setBoolFld(int index, const QString &fld, bool center)
268 {
269    if (fld.trimmed().toInt())
270      setTextFld(index, QObject::tr("Yes"), center);
271    else
272      setTextFld(index, QObject::tr("No"), center);
273 }
274
275 void ItemFormatterBase::setBoolFld(int index, int fld, bool center)
276 {
277    if (fld)
278      setTextFld(index, QObject::tr("Yes"), center);
279    else
280      setTextFld(index, QObject::tr("No"), center);
281 }
282
283 void ItemFormatterBase::setNumericFld(int index, const QString &fld)
284 {
285    setRightFld(index, fld.trimmed());
286    setSortValue(index, fld.toDouble() );
287 }
288
289 void ItemFormatterBase::setNumericFld(int index, const QString &fld, const QVariant &sortval)
290 {
291    setRightFld(index, fld.trimmed());
292    setSortValue(index, sortval );
293 }
294
295 void ItemFormatterBase::setBytesFld(int index, const QString &fld)
296 {
297    qint64 qfld = fld.trimmed().toLongLong();
298    QString msg;
299    switch (cnvFlag) {
300    case BYTES_CONVERSION_NONE:
301       msg = QString::number(qfld);
302       break;
303    case BYTES_CONVERSION_IEC:
304       msg = convertBytesIEC(qfld);
305       break;
306    case BYTES_CONVERSION_SI:
307       msg = convertBytesSI(qfld);
308       break;
309    default:
310       msg = " ";
311       break;
312    }
313
314    setNumericFld(index, msg, QVariant(qfld));
315 }
316
317 void ItemFormatterBase::setDurationFld(int index, const QString &fld)
318 {
319    static const qint64 HOUR = Q_INT64_C(3600);
320    static const qint64 DAY = HOUR * 24;
321    static const qint64 WEEK = DAY * 7;
322    static const qint64 MONTH = DAY * 30;
323    static const qint64 YEAR = DAY * 365;
324    static const qint64 divs[] = { YEAR, MONTH, WEEK, DAY, HOUR };
325    static const char sufs[] = { 'y', 'm', 'w', 'd', 'h', '\0' };
326
327    qint64 dfld = fld.trimmed().toLongLong();
328
329    char suffix = 's';
330    if (dfld) {
331       for (int pos = 0 ; sufs[pos] ; ++pos) {
332           if (dfld % divs[pos] == 0) {
333              dfld /= divs[pos];
334              suffix = sufs[pos];
335              break;
336           }
337       }
338    }
339    QString msg;
340    if (dfld < 100) {
341       msg = QString("%1%2").arg(dfld).arg(suffix);
342    } else {
343       /* previous check returned a number too big. The original specification perhaps
344          was mixed, like 1d 2h, so we try to match with this routine */
345       dfld = fld.trimmed().toLongLong();
346       msg = "";
347       for (int pos = 0 ; sufs[pos] ; ++pos) {
348           if (dfld / divs[pos] != 0) {
349              msg += QString(" %1%2").arg(dfld / divs[pos]).arg(sufs[pos]);
350              dfld %= divs[pos];
351           }
352       }
353       if (dfld)
354          msg += QString(" %1s").arg(dfld);
355    }
356
357    setNumericFld(index, msg, QVariant(fld.trimmed().toLongLong()));
358 }
359
360 void ItemFormatterBase::setVolStatusFld(int index, const QString &fld, bool center)
361 {
362   QString mp(fld.trimmed());
363    setTextFld(index, volume_status_to_str(mp.toUtf8()), center);
364
365    if (mp == "Append" ) {
366       setBackground(index, Qt::green);
367    } else if (mp == "Error") {
368       setBackground(index, Qt::red);
369    } else if (mp == "Used" || mp == "Full"){
370       setBackground(index, Qt::yellow);
371    } else if (mp == "Read-only" || mp == "Disabled"){
372       setBackground(index, Qt::lightGray);
373    }
374 }
375
376 void ItemFormatterBase::setJobStatusFld(int index, const QString &status, bool center)
377 {
378    /* C (created, not yet running) uses the default background */
379    static QString greenchars("TR");
380    static QString redchars("BEf");
381    static QString yellowchars("eDAFSMmsjdctp");
382
383    setTextFld(index, convertJobStatus(status), center);
384
385    QString st(status.trimmed());
386    if (greenchars.contains(st, Qt::CaseSensitive)) {
387       setBackground(index, Qt::green);
388    } else if (redchars.contains(st, Qt::CaseSensitive)) {
389       setBackground(index, Qt::red);
390    } else if (yellowchars.contains(st, Qt::CaseSensitive)){ 
391       setBackground(index, Qt::yellow);
392    }
393 }
394
395 void ItemFormatterBase::setJobTypeFld(int index, const QString &fld, bool center)
396 {
397    QByteArray jtype(fld.trimmed().toAscii());
398    if (jtype.size()) {
399       setTextFld(index, job_type_to_str(jtype[0]), center);
400    } else {
401       setTextFld(index, "", center);
402    }
403 }
404
405 void ItemFormatterBase::setJobLevelFld(int index, const QString &fld, bool center)
406 {
407    QByteArray lvl(fld.trimmed().toAscii());
408    if (lvl.size()) {
409       setTextFld(index, job_level_to_str(lvl[0]), center);
410    } else {
411       setTextFld(index, "", center);
412    }
413 }
414
415
416
417 /***********************************************
418  *
419  * treeitem formatting routines
420  *
421  ***********************************************/
422 TreeItemFormatter::TreeItemFormatter(QTreeWidgetItem &parent, int indent_level):
423 ItemFormatterBase(),
424 wdg(new QTreeWidgetItem(&parent)),
425 level(indent_level)
426 {
427 }
428
429 void TreeItemFormatter::setText(int index, const QString &fld)
430 {
431    wdg->setData(index, Qt::UserRole, level);
432    wdg->setText(index, fld);
433 }
434
435 void TreeItemFormatter::setTextAlignment(int index, int align)
436 {
437    wdg->setTextAlignment(index, align);
438 }
439
440 void TreeItemFormatter::setBackground(int index, const QBrush &qb)
441 {
442    wdg->setBackground(index, qb);
443 }
444
445 /* at this time we don't sort trees, so this method does nothing */
446 void TreeItemFormatter::setSortValue(int /* index */, const QVariant & /* value */)
447 {
448 }
449
450 void TreeItemFormatter::setPixmap(int index, const QPixmap &pix)
451 {
452    wdg->setIcon(index, QIcon(pix));
453 }
454
455 /***********************************************
456  *
457  * Specialized table widget used for sorting
458  *
459  ***********************************************/
460 TableItemFormatter::BatSortingTableItem::BatSortingTableItem():
461 QTableWidgetItem(1)
462 {
463 }
464
465 void TableItemFormatter::BatSortingTableItem::setSortData(const QVariant &d)
466 {
467    setData(SORTDATA_ROLE, d);
468 }
469
470 bool TableItemFormatter::BatSortingTableItem::operator< ( const QTableWidgetItem & o ) const 
471 {
472    QVariant my = data(SORTDATA_ROLE);
473    QVariant other = o.data(SORTDATA_ROLE);
474    if (!my.isValid() || !other.isValid() || my.type() != other.type())
475       return QTableWidgetItem::operator< (o); /* invalid combination, revert to default sorting */
476
477    /* 64bit integers must be handled separately, others can be converted to double */
478    if (QVariant::ULongLong == my.type()) {
479       return my.toULongLong() < other.toULongLong(); 
480    } else if (QVariant::LongLong == my.type()) {
481       return my.toLongLong() < other.toLongLong(); 
482    } else if (my.canConvert(QVariant::Double)) {
483       return my.toDouble() < other.toDouble(); 
484    } else {
485       return QTableWidgetItem::operator< (o); /* invalid combination, revert to default sorting */
486    }
487 }
488
489 /***********************************************
490  *
491  * tableitem formatting routines
492  *
493  ***********************************************/
494 TableItemFormatter::TableItemFormatter(QTableWidget &tparent, int trow):
495 ItemFormatterBase(),
496 parent(&tparent),
497 row(trow),
498 last(NULL)
499 {
500 }
501
502 void TableItemFormatter::setPixmap(int index, const QPixmap &pix)
503 {
504 // Centered, but not sortable !
505    QLabel *lbl = new QLabel();
506    lbl->setAlignment(Qt::AlignCenter);
507    lbl->setPixmap(pix);
508    parent->setCellWidget(row, index, lbl);
509 }
510
511 void TableItemFormatter::setPixmap(int index, const QPixmap &pix, 
512                                    const QString &tips)
513 {
514 // Centered, but not sortable !
515    QLabel *lbl = new QLabel();
516    lbl->setAlignment(Qt::AlignCenter);
517    lbl->setPixmap(pix);
518    if (!tips.isEmpty()) {
519       lbl->setToolTip(tips);
520    }
521    parent->setCellWidget(row, index, lbl);
522
523 //   last = new BatSortingTableItem;
524 //   parent->setItem(row, index, last);
525 //   last->setIcon(pix);
526 }
527
528 void TableItemFormatter::setText(int col, const QString &fld)
529 {
530    last = new BatSortingTableItem;
531    parent->setItem(row, col, last);
532    last->setText(fld);
533 }
534
535 void TableItemFormatter::setTextAlignment(int /*index*/, int align)
536 {
537    last->setTextAlignment(align);
538 }
539
540 void TableItemFormatter::setBackground(int /*index*/, const QBrush &qb)
541 {
542    last->setBackground(qb);
543 }
544
545 void TableItemFormatter::setSortValue(int /* index */, const QVariant &value )
546 {
547    last->setSortData(value);
548 }
549
550 QTableWidgetItem *TableItemFormatter::widget(int col)
551 {
552    return parent->item(row, col);
553 }
554
555 const QTableWidgetItem *TableItemFormatter::widget(int col) const
556 {
557    return parent->item(row, col);
558 }