[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bacula-devel] patch: improve formatting routines and joblist display for bat


Notable changes:

mainwin/fmtwidgetitem:
- added a formatter for table widgets and refactored tree formatter
Most of the code is now common and you can switch between tree and table with very little effort. - bytes formatter aligned with previous work of Dirk. Now respects prefs selection (BTW, IEC units, e.g. MiB, are 1024-based) - redone duration formatting. Now if the routine can't find an exact match or the resulting number is too large it breaks the duration in pieces. This should handle nicely both single number (e.g. 1y) and the multi-number (1y 2d) cases. Of course, while the formatter will produce a reasonable break up, it can't be always the same you specified.
As an example, try specifying 1y 22d.
I've also used one-letter abbreviations to avoid using too much space with multi-number formats.

joblist:
- used new formatter
- selection by row
- added verify level decoding
- changed the order by clause to place queued jobs at top, white-colored.
- split up populate in three to be easier to follow

fileset:
- selection by row

Ciao,
Riccardo


Index: bacula/src/qt-console/mainwin.h
===================================================================
--- bacula/src/qt-console/mainwin.h	(revision 6973)
+++ bacula/src/qt-console/mainwin.h	(working copy)
@@ -59,8 +59,6 @@
    void hashInsert(QTreeWidgetItem *, Pages *);
    void hashRemove(Pages *);
    void hashRemove(QTreeWidgetItem *, Pages *);
-   void hrConvert(QString &, qlonglong &);
-   void hrConvertSeconds(QString &, qlonglong &);
    Console *currentConsole();
    QTreeWidgetItem *currentTopItem();
    Pages* getFromHash(QTreeWidgetItem *);
@@ -101,7 +99,6 @@
    bool m_rtRestore1Debug;
    bool m_rtRestore2Debug;
    bool m_rtRestore3Debug;
-   int m_radioConvert;
    bool m_openBrowser;
    bool m_openPlot;
    bool m_openDirStat;
