]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/qt-console/medialist/mediaview.cpp
Backport from BEE
[bacula/bacula] / bacula / src / qt-console / medialist / mediaview.cpp
index e56601a70afc71a2ce6a08301cb046fd47c792e0..1475297e4a78c413c7c34fdeff12bd8dbb49f161 100644 (file)
@@ -1,31 +1,19 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
+   Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
 
-   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.
+   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 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.
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
 
    Bacula® is a registered trademark of Kern Sibbald.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
 */
+
 #include "bat.h"
 #include <QAbstractEventDispatcher>
 #include <QMenu>
@@ -38,7 +26,7 @@
 #include "run/run.h"
 #include "util/fmtwidgetitem.h"
 
-MediaView::MediaView()
+MediaView::MediaView() : Pages()
 {
    setupUi(this);
    m_name = tr("Media");
@@ -50,7 +38,7 @@ MediaView::MediaView()
    connect(m_pbPurge, SIGNAL(pressed()), this, SLOT(purgePushed()));
    connect(m_pbDelete, SIGNAL(pressed()), this, SLOT(deletePushed()));
    connect(m_pbPrune, SIGNAL(pressed()), this, SLOT(prunePushed()));
-   connect(m_tableMedia, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), 
+   connect(m_tableMedia, SIGNAL(itemDoubleClicked(QTableWidgetItem*)),
            this, SLOT(showInfoForMedia(QTableWidgetItem *)));
 
    /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_medialist.h */
@@ -82,7 +70,7 @@ void MediaView::editPushed()
    QStringList sel;
    QString cmd;
    getSelection(sel);
-   
+
    for(int i=0; i<sel.count(); i++) {
       cmd = sel.at(i);
       new MediaEdit(mainWin->getFromHash(this), cmd);
@@ -91,25 +79,61 @@ void MediaView::editPushed()
 
 void MediaView::purgePushed()
 {
+   if (QMessageBox::warning(this, "Bat",
+      tr("Are you sure you want to purge ??  !!!.\n"
+"The Purge command will delete associated Catalog database records from Jobs and"
+" Volumes without considering the retention period. Purge  works only on the"
+" Catalog database and does not affect data written to Volumes. This command can"
+" be dangerous because you can delete catalog records associated with current"
+" backups of files, and we recommend that you do not use it unless you know what"
+" you are doing.\n"
+      "Press OK to proceed with the purge operation?"),
+      QMessageBox::Ok | QMessageBox::Cancel)
+      == QMessageBox::Cancel) { return; }
+
+   QStringList lst;
+   QString cmd;
+   getSelection(lst);
+   for(int i=0; i<lst.count(); i++) {
+      cmd = "purge volume=" + lst.at(i);
+      consoleCommand(cmd);
+   }
+   populateTable();
 }
 
 bool MediaView::getSelection(QStringList &list)
 {
-   QList<QTableWidgetItem*> items = m_tableMedia->selectedItems();
+   int i, nb, nr_rows, row;
+   bool *tab;
    QTableWidgetItem *it;
-   int row;
-   int nb = items.count();
-   int *tab = (int *) malloc (nb * sizeof(int));
-   memset(tab, 0, sizeof(int)*nb);
-   for (int i = 0; i < nb; ++i) {
+   QList<QTableWidgetItem*> items = m_tableMedia->selectedItems();
+
+   /*
+    * See if anything is selected.
+    */
+   nb = items.count();
+   if (!nb) {
+      return false;
+   }
+
+   /*
+    * Create a nibble map for each row so we can see if its
+    * selected or not.
+    */
+   nr_rows = m_tableMedia->rowCount();
+   tab = (bool *)malloc (nr_rows * sizeof(bool));
+   memset(tab, 0, sizeof(bool) * nr_rows);
+
+   for (i = 0; i < nb; ++i) {
       row = items[i]->row();
       if (!tab[row]) {
-         tab[row]=1;
+         tab[row] = true;
          it = m_tableMedia->item(row, 0);
          list.append(it->text());
       }
    }
    free(tab);
+
    return list.count() > 0;
 }
 
@@ -128,10 +152,6 @@ void MediaView::prunePushed()
 
 void MediaView::deletePushed()
 {
-   QStringList sel;
-   QString cmd;
-   getSelection(sel);
-
    if (QMessageBox::warning(this, "Bat",
       tr("Are you sure you want to delete??  !!!.\n"
 "This delete command is used to delete a Volume record and all associated catalog"
@@ -144,8 +164,14 @@ void MediaView::deletePushed()
       QMessageBox::Ok | QMessageBox::Cancel)
       == QMessageBox::Cancel) { return; }
 
-   cmd = "delete volume=" + sel.join(",");
-   consoleCommand(cmd);
+   QStringList lst;
+   QString cmd;
+   getSelection(lst);
+   for(int i=0; i<lst.count(); i++) {
+      cmd = "delete volume=" + lst.at(i);
+      consoleCommand(cmd);
+   }
+   populateTable();
 }
 
 void MediaView::populateForm()
@@ -168,15 +194,50 @@ void MediaView::populateForm()
 }
 
 /*
- * The main meat of the class!!  The function that querries the director and 
+ * If chkExpired button is checked, we can remove all non Expired
+ * entries
+ */
+void MediaView::filterExipired(QStringList &list)
+{
+   utime_t t, now = time(NULL);
+   QString resultline, stat, LastWritten;
+   QStringList fieldlist;
+
+   /* We should now in advance how many rows we will have */
+   if (m_chkExpired->isChecked()) {
+      for (int i=list.size() -1; i >= 0; i--) {
+         fieldlist = list.at(i).split("\t");
+         ASSERT(fieldlist.size() != 9);
+         LastWritten = fieldlist.at(7);
+         if (LastWritten == "") {
+            list.removeAt(i);
+
+         } else {
+            stat = fieldlist.at(8);
+            t = str_to_utime(LastWritten.toAscii().data());
+            t = t + stat.toULongLong();
+            if (t > now) {
+               list.removeAt(i);
+            }
+         }
+      }
+   }
+}
+
+/*
+ * The main meat of the class!!  The function that querries the director and
  * creates the widgets with appropriate values.
  */
 void MediaView::populateTable()
 {
    utime_t t;
    time_t ttime;
-   QString stat, LastWritten;
+   QString stat, resultline, query;
+   QString str_usage;
+   QHash<QString, float> hash_size;
+   QStringList fieldlist, results;
    char buf[256];
+   float usage;
    struct tm tm;
 
    m_populated = true;
@@ -187,7 +248,7 @@ void MediaView::populateTable()
    if (m_cbPool->currentText() != "") {
       cmd = " Pool.Name = '" + m_cbPool->currentText() + "'";
       where.append(cmd);
-   } 
+   }
 
    if (m_cbStatus->currentText() != "") {
       cmd = " Media.VolStatus = '" + m_cbStatus->currentText() + "'";
@@ -220,101 +281,118 @@ void MediaView::populateTable()
       cmd = "";
    }
 
-   m_tableMedia->clearContents();
+   query =
+      "SELECT AVG(VolBytes) AS size, COUNT(1) as nb, "
+      "MediaType  FROM Media "
+      "WHERE VolStatus IN ('Full', 'Used') "
+      "GROUP BY MediaType";
 
-   QString query = 
-      "SELECT MediaId, VolumeName, InChanger, Slot, VolBytes, VolStatus, "
-      "Pool.Name, "
-      "MediaType, LastWritten,"
-      "Media.VolRetention "
+   if (mainWin->m_sqlDebug) {
+      Pmsg1(000, "MediaView query cmd : %s\n",query.toUtf8().data());
+   }
+   if (m_console->sql_cmd(query, results)) {
+      foreach (resultline, results) {
+         fieldlist = resultline.split("\t");
+         if (fieldlist.at(1).toInt() >= 1) {
+            //           MediaType
+            hash_size[fieldlist.at(2)]
+               = fieldlist.at(0).toFloat();
+         }
+      }
+   }
+
+   m_tableMedia->clearContents();
+   query =
+      "SELECT VolumeName, InChanger, "
+      "Slot, MediaType, VolStatus, VolBytes, Pool.Name,  "
+      "LastWritten, Media.VolRetention "
       "FROM Media JOIN Pool USING (PoolId) "
-      "LEFT JOIN Location USING (LocationId) "
-      + cmd + 
+      "LEFT JOIN Location ON (Media.LocationId=Location.LocationId) "
+      + cmd +
       " ORDER BY VolumeName LIMIT " + m_sbLimit->cleanText();
 
-//   Pmsg1(000, "MediaView query cmd : %s\n",query.toUtf8().data());
-
-   QStringList results;
+   m_tableMedia->sortByColumn(0, Qt::AscendingOrder);
+   m_tableMedia->setSortingEnabled(false); /* Don't sort during insert */
+   results.clear();
+   if (mainWin->m_sqlDebug) {
+      Pmsg1(000, "MediaView query cmd : %s\n",query.toUtf8().data());
+   }
    if (m_console->sql_cmd(query, results)) {
-      QString resultline;
-      QStringList fieldlist;
-      m_tableMedia->setRowCount(results.size());
       int row=0;
+      filterExipired(results);
+      m_tableMedia->setRowCount(results.size());
+
       foreach (resultline, results) { // should have only one result
+         int index = 0;
+         QString VolBytes, MediaType, LastWritten, VolStatus;
          fieldlist = resultline.split("\t");
+         if (fieldlist.size() != 10) {
+            continue;
+         }
          QStringListIterator fld(fieldlist);
-         int index=0;
          TableItemFormatter mediaitem(*m_tableMedia, row);
 
-         fld.next();            // MediaId
-         
          /* VolumeName */
-         mediaitem.setTextFld(index++, fld.next()); 
-         
-         /* Online */
          mediaitem.setTextFld(index++, fld.next());
-         fld.next();            // Slot
+
+         /* Online */
+         mediaitem.setInChanger(index++, fld.next());
+
+         /* Slot */
+         mediaitem.setNumericFld(index++, fld.next());
+
+         MediaType = fld.next();
+         VolStatus = fld.next();
 
          /* Volume bytes */
-         mediaitem.setBytesFld(index++, fld.next());
+         VolBytes = fld.next();
+         mediaitem.setBytesFld(index++, VolBytes);
 
          /* Usage */
-         mediaitem.setTextFld(index++, "NYI");
-         
+         usage = 0;
+         if (hash_size.contains(MediaType) &&
+             hash_size[MediaType] != 0) {
+            usage = VolBytes.toLongLong() * 100 / hash_size[MediaType];
+         }
+         mediaitem.setPercent(index++, usage);
+
          /* Volstatus */
-         mediaitem.setVolStatusFld(index++, fld.next());
+         mediaitem.setVolStatusFld(index++, VolStatus);
 
          /* Pool */
          mediaitem.setTextFld(index++, fld.next());
 
          /* MediaType */
-         mediaitem.setTextFld(index++, fld.next());
+         mediaitem.setTextFld(index++, MediaType);
 
-         /* LastWritten */
          LastWritten = fld.next();
-         mediaitem.setTextFld(index++, LastWritten);
+         buf[0] = 0;
+         if (LastWritten != "") {
+            stat = fld.next();  // VolUseDuration
+            t = str_to_utime(LastWritten.toAscii().data());
+            t = t + stat.toULongLong();
+            ttime = t;
+            localtime_r(&ttime, &tm);
+            strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
+         }
 
-         stat = fld.next();
-         t = str_to_utime(LastWritten.toAscii().data());
-         t = t + stat.toULongLong();
-         ttime = t;
-         localtime_r(&ttime, &tm);         
-         strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
+         /* LastWritten */
+         mediaitem.setTextFld(index++, LastWritten);
 
+         /* When expired */
          mediaitem.setTextFld(index++, buf);
-         
          row++;
       }
    }
-
    m_tableMedia->resizeColumnsToContents();
    m_tableMedia->resizeRowsToContents();
    m_tableMedia->verticalHeader()->hide();
+   m_tableMedia->setSortingEnabled(true);
 
    /* make read only */
    m_tableMedia->setEditTriggers(QAbstractItemView::NoEditTriggers);
 }
 
-/*
- * Called from the signal of the context sensitive menu!
- */
-void MediaView::editVolume()
-{
-   MediaEdit* edit = new MediaEdit(mainWin->getFromHash(this), m_currentVolumeId);
-   connect(edit, SIGNAL(destroyed()), this, SLOT(populateTable()));
-}
-
-/*
- * Called from the signal of the context sensitive menu!
- */
-void MediaView::viewVolume()
-{
-   QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
-   MediaInfo* view = new MediaInfo(parentItem, m_currentVolumeName);
-   connect(view, SIGNAL(destroyed()), this, SLOT(populateTable()));
-
-}
-
 /*
  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
  * The tree has been populated.
@@ -325,7 +403,9 @@ void MediaView::PgSeltreeWidgetClicked()
       populateForm();
       populateTable();
    }
-   dockPage();
+   if (!isOnceDocked()) {
+      dockPage();
+   }
 }
 
 /*
@@ -339,68 +419,6 @@ void MediaView::currentStackItem()
    }
 }
 
-/*
- * Called from the signal of the context sensitive menu to delete a volume!
- */
-void MediaView::deleteVolume()
-{
-   if (QMessageBox::warning(this, "Bat",
-      tr("Are you sure you want to delete??  !!!.\n"
-"This delete command is used to delete a Volume record and all associated catalog"
-" records that were created. This command operates only on the Catalog"
-" database and has no effect on the actual data written to a Volume. This"
-" command can be dangerous and we strongly recommend that you do not use"
-" it unless you know what you are doing.  All Jobs and all associated"
-" records (File and JobMedia) will be deleted from the catalog."
-      "Press OK to proceed with delete operation.?"),
-      QMessageBox::Ok | QMessageBox::Cancel)
-      == QMessageBox::Cancel) { return; }
-
-   QStringList lst;
-   QString cmd;
-   getSelection(lst);
-   for(int i=0; i<lst.count(); i++) {
-      cmd = "delete volume=" + lst.at(i);
-      consoleCommand(cmd);
-   }
-   populateTable();
-}
-
-/*
- * Called from the signal of the context sensitive menu to purge!
- */
-void MediaView::purgeVolume()
-{
-   if (QMessageBox::warning(this, "Bat",
-      tr("Are you sure you want to purge ??  !!!.\n"
-"The Purge command will delete associated Catalog database records from Jobs and"
-" Volumes without considering the retention period. Purge  works only on the"
-" Catalog database and does not affect data written to Volumes. This command can"
-" be dangerous because you can delete catalog records associated with current"
-" backups of files, and we recommend that you do not use it unless you know what"
-" you are doing.\n"
-      "Press OK to proceed with the purge operation?"),
-      QMessageBox::Ok | QMessageBox::Cancel)
-      == QMessageBox::Cancel) { return; }
-
-   QStringList lst;
-   QString cmd;
-   getSelection(lst);
-   for(int i=0; i<lst.count(); i++) {
-      cmd = "purge volume=" + lst.at(i);
-      consoleCommand(cmd);
-   }
-   populateTable();
-}
-
-/*
- * Called from the signal of the context sensitive menu to prune!
- */
-void MediaView::pruneVolume()
-{
-   new prunePage(m_currentVolumeName, "");
-}
-
 // /*
 //  * Called from the signal of the context sensitive menu to relabel!
 //  */
@@ -409,7 +427,7 @@ void MediaView::pruneVolume()
 //    setConsoleCurrent();
 //    new relabelDialog(m_console, m_currentVolumeName);
 // }
-// 
+//
 // /*
 //  * Called from the signal of the context sensitive menu to purge!
 //  */
@@ -419,14 +437,14 @@ void MediaView::pruneVolume()
 //    consoleCommand(cmd);
 //    populateTable();
 // }
-// 
+//
 // void MediaView::allVolumes()
 // {
 //    QString cmd = "update volume allfrompools";
 //    consoleCommand(cmd);
 //    populateTable();
 // }
-// 
+//
 //  /*
 //   * Called from the signal of the context sensitive menu to purge!
 //   */
@@ -440,4 +458,4 @@ void MediaView::pruneVolume()
 //     consoleCommand(cmd);
 //     populateTable();
 //  }
-//  
+//