Index: bacula/src/qt-console/storage/storage.cpp
===================================================================
--- bacula/src/qt-console/storage/storage.cpp	(revision 6973)
+++ bacula/src/qt-console/storage/storage.cpp	(working copy)
@@ -95,7 +95,7 @@
    mp_treeWidget->setHeaderLabels(headerlist);
 
    foreach(QString storageName, m_console->storage_list){
-      ItemFormatter storageItem(*topItem, 1);
+      TreeItemFormatter storageItem(*topItem, 1);
       storageItem.setTextFld(0, storageName);
       storageItem.widget()->setExpanded(true);
 
@@ -167,7 +167,7 @@
          /* Iterate through fields in the record */
          QStringListIterator fld(fieldlist);
          int index = 0;
-	 ItemFormatter fmt(*parent, 2);
+	 TreeItemFormatter fmt(*parent, 2);
 
          /* volname */
          fmt.setTextFld(index++, fld.next()); 
Index: bacula/src/qt-console/medialist/medialist.cpp
===================================================================
--- bacula/src/qt-console/medialist/medialist.cpp	(revision 6973)
+++ bacula/src/qt-console/medialist/medialist.cpp	(working copy)
@@ -146,7 +146,7 @@
 	       continue; // some fields missing, ignore row
 
             int index = 0;
-	    ItemFormatter mediaitem(*pooltreeitem, 2);
+	    TreeItemFormatter mediaitem(*pooltreeitem, 2);
   
             /* Iterate through fields in the record */
 	    QStringListIterator fld(fieldlist);
Index: bacula/src/qt-console/mainwin.cpp
===================================================================
--- bacula/src/qt-console/mainwin.cpp	(revision 6973)
+++ bacula/src/qt-console/mainwin.cpp	(working copy)
@@ -54,6 +54,7 @@
 #include "jobgraphs/jobplot.h"
 #endif
 #include "status/dirstat.h"
+#include "util/fmtwidgetitem.h"
 
 /* 
  * Daemon message callback
@@ -674,13 +675,16 @@
    prefs.rtRestore1CheckBox->setCheckState(m_rtRestore1Debug ? Qt::Checked : Qt::Unchecked);
    prefs.rtRestore2CheckBox->setCheckState(m_rtRestore2Debug ? Qt::Checked : Qt::Unchecked);
    prefs.rtRestore3CheckBox->setCheckState(m_rtRestore3Debug ? Qt::Checked : Qt::Unchecked);
-   if (m_radioConvert == 0) {
+   switch (ItemFormatterBase::getBytesConversion()) {
+   case ItemFormatterBase::BYTES_CONVERSION_NONE:
       prefs.radioConvertOff->setChecked(Qt::Checked);
-   } else if (m_radioConvert == 1){
+      break;
+   case ItemFormatterBase::BYTES_CONVERSION_IEC:
       prefs.radioConvertIEC->setChecked(Qt::Checked);
-   } else {
-      m_radioConvert = 2;
+      break;
+   default:
       prefs.radioConvertStandard->setChecked(Qt::Checked);
+      break;
    }
    prefs.openPlotCheckBox->setCheckState(m_openPlot ? Qt::Checked : Qt::Unchecked);
    prefs.openBrowserCheckBox->setCheckState(m_openBrowser ? Qt::Checked : Qt::Unchecked);
@@ -725,11 +729,11 @@
    mainWin->m_rtRestore2Debug = this->rtRestore2CheckBox->checkState() == Qt::Checked;
    mainWin->m_rtRestore3Debug = this->rtRestore3CheckBox->checkState() == Qt::Checked;
    if (this->radioConvertOff->isChecked()) {
-      mainWin->m_radioConvert = 0;
+      ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_NONE);
    } else if (this->radioConvertIEC->isChecked()){
-      mainWin->m_radioConvert = 1;
+      ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_IEC);
    } else {
-      mainWin->m_radioConvert = 2;
+      ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_SI);
    }
    mainWin->m_openPlot = this->openPlotCheckBox->checkState() == Qt::Checked;
    mainWin->m_openBrowser = this->openBrowserCheckBox->checkState() == Qt::Checked;
@@ -757,7 +761,7 @@
    settings.endGroup();
    settings.beginGroup("Misc");
    settings.setValue("longList", mainWin->m_longList);
-   settings.setValue("byteConvert", mainWin->m_radioConvert);
+   settings.setValue("byteConvert", ItemFormatterBase::getBytesConversion());
    settings.setValue("openplot", mainWin->m_openPlot);
    settings.setValue("openbrowser", mainWin->m_openBrowser);
    settings.setValue("opendirstat", mainWin->m_openDirStat);
@@ -812,7 +816,9 @@
    settings.endGroup();
    settings.beginGroup("Misc");
    m_longList = settings.value("longList", false).toBool();
-   m_radioConvert = settings.value("byteConvert", false).toInt();
+   ItemFormatterBase::setBytesConversion(
+	 (ItemFormatterBase::BYTES_CONVERSION) settings.value("byteConvert", 
+	 ItemFormatterBase::BYTES_CONVERSION_IEC).toInt());
    m_openPlot = settings.value("openplot", false).toBool();
    m_openBrowser = settings.value("openbrowser", false).toBool();
    m_openDirStat = settings.value("opendirstat", false).toBool();
@@ -833,70 +839,4 @@
    settings.endGroup();
 }
 
-void MainWin::hrConvert(QString &ret, qlonglong &inval)
-{
-   double net = 0;
-   qlonglong base;
-   QStringList suflist;
 
-   if (m_radioConvert == 0) {
-      ret =  QString("%1").arg(inval);
-      return;
-   } else if (m_radioConvert == 1){
-      base = 1000;
-      suflist = (QStringList() << "B" << "KiB" << "MiB" << "GiB" << "TiB" << "PiB" << "EiB" << "ZiB");
-   } else {
-      base = 1024;
-      suflist = (QStringList() << "B" << "KB" << "MB" << "GB" << "TB" << "PB" << "EB" << "ZB");
-   }
-   qlonglong running = base;
-   bool done = false;
-   int count = 1;
-   while (done == false) {
-      QString test1 =  QString("%1").arg(inval);
-      QString test2 =  QString("%1").arg(running);
-      if (float(inval) < (float)(running)) {
-         done = true;
-         ret = suflist[count - 1];
-         net = (float)inval / (float)(running/base);
-      }
-      count += 1;
-      if (count > suflist.count()) done = true;
-      running *= base;
-   }
-   char format = 'f';
-   if (net != 0)
-      ret =  QString("%1 %2")
-                  .arg(net, 0, format, 2, QLatin1Char(' '))
-                  .arg(ret);
-   else ret = "0 B";
-}
-
-void MainWin::hrConvertSeconds(QString &ret, qlonglong &inval)
-{
-   double net = 0;
-   QList<qlonglong> durations;
-   durations.append(1);
-   durations.append(60);
-   durations.append(3600);
-   durations.append(86400);
-   durations.append(2592000);
-   durations.append(31536000);
-   QStringList abbrlist = (QStringList() << "Sec" << "Min" << "Hrs" << "Days" << "Mnth" << "Yrs");
-   bool done = false;
-   int count = 1;
-   while (done == false) {
-      QString test1 =  QString("%1").arg(inval);
-      QString test2 =  QString("%1").arg(durations[count]);
-      if ((inval < durations[count]) || (count >= abbrlist.count() - 1)) { 
-         done = true;
-         net = (float)inval / (float)(durations[count - 1]);
-         if (net != 0)
-            ret =  QString("%1 %2")
-                  .arg(net, 0, 'f', 2, QLatin1Char(' '))
-                  .arg(abbrlist[count - 1]);
-         else ret = "0 S";
-      }
-      count += 1;
-   }
-}
Index: bacula/src/qt-console/joblist/joblist.cpp
===================================================================
--- bacula/src/qt-console/joblist/joblist.cpp	(revision 6973)
+++ bacula/src/qt-console/joblist/joblist.cpp	(working copy)
@@ -40,6 +40,7 @@
 #ifdef HAVE_QWT
 #include "jobgraphs/jobplot.h"
 #endif
+#include "util/fmtwidgetitem.h"
 
 /*
  * Constructor for the class
@@ -106,14 +107,120 @@
  */
 void JobList::populateTable()
 {
-   QStringList results;
-   QString resultline;
-   QBrush blackBrush(Qt::black);
-
    if (!m_console->preventInUseConnect())
        return;
 
    /* Can't do this in constructor because not neccesarily conected in constructor */
+   prepareFilterWidgets();
+
+   /* Set up query */
+   QString query;
+   fillQueryString(query);
+
+   /* Set up the Header for the table */
+   QStringList headerlist = (QStringList()
+      << tr("Job Id") << tr("Job Name") << tr("Client") << tr("Job Starttime") 
+      << tr("Job Type") << tr("Job Level") << tr("Job Files") 
+      << tr("Job Bytes") << tr("Job Status")  << tr("Purged") << tr("File Set"));
+
+   m_jobIdIndex = headerlist.indexOf(tr("Job Id"));
+   m_purgedIndex = headerlist.indexOf(tr("Purged"));
+   m_typeIndex = headerlist.indexOf(tr("Job Type"));
+   m_statusIndex = headerlist.indexOf(tr("Job Status"));
+   m_startIndex = headerlist.indexOf(tr("Job Starttime"));
+   m_filesIndex = headerlist.indexOf(tr("Job Files"));
+   m_bytesIndex = headerlist.indexOf(tr("Job Bytes"));
+
+   /* Initialize the QTableWidget */
+   m_checkCurrentWidget = false;
+   mp_tableWidget->clear();
+   m_checkCurrentWidget = true;
+   mp_tableWidget->setColumnCount(headerlist.size());
+   mp_tableWidget->setHorizontalHeaderLabels(headerlist);
+   mp_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+   mp_tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+
+   if (mainWin->m_sqlDebug) {
+      Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
+   }
+
+   QStringList results;
+   if (m_console->sql_cmd(query, results)) {
+      m_resultCount = results.count();
+
+      QStringList fieldlist;
+      mp_tableWidget->setRowCount(results.size());
+
+      int row = 0;
+      /* Iterate through the record returned from the query */
+      QString resultline;
+      foreach (resultline, results) {
+         fieldlist = resultline.split("\t");
+         if (fieldlist.size() < 12)
+	    continue; // some fields missing, ignore row
+
+	 TableItemFormatter jobitem(*mp_tableWidget, row);
+  
+         /* Iterate through fields in the record */
+	 QStringListIterator fld(fieldlist);
+         int col = 0;
+
+	 /* job id */
+         jobitem.setNumericFld(col++, fld.next());
+
+	 /* job name */
+         jobitem.setTextFld(col++, fld.next());
+
+	 /* client */
+         jobitem.setTextFld(col++, fld.next());
+
+	 /* job starttime */
+         jobitem.setTextFld(col++, fld.next(), true);
+
+	 /* job type */
+         jobitem.setJobTypeFld(col++, fld.next());
+
+	 /* job level */
+         jobitem.setJobLevelFld(col++, fld.next());
+
+	 /* job files */
+         jobitem.setNumericFld(col++, fld.next());
+
+	 /* job bytes */
+         jobitem.setBytesFld(col++, fld.next());
+
+	 /* job status */
+	 QString shortstatus(fld.next());
+	 QString longstatus(fld.next());
+         jobitem.setJobStatusFld(col++, shortstatus, longstatus);
+
+	 /* purged */
+         if (fld.next().toInt())
+	    jobitem.setTextFld(col++, tr("IS"), true);
+	 else
+	    jobitem.setTextFld(col++, tr("NOT"), true);
+
+	 /* fileset */
+         jobitem.setTextFld(col++, fld.next());
+
+         row++;
+      }
+   } 
+   /* Resize the columns */
+   mp_tableWidget->resizeColumnsToContents();
+   mp_tableWidget->resizeRowsToContents();
+   mp_tableWidget->verticalHeader()->hide();
+   if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){
+      /* for context sensitive searches, let the user know if there were no
+       * results */
+      QMessageBox::warning(this, "Bat",
+          tr("The Jobs query returned no results.\n"
+         "Press OK to continue?"), QMessageBox::Ok );
+   }
+}
+
+void JobList::prepareFilterWidgets()
+{
    if (!m_populated) {
       clientComboBox->addItem(tr("Any"));
       clientComboBox->addItems(m_console->client_list);
@@ -150,9 +257,11 @@
       statusComboBox->addItem(tr("Any"));
       statusComboBox->addItems(statusLongList);
    }
+}
 
-   /* Set up query */
-   QString query("");
+void JobList::fillQueryString(QString &query)
+{
+   query = "";
    int volumeIndex = volumeComboBox->currentIndex();
    if (volumeIndex != -1)
       m_mediaName = volumeComboBox->itemText(volumeIndex);
@@ -221,126 +330,15 @@
       }
    }
    /* Descending */
-   query += " ORDER BY Job.Starttime DESC, Job.JobId DESC";
+   query += " ORDER BY Job.Starttime=0 DESC, Job.Starttime DESC, Job.JobId DESC";
    /* If Limit check box for limit records returned is checked  */
    if (limitCheckBox->checkState() == Qt::Checked) {
       QString limit;
       limit.setNum(limitSpinBox->value());
       query += " LIMIT " + limit;
    }
-
-   /* Set up the Header for the table */
-   QStringList headerlist = (QStringList()
-      << tr("Job Id") << tr("Job Name") << tr("Client") << tr("Job Starttime") 
-      << tr("Job Type") << tr("Job Level") << tr("Job Files") 
-      << tr("Job Bytes") << tr("Job Status")  << tr("Purged") << tr("File Set"));
-   m_jobIdIndex = headerlist.indexOf(tr("Job Id"));
-   m_purgedIndex = headerlist.indexOf(tr("Purged"));
-   m_typeIndex = headerlist.indexOf(tr("Job Type"));
-   m_statusIndex = headerlist.indexOf(tr("Job Status"));
-   m_startIndex = headerlist.indexOf(tr("Job Starttime"));
-   m_filesIndex = headerlist.indexOf(tr("Job Files"));
-   m_bytesIndex = headerlist.indexOf(tr("Job Bytes"));
-   int jobLevelIndex = headerlist.indexOf(tr("Job Level"));
-
-   /* Initialize the QTableWidget */
-   m_checkCurrentWidget = false;
-   mp_tableWidget->clear();
-   m_checkCurrentWidget = true;
-   mp_tableWidget->setColumnCount(headerlist.size());
-   mp_tableWidget->setHorizontalHeaderLabels(headerlist);
-
-   if (mainWin->m_sqlDebug) {
-      Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
-   }
-   if (m_console->sql_cmd(query, results)) {
-      m_resultCount = results.count();
-
-      QTableWidgetItem* p_tableitem;
-      QString field;
-      QStringList fieldlist;
-      mp_tableWidget->setRowCount(results.size());
-
-      int row = 0;
-      /* Iterate through the record returned from the query */
-      foreach (resultline, results) {
-         fieldlist = resultline.split("\t");
-         int column = 0;
-         bool m_statusIndexDone = false;
-         QString statusCode("");
-         /* Iterate through fields in the record */
-         foreach (field, fieldlist) {
-            field = field.trimmed();  /* strip leading & trailing spaces */
-            if ((column == m_statusIndex) && (!m_statusIndexDone)){
-               m_statusIndexDone = true;
-               statusCode = field;
-            } else {
-               p_tableitem = new QTableWidgetItem(field, 1);
-               p_tableitem->setFlags(Qt::ItemIsSelectable);
-               p_tableitem->setForeground(blackBrush);
-               mp_tableWidget->setItem(row, column, p_tableitem);
-               if (column == m_statusIndex)
-                  setStatusColor(p_tableitem, statusCode);
-               if (column == m_bytesIndex) {
-                  QString text;
-                  bool okay;
-                  qlonglong bytes = field.toULongLong(&okay);
-                  if (okay){
-                     QString test =  QString("%1").arg(bytes);
-                     mainWin->hrConvert(text, bytes);
-                     p_tableitem->setText(text);
-                  } else { Pmsg1(000, "conversion error %s\n", field.toUtf8().data()); }
-               } else if (column == m_purgedIndex) {
-                  bool okay;
-                  int isPurged = field.toInt(&okay);
-                  if (okay){
-                     if (isPurged) { p_tableitem->setText(tr("IS"));
-                     } else { p_tableitem->setText(tr("NOT")); }
-                  }
-               } else if (column == m_typeIndex) {
-                  if (field == "B") { p_tableitem->setText(tr("Backup")); }
-                  else if (field == "R") { p_tableitem->setText(tr("Restore")); }
-               } else if (column == jobLevelIndex) {
-                  if (field == "F") { p_tableitem->setText("Full"); }
-                  else if (field == "D") { p_tableitem->setText("Diff"); }
-                  else if (field == "I") { p_tableitem->setText("Incr"); }
-               }   
-               if ((column == m_bytesIndex) || (column == m_filesIndex)){
-                  p_tableitem->setTextAlignment(Qt::AlignRight);
-               }
-               column++;
-            }
-         }
-         row++;
-      }
-   } 
-   /* Resize the columns */
-   mp_tableWidget->resizeColumnsToContents();
-   mp_tableWidget->resizeRowsToContents();
-   mp_tableWidget->verticalHeader()->hide();
-   if ((m_mediaName != tr("Any")) && (m_resultCount == 0)){
-      /* for context sensitive searches, let the user know if there were no
-       * results */
-      QMessageBox::warning(this, "Bat",
-          tr("The Jobs query returned no results.\n"
-         "Press OK to continue?"), QMessageBox::Ok );
-   }
 }
 
-void JobList::setStatusColor(QTableWidgetItem *item, QString &field)
-{
-   QString greenchars("TCR");
-   QString redchars("BEf");
-   QString yellowchars("eDAFSMmsjdctp");
-   if (greenchars.contains(field, Qt::CaseSensitive)) {
-      item->setBackground(Qt::green);
-   } else if (redchars.contains(field, Qt::CaseSensitive)) {
-      item->setBackground(Qt::red);
-   } else if (yellowchars.contains(field, Qt::CaseSensitive)){ 
-      item->setBackground(Qt::yellow);
-   }
-}
-
 /*
  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
  * The tree has been populated.
Index: bacula/src/qt-console/joblist/joblist.h
===================================================================
--- bacula/src/qt-console/joblist/joblist.h	(revision 6973)
+++ bacula/src/qt-console/joblist/joblist.h	(working copy)
@@ -73,9 +73,10 @@
 
 private:
    void createConnections();
-   void setStatusColor(QTableWidgetItem *item, QString &field);
    void writeSettings();
    void readSettings();
+   void prepareFilterWidgets();
+   void fillQueryString(QString &query);
    void selectedJobsGet();
    QSplitter *m_splitter;
    QString m_groupText;
Index: bacula/src/qt-console/util/fmtwidgetitem.h
===================================================================
--- bacula/src/qt-console/util/fmtwidgetitem.h	(revision 6973)
+++ bacula/src/qt-console/util/fmtwidgetitem.h	(working copy)
@@ -34,25 +34,33 @@
  */
 
 class QTreeWidgetItem;
+class QTableWidget;
+class QTableWidgetItem;
 class QString;
+class QBrush;
 
 /*
- * This class can be used instead of QTreeWidgetItem (it allocates one internally,
- * to format data fields.
- * All setXXXFld routines receive a column index and the unformatted string value.
+ * base class for formatters
+ *
  */
-class ItemFormatter
+class ItemFormatterBase
 {
 public:
+  enum BYTES_CONVERSION {
+    BYTES_CONVERSION_NONE,
+    BYTES_CONVERSION_IEC,
+    BYTES_CONVERSION_SI,
+  };
 
-   ItemFormatter(QTreeWidgetItem &parent, int indent_level);
+public:
+   virtual ~ItemFormatterBase(); 
 
    /* Prints Yes if fld is != 0, No otherwise. Centers field if center true*/
    void setBoolFld(int index, const QString &fld, bool center = true);
    void setBoolFld(int index, int fld, bool center = true);
 
    /* Normal text field. Centers field if center true*/
-   void setTextFld(int index, const QString &fld, bool center = false);
+   virtual void setTextFld(int index, const QString &fld, bool center = false) = 0;
 
    /* Right-aligned text field.*/
    void setNumericFld(int index, const QString &fld);
@@ -65,91 +73,93 @@
 
    /* fld value interpreted as volume status. Colored accordingly */
    void setVolStatusFld(int index, const QString &fld, bool center = true);
+  
+   /* fld value interpreted as job status. Colored accordingly */
+   void setJobStatusFld(int index, const QString &shortStatus, const QString &longstatus, 
+			bool center = true);
+  
+   /* fld value interpreted as job type. */
+   void setJobTypeFld(int index, const QString &fld, bool center = false);
+  
+   /* fld value interpreted as job level. */
+   void setJobLevelFld(int index, const QString &fld, bool center = false);
+  
+   static void setBytesConversion(BYTES_CONVERSION b) {
+      cnvFlag = b;
+   }
+   static BYTES_CONVERSION getBytesConversion() {
+      return cnvFlag;
+   }
 
-   /* access internal widget */
-   QTreeWidgetItem *widget() { return wdg; }
-   const QTreeWidgetItem *widget() const { return wdg; }
+protected:
+   /* only derived classes can create one of these */
+   ItemFormatterBase();
 
+   virtual void setTextAlignment(int index, int align) = 0;
+   virtual void setBackground(int index, const QBrush &) = 0;
+
 private:
-   QTreeWidgetItem *wdg;
-   int level;
-};
+   /* bytes formatted as power-of-two with IEC suffixes (KiB, MiB, and so on) */
+   static QString convertBytesIEC(qint64 fld);
 
-#endif /* _FMTWIDGETITEM_H_ */
-#ifndef _FMTWIDGETITEM_H_
-#define _FMTWIDGETITEM_H_
-/*
-   Bacula® - The Network Backup Solution
+   /* bytes formatted as power-of-ten with SI suffixes (kB, MB, and so on) */
+   static QString convertBytesSI(qint64 fld);
 
-   Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
+private:
+   static BYTES_CONVERSION cnvFlag;
+};
 
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation and included
-   in the file LICENSE.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Bacula® is a registered trademark of John Walker.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@xxxxxxxxxxxxxx
-*/
 /*
- *   Version $Id$
- *
- *   TreeView formatting helpers - Riccardo Ghetta, May 2008 
- */
-
-class QTreeWidgetItem;
-class QString;
-
-/*
  * This class can be used instead of QTreeWidgetItem (it allocates one internally,
  * to format data fields.
  * All setXXXFld routines receive a column index and the unformatted string value.
  */
-class ItemFormatter
+class TreeItemFormatter : public ItemFormatterBase
 {
 public:
 
-   ItemFormatter(QTreeWidgetItem &parent, int indent_level);
+   TreeItemFormatter(QTreeWidgetItem &parent, int indent_level);
 
-   /* Prints Yes if fld is != 0, No otherwise. Centers field if center true*/
-   void setBoolFld(int index, const QString &fld, bool center = true);
+   virtual void setTextFld(int index, const QString &fld, bool center = false);
 
-   /* Normal text field. Centers field if center true*/
-   void setTextFld(int index, const QString &fld, bool center = false);
-
-   /* Right-aligned text field.*/
-   void setNumericFld(int index, const QString &fld);
-
-   /* fld value interpreted as bytes and formatted with size suffixes */
-   void setBytesFld(int index, const QString &fld);
-
-   /* fld value interpreted as seconds and formatted with y,m,w,h suffixes */
-   void setDurationFld(int index, const QString &fld);
-
-   /* fld value interpreted as volume status. Colored accordingly */
-   void setVolStatusFld(int index, const QString &fld, bool center = true);
-
    /* access internal widget */
    QTreeWidgetItem *widget() { return wdg; }
    const QTreeWidgetItem *widget() const { return wdg; }
 
+protected:
+   virtual void setTextAlignment(int index, int align);
+   virtual void setBackground(int index, const QBrush &);
+
 private:
    QTreeWidgetItem *wdg;
    int level;
 };
 
+/*
+ * This class can be used instead of QTableWidgetItem (it allocates one internally,
+ * to format data fields.
+ * All setXXXFld routines receive the column and the unformatted string value.
+ */
+class TableItemFormatter : public ItemFormatterBase
+{
+public:
+
+   TableItemFormatter(QTableWidget &parent, int row);
+
+   virtual void setTextFld(int col, const QString &fld, bool center = false);
+
+   /* access internal widget at column col*/
+   QTableWidgetItem *widget(int col);
+   const QTableWidgetItem *widget(int col) const;
+
+protected:
+   virtual void setTextAlignment(int index, int align);
+   virtual void setBackground(int index, const QBrush &);
+
+private:
+   QTableWidget *parent;
+   int row;
+   QTableWidgetItem *last;
+};
+
 #endif /* _FMTWIDGETITEM_H_ */
Index: bacula/src/qt-console/util/fmtwidgetitem.cpp
===================================================================
--- bacula/src/qt-console/util/fmtwidgetitem.cpp	(revision 6973)
+++ bacula/src/qt-console/util/fmtwidgetitem.cpp	(working copy)
@@ -36,26 +36,135 @@
  */ 
 
 #include <QTreeWidgetItem>
+#include <QTableWidget>
+#include <QTableWidgetItem>
+#include <QBrush>
 #include <QString>
 #include <QStringList>
 #include <math.h>
 #include "fmtwidgetitem.h"
 
-ItemFormatter::ItemFormatter(QTreeWidgetItem &parent, int indent_level):
-wdg(new QTreeWidgetItem(&parent)),
-level(indent_level)
+/***********************************************
+ *
+ * ItemFormatterBase static members
+ *
+ ***********************************************/
+
+ItemFormatterBase::BYTES_CONVERSION ItemFormatterBase::cnvFlag(BYTES_CONVERSION_IEC);
+
+QString ItemFormatterBase::convertBytesIEC(qint64 qfld)
 {
+   static const qint64 KB = Q_INT64_C(1024);
+   static const qint64 MB = (KB * KB);
+   static const qint64 GB = (MB * KB);
+   static const qint64 TB = (GB * KB);
+   static const qint64 PB = (TB * KB);
+   static const qint64 EB = (PB * KB);
+
+   /* note: division is integer, so to have some decimals we divide for a
+      smaller unit (e.g. GB for a TB number and so on) */
+   char suffix;
+   if (qfld >= EB) {
+      qfld /= PB; 
+      suffix = 'E';
+   }
+   else if (qfld >= PB) {
+      qfld /= TB; 
+      suffix = 'P';
+   }
+   else if (qfld >= TB) {
+      qfld /= GB; 
+      suffix = 'T';
+   }
+   else if (qfld >= GB) {
+      qfld /= MB;
+      suffix = 'G';
+   }
+   else if (qfld >= MB) {
+      qfld /= KB;
+      suffix = 'M';
+   }
+   else if (qfld >= KB) {
+      suffix = 'K';
+   }
+   else  {
+      /* plain bytes, no need to reformat */
+      return QString("%1 B").arg(qfld); 
+   }
+
+   /* having divided for a smaller unit, now we can safely convert to double and
+      use the extra room for decimals */
+   return QString("%1 %2iB").arg(qfld / 1000.0, 0, 'f', 2).arg(suffix);
 }
 
-void ItemFormatter::setBoolFld(int index, const QString &fld, bool center)
+QString ItemFormatterBase::convertBytesSI(qint64 qfld)
 {
+   static const qint64 KB = Q_INT64_C(1000);
+   static const qint64 MB = (KB * KB);
+   static const qint64 GB = (MB * KB);
+   static const qint64 TB = (GB * KB);
+   static const qint64 PB = (TB * KB);
+   static const qint64 EB = (PB * KB);
+
+   /* note: division is integer, so to have some decimals we divide for a
+      smaller unit (e.g. GB for a TB number and so on) */
+   char suffix;
+   if (qfld >= EB) {
+      qfld /= PB; 
+      suffix = 'E';
+   }
+   else if (qfld >= PB) {
+      qfld /= TB; 
+      suffix = 'P';
+   }
+   else if (qfld >= TB) {
+      qfld /= GB; 
+      suffix = 'T';
+   }
+   else if (qfld >= GB) {
+      qfld /= MB;
+      suffix = 'G';
+   }
+   else if (qfld >= MB) {
+      qfld /= KB;
+      suffix = 'M';
+   }
+   else if (qfld >= KB) {
+      suffix = 'k'; /* SI uses lowercase k */
+   }
+   else  {
+      /* plain bytes, no need to reformat */
+      return QString("%1 B").arg(qfld); 
+   }
+
+   /* having divided for a smaller unit, now we can safely convert to double and
+      use the extra room for decimals */
+   return QString("%1 %2B").arg(qfld / 1000.0, 0, 'f', 2).arg(suffix);
+}
+
+/***********************************************
+ *
+ * base formatting routines
+ *
+ ***********************************************/
+
+ItemFormatterBase::ItemFormatterBase()
+{
+}
+
+ItemFormatterBase::~ItemFormatterBase()
+{
+}
+
+void ItemFormatterBase::setBoolFld(int index, const QString &fld, bool center)
+{
    if (fld.trimmed().toInt())
      setTextFld(index, "Yes", center);
    else
      setTextFld(index, "No", center);
 }
 
-void ItemFormatter::setBoolFld(int index, int fld, bool center)
+void ItemFormatterBase::setBoolFld(int index, int fld, bool center)
 {
    if (fld)
      setTextFld(index, "Yes", center);
@@ -63,84 +172,234 @@
      setTextFld(index, "No", center);
 }
 
-void ItemFormatter::setTextFld(int index, const QString &fld, bool center)
+void ItemFormatterBase::setNumericFld(int index, const QString &fld)
 {
+   setTextFld(index, fld);
+   setTextAlignment(index, Qt::AlignRight | Qt::AlignVCenter);
+}
+
+void ItemFormatterBase::setBytesFld(int index, const QString &fld)
+{
+   qint64 qfld = fld.trimmed().toLongLong();
+   QString msg;
+   switch (cnvFlag) {
+   case BYTES_CONVERSION_NONE:
+      msg = QString::number(qfld);
+      break;
+   case BYTES_CONVERSION_IEC:
+      msg = convertBytesIEC(qfld);
+      break;
+   case BYTES_CONVERSION_SI:
+      msg = convertBytesSI(qfld);
+      break;
+   }
+   setNumericFld(index, msg);
+}
+
+void ItemFormatterBase::setDurationFld(int index, const QString &fld)
+{
+   static const qint64 HOUR = Q_INT64_C(3600);
+   static const qint64 DAY = HOUR * 24;
+   static const qint64 WEEK = DAY * 7;
+   static const qint64 MONTH = DAY * 30;
+   static const qint64 YEAR = DAY * 365;
+   static const qint64 divs[] = { YEAR, MONTH, WEEK, DAY, HOUR };
+   static const char sufs[] = { 'y', 'm', 'w', 'd', 'h', '\0' };
+
+   qint64 dfld = fld.trimmed().toLongLong();
+
+   char suffix = 's';
+   if (dfld) {
+      for (int pos = 0 ; sufs[pos] ; ++pos) {
+	  if (dfld % divs[pos] == 0) {
+	     dfld /= divs[pos];
+	     suffix = sufs[pos];
+	     break;
+	  }
+      }
+   }
+   QString msg;
+   if (dfld < 100) {
+      msg = QString("%1%2").arg(dfld).arg(suffix);
+   } else {
+      /* previous check returned a number too big. The original specification perhaps
+         was mixed, like 1d 2h, so we try to match with this routine */
+      dfld = fld.trimmed().toLongLong();
+      msg = "";
+      for (int pos = 0 ; sufs[pos] ; ++pos) {
+	  if (dfld / divs[pos] != 0) {
+	     msg += QString(" %1%2").arg(dfld / divs[pos]).arg(sufs[pos]);
+	     dfld %= divs[pos];
+	  }
+      }
+      if (dfld)
+ 	 msg += QString(" %1s").arg(dfld);
+           
+/*
+     double net = 0;
+     QList<qlonglong> durations;
+     durations.append(1);
+     durations.append(60);
+     durations.append(HOUR);
+     durations.append(DAY);
+     durations.append(MONTH);
+     durations.append(YEAR);
+     QStringList abbrlist = (QStringList() << "s" << "min" << "h" << "d" << "m" << "y");
+     bool done = false;
+     int count = 1;
+     while (done == false) {
+	if ((dfld < durations[count]) || (count >= abbrlist.count() - 1)) { 
+           done = true;
+	   net = (double)dfld / (double)(durations[count - 1]);
+	   if (net != 0) {
+              msg =  QString("%1%2")
+                  .arg(net, 0, 'f', 2, QLatin1Char(' '))
+                  .arg(abbrlist[count - 1]);
+	   } else {
+	     msg = "0s";
+	   }
+	}
+        count += 1;
+     }
+*/   }
+
+   setNumericFld(index, msg);
+}
+
+void ItemFormatterBase::setVolStatusFld(int index, const QString &fld, bool center)
+{
+   setTextFld(index, fld, center);
+
+   if (fld == "Append" ) {
+      setBackground(index, Qt::green);
+   } else if (fld == "Error") {
+      setBackground(index, Qt::red);
+   } else if (fld == "Used" || fld == "Full"){
+      setBackground(index, Qt::yellow);
+   }
+}
+
+void ItemFormatterBase::setJobStatusFld(int index, const QString &shortstatus, 
+					const QString &longstatus, bool center)
+{
+   /* C (created, not yet running) uses the default background */
+   static QString greenchars("TR");
+   static QString redchars("BEf");
+   static QString yellowchars("eDAFSMmsjdctp");
+
+   setTextFld(index, longstatus, center);
+
+   QString st(shortstatus.trimmed());
+   if (greenchars.contains(st, Qt::CaseSensitive)) {
+      setBackground(index, Qt::green);
+   } else if (redchars.contains(st, Qt::CaseSensitive)) {
+      setBackground(index, Qt::red);
+   } else if (yellowchars.contains(st, Qt::CaseSensitive)){ 
+      setBackground(index, Qt::yellow);
+   }
+}
+
+void ItemFormatterBase::setJobTypeFld(int index, const QString &fld, bool center)
+{
+   static QHash<QString, QString> jobt;
+   if (jobt.isEmpty()) {
+      jobt.insert("B", QObject::tr("Backup"));
+      jobt.insert("R", QObject::tr("Restore"));
+      jobt.insert("V", QObject::tr("Verify"));
+      jobt.insert("A", QObject::tr("Admin"));
+   }
+
+   setTextFld(index, jobt.value(fld.trimmed(), fld.trimmed()), center);
+}
+
+void ItemFormatterBase::setJobLevelFld(int index, const QString &fld, bool center)
+{
+   static QHash<QString, QString> jobt;
+   if (jobt.isEmpty()) {
+      jobt.insert("F", QObject::tr("Full"));
+      jobt.insert("D", QObject::tr("Differential"));
+      jobt.insert("I", QObject::tr("Incremental"));
+      jobt.insert("C", QObject::tr("Catalog"));
+      jobt.insert("O", QObject::tr("VolToCatalog"));
+   }
+
+   setTextFld(index, jobt.value(fld.trimmed(), fld.trimmed()), center);
+}
+
+
+
+/***********************************************
+ *
+ * treeitem formatting routines
+ *
+ ***********************************************/
+TreeItemFormatter::TreeItemFormatter(QTreeWidgetItem &parent, int indent_level):
+ItemFormatterBase(),
+wdg(new QTreeWidgetItem(&parent)),
+level(indent_level)
+{
+}
+
+void TreeItemFormatter::setTextFld(int index, const QString &fld, bool center)
+{
    wdg->setData(index, Qt::UserRole, level);
    if (center) {
-      wdg->setTextAlignment(index, Qt::AlignHCenter);
+      setTextAlignment(index, Qt::AlignCenter);
    }
    wdg->setText(index, fld.trimmed());
 }
 
-void ItemFormatter::setNumericFld(int index, const QString &fld)
+void TreeItemFormatter::setTextAlignment(int index, int align)
 {
-   wdg->setData(index, Qt::UserRole, level);
-   wdg->setTextAlignment(index, Qt::AlignRight);
-   wdg->setText(index, fld.trimmed());
+   wdg->setTextAlignment(index, align);
 }
 
-void ItemFormatter::setBytesFld(int index, const QString &fld)
+void TreeItemFormatter::setBackground(int index, const QBrush &qb)
 {
-   static const double KB = 1024.0;
-   static const double MB = KB * KB;
-   static const double GB = MB * KB;
-   static const double TB = GB * KB;
+   wdg->setBackground(index, qb);
+}
 
-   double dfld = fld.trimmed().toDouble();
-   QString msg;
-   if (dfld >= TB)
-      msg = QString("%1TB").arg(dfld / TB, 0, 'f', 2);
-   else if (dfld >= GB)
-      msg = QString("%1GB").arg(dfld / GB, 0, 'f', 2);
-   else if (dfld >= MB)
-      msg = QString("%1MB").arg(dfld / MB, 0, 'f', 2);
-   else if (dfld >= KB)
-      msg = QString("%1KB").arg(dfld / KB, 0, 'f', 2);
-   else
-      msg = QString::number(dfld, 'f', 0);
- 
-   wdg->setData(index, Qt::UserRole, level);
-   wdg->setTextAlignment(index, Qt::AlignRight);
-   wdg->setText(index, msg);
+
+/***********************************************
+ *
+ * tableitem formatting routines
+ *
+ ***********************************************/
+TableItemFormatter::TableItemFormatter(QTableWidget &tparent, int trow):
+ItemFormatterBase(),
+parent(&tparent),
+row(trow),
+last(NULL)
+{
 }
 
-void ItemFormatter::setDurationFld(int index, const QString &fld)
+void TableItemFormatter::setTextFld(int col, const QString &fld, bool center)
 {
-   static const double HOUR = 3600;
-   static const double DAY = HOUR * 24;
-   static const double WEEK = DAY * 7;
-   static const double MONTH = DAY * 30;
-   static const double YEAR = DAY * 365;
+   last = new QTableWidgetItem(1);
+/*   last->setForeground(blackBrush); */
+   parent->setItem(row, col, last);
+   if (center) {
+      setTextAlignment(col, Qt::AlignCenter);
+   }
+   last->setText(fld.trimmed());
+}
 
-   double dfld = fld.trimmed().toDouble();
-   QString msg;
-   if (fmod(dfld, YEAR) == 0)
-      msg = QString("%1y").arg(dfld / YEAR, 0, 'f', 0);
-   else if (fmod(dfld, MONTH) == 0)
-      msg = QString("%1m").arg(dfld / MONTH, 0, 'f', 0);
-   else if (fmod(dfld, WEEK) == 0)
-      msg = QString("%1w").arg(dfld / WEEK, 0, 'f', 0);
-   else if (fmod(dfld, DAY) == 0)
-      msg = QString("%1d").arg(dfld / DAY, 0, 'f', 0);
-   else if (fmod(dfld, HOUR) == 0)
-      msg = QString("%1h").arg(dfld / HOUR, 0, 'f', 0);
-   else
-      msg = QString("%1s").arg(dfld, 0, 'f', 0);
- 
-   wdg->setData(index, Qt::UserRole, level);
-   wdg->setTextAlignment(index, Qt::AlignRight);
-   wdg->setText(index, msg);
+void TableItemFormatter::setTextAlignment(int /*index*/, int align)
+{
+   last->setTextAlignment(align);
 }
 
-void ItemFormatter::setVolStatusFld(int index, const QString &fld, bool center)
+void TableItemFormatter::setBackground(int /*index*/, const QBrush &qb)
 {
-  setTextFld(index, fld, center);
+   last->setBackground(qb);
+}
 
-   if (fld == "Append" ) {
-      wdg->setBackground(index, Qt::green);
-   } else if (fld == "Error") {
-      wdg->setBackground(index, Qt::red);
-   } else if (fld == "Used" || fld == "Full"){
-      wdg->setBackground(index, Qt::yellow);
-   }
+QTableWidgetItem *TableItemFormatter::widget(int col)
+{
+  return parent->item(row, col);
 }
+
+const QTableWidgetItem *TableItemFormatter::widget(int col) const
+{
+  return parent->item(row, col);
+}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft 
Defy all challenges. Microsoft(R) Visual Studio 2008. 
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Bacula-devel mailing list
Bacula-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/bacula-devel


This mailing list archive is a service of Copilotco.