]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/qt-console/joblist/joblist.cpp
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / qt-console / joblist / joblist.cpp
index a7536450078d127ad46bd881570239d7d043c4c5..4afbb68fc575073850bda67e5a945295b8ba4f3c 100644 (file)
@@ -1,33 +1,23 @@
 /*
-   Bacula® - The Network Backup Solution
+   Bacula(R) - The Network Backup Solution
 
+   Copyright (C) 2000-2015 Kern Sibbald
    Copyright (C) 2007-2009 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.
-
-   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 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.
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   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.
+
+   This notice must be preserved when any source code is 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
- *   Version $Id$
- *
  *   Dirk Bartley, March 2007
  */
  
@@ -36,6 +26,7 @@
 #include <QTableWidgetItem>
 #include "joblist.h"
 #include "restore.h"
+#include "job/job.h"
 #include "joblog/joblog.h"
 #ifdef HAVE_QWT
 #include "jobgraphs/jobplot.h"
  */
 JobList::JobList(const QString &mediaName, const QString &clientName,
           const QString &jobName, const QString &filesetName, QTreeWidgetItem *parentTreeWidgetItem)
+   : Pages()
 {
    setupUi(this);
-   m_name = ""; /* treeWidgetName has a virtual override in this class */
+   m_name = "Jobs Run"; /* treeWidgetName has a virtual override in this class */
    m_mediaName = mediaName;
    m_clientName = clientName;
    m_jobName = jobName;
    m_filesetName = filesetName;
-   m_filesetName = filesetName;
    pgInitialize("", parentTreeWidgetItem);
    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/emblem-system.png")));
@@ -63,17 +54,16 @@ JobList::JobList(const QString &mediaName, const QString &clientName,
    m_resultCount = 0;
    m_populated = false;
    m_closeable = false;
-   if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != ""))
+   if ((m_mediaName != "") || (m_clientName != "") || (m_jobName != "") || (m_filesetName != "")) {
       m_closeable=true;
+   }
    m_checkCurrentWidget = true;
-   createConnections();
 
    /* Set Defaults for check and spin for limits */
    limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
    limitSpinBox->setValue(mainWin->m_recordLimitVal);
    daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
    daysSpinBox->setValue(mainWin->m_daysLimitVal);
-   dockPage();
 
    QGridLayout *gridLayout = new QGridLayout(this);
    gridLayout->setSpacing(6);
@@ -85,11 +75,13 @@ JobList::JobList(const QString &mediaName, const QString &clientName,
    area->setObjectName(QString::fromUtf8("area"));
    area->setWidget(frame);
    area->setWidgetResizable(true);
-   m_splitter->addWidget(mp_tableWidget);
    m_splitter->addWidget(area);
+   m_splitter->addWidget(mp_tableWidget);
 
    gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
+   createConnections();
    readSettings();
+   if (m_closeable) { dockPage(); }
 }
 
 /*
@@ -132,6 +124,10 @@ void JobList::populateTable()
    m_startIndex = headerlist.indexOf(tr("Job Starttime"));
    m_filesIndex = headerlist.indexOf(tr("Job Files"));
    m_bytesIndex = headerlist.indexOf(tr("Job Bytes"));
+   m_levelIndex = headerlist.indexOf(tr("Job Level"));
+   m_nameIndex = headerlist.indexOf(tr("Job Name"));
+   m_filesetIndex = headerlist.indexOf(tr("File Set"));
+   m_clientIndex = headerlist.indexOf(tr("Client"));
 
    /* Initialize the QTableWidget */
    m_checkCurrentWidget = false;
@@ -229,16 +225,7 @@ void JobList::populateTable()
    }
 
    /* make read only */
-   int rcnt = mp_tableWidget->rowCount();
-   int ccnt = mp_tableWidget->columnCount();
-   for(int r=0; r < rcnt; r++) {
-      for(int c=0; c < ccnt; c++) {
-         QTableWidgetItem* item = mp_tableWidget->item(r, c);
-         if (item) {
-            item->setFlags(Qt::ItemFlags(item->flags() & (~Qt::ItemIsEditable)));
-         }
-      }
-   }
+   mp_tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
 }
 
 void JobList::prepareFilterWidgets()
@@ -348,6 +335,20 @@ void JobList::PgSeltreeWidgetClicked()
 {
    if (!m_populated) {
       populateTable();
+      /* Lets make sure the splitter is not all the way to size index 0 == 0 */
+      QList<int> sizes = m_splitter->sizes();
+      if (sizes[0] == 0) {
+         int frameMax = frame->maximumHeight();
+         int sizeSum = 0;
+         foreach(int size, sizes) { sizeSum += size; }
+         int tabHeight = mainWin->tabWidget->geometry().height();
+         sizes[0] = frameMax;
+         sizes[1] = tabHeight - frameMax;
+         m_splitter->setSizes(sizes);
+      }
+   }
+   if (!isOnceDocked()) {
+      dockPage();
    }
 }
 
@@ -367,15 +368,15 @@ void JobList::currentStackItem()
 void JobList::treeWidgetName(QString &desc)
 {
    if (m_mediaName != "" ) {
-     desc = tr("JobList of Volume %1").arg(m_mediaName);
+     desc = tr("Jobs Run on Volume %1").arg(m_mediaName);
    } else if (m_clientName != "" ) {
-     desc = tr("JobList of Client %1").arg(m_clientName);
+     desc = tr("Jobs Run from Client %1").arg(m_clientName);
    } else if (m_jobName != "" ) {
-     desc = tr("JobList of Job %1").arg(m_jobName);
+     desc = tr("Jobs Run of Job %1").arg(m_jobName);
    } else if (m_filesetName != "" ) {
-     desc = tr("JobList of fileset %1").arg(m_filesetName);
+     desc = tr("Jobs Run with fileset %1").arg(m_filesetName);
    } else {
-     desc = tr("JobList");
+     desc = tr("Jobs Run");
    }
 }
 
@@ -387,8 +388,7 @@ void JobList::createConnections()
 {
    /* connect to the action specific to this pages class that shows up in the 
     * page selector tree */
-   connect(actionRefreshJobList, SIGNAL(triggered()), this,
-                SLOT(populateTable()));
+   connect(actionRefreshJobList, SIGNAL(triggered()), this, SLOT(populateTable()));
    connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
 #ifdef HAVE_QWT
    connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
@@ -398,6 +398,7 @@ void JobList::createConnections()
 #endif
    /* for the selectionChanged to maintain m_currentJob and a delete selection */
    connect(mp_tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
+   connect(mp_tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(showInfoForJob()));
 
    /* Do what is required for the local context sensitive menu */
 
@@ -405,28 +406,18 @@ void JobList::createConnections()
    /* setContextMenuPolicy is required */
    mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
 
-   connect(actionListJobid, SIGNAL(triggered()), this,
-                SLOT(consoleListJobid()));
-   connect(actionListFilesOnJob, SIGNAL(triggered()), this,
-                SLOT(consoleListFilesOnJob()));
-   connect(actionListJobMedia, SIGNAL(triggered()), this,
-                SLOT(consoleListJobMedia()));
-   connect(actionListVolumes, SIGNAL(triggered()), this,
-                SLOT(consoleListVolumes()));
-   connect(actionDeleteJob, SIGNAL(triggered()), this,
-                SLOT(consoleDeleteJob()));
-   connect(actionPurgeFiles, SIGNAL(triggered()), this,
-                SLOT(consolePurgeFiles()));
-   connect(actionRestoreFromJob, SIGNAL(triggered()), this,
-                SLOT(preRestoreFromJob()));
-   connect(actionRestoreFromTime, SIGNAL(triggered()), this,
-                SLOT(preRestoreFromTime()));
-   connect(actionShowLogForJob, SIGNAL(triggered()), this,
-                SLOT(showLogForJob()));
-   connect(actionCancelJob, SIGNAL(triggered()), this,
-                SLOT(consoleCancelJob()));
-   connect(actionListJobTotals, SIGNAL(triggered()), this,
-                SLOT(consoleListJobTotals()));
+   connect(actionListFilesOnJob, SIGNAL(triggered()), this, SLOT(consoleListFilesOnJob()));
+   connect(actionListJobMedia, SIGNAL(triggered()), this, SLOT(consoleListJobMedia()));
+   connect(actionDeleteJob, SIGNAL(triggered()), this, SLOT(consoleDeleteJob()));
+   connect(actionRestartJob, SIGNAL(triggered()), this, SLOT(consoleRestartJob()));
+   connect(actionPurgeFiles, SIGNAL(triggered()), this, SLOT(consolePurgeFiles()));
+   connect(actionRestoreFromJob, SIGNAL(triggered()), this, SLOT(preRestoreFromJob()));
+   connect(actionRestoreFromTime, SIGNAL(triggered()), this, SLOT(preRestoreFromTime()));
+   connect(actionShowLogForJob, SIGNAL(triggered()), this, SLOT(showLogForJob()));
+   connect(actionShowInfoForJob, SIGNAL(triggered()), this, SLOT(showInfoForJob()));
+   connect(actionCancelJob, SIGNAL(triggered()), this, SLOT(consoleCancelJob()));
+   connect(actionListJobTotals, SIGNAL(triggered()), this, SLOT(consoleListJobTotals()));
+   connect(m_splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(splitterMoved(int, int)));
 
    m_contextActions.append(actionRefreshJobList);
    m_contextActions.append(actionListJobTotals);
@@ -436,13 +427,6 @@ void JobList::createConnections()
  * Functions to respond to local context sensitive menu sending console commands
  * If I could figure out how to make these one function passing a string, Yaaaaaa
  */
-void JobList::consoleListJobid()
-{
-   QString cmd("list jobid=");
-   cmd += m_currentJob;
-   if (mainWin->m_longList) { cmd.prepend("l"); }
-   consoleCommand(cmd);
-}
 void JobList::consoleListFilesOnJob()
 {
    QString cmd("list files jobid=");
@@ -457,19 +441,14 @@ void JobList::consoleListJobMedia()
    if (mainWin->m_longList) { cmd.prepend("l"); }
    consoleCommand(cmd);
 }
-void JobList::consoleListVolumes()
-{
-   QString cmd("list volumes jobid=");
-   cmd += m_currentJob;
-   if (mainWin->m_longList) { cmd.prepend("l"); }
-   consoleCommand(cmd);
-}
+
 void JobList::consoleListJobTotals()
 {
    QString cmd("list jobtotals");
    if (mainWin->m_longList) { cmd.prepend("l"); }
    consoleCommand(cmd);
 }
+
 void JobList::consoleDeleteJob()
 {
    if (QMessageBox::warning(this, "Bat",
@@ -489,6 +468,23 @@ void JobList::consoleDeleteJob()
    consoleCommand(cmd, false);
    populateTable();
 }
+
+void JobList::consoleRestartJob()
+{
+   QString cmd;
+
+   cmd = tr("run job=\"%1\" client=\"%2\" level=%3").arg(m_jobName).arg(m_clientName).arg(m_levelName);
+   if (m_filesetName != "" && m_filesetName != "*None*") {
+      cmd += tr(" fileset=\"%1\"").arg(m_filesetName);
+   }
+
+   if (mainWin->m_commandDebug) Pmsg1(000, "Run cmd : %s\n",cmd.toUtf8().data());
+   consoleCommand(cmd, false);
+   populateTable();
+}
+
+
+
 void JobList::consolePurgeFiles()
 {
    if (QMessageBox::warning(this, "Bat",
@@ -503,11 +499,13 @@ void JobList::consolePurgeFiles()
       QMessageBox::Ok | QMessageBox::Cancel)
       == QMessageBox::Cancel) { return; }
 
+   m_console->m_warningPrevent = true;
    foreach(QString job, m_selectedJobsList) {
       QString cmd("purge files jobid=");
       cmd += job;
       consoleCommand(cmd, false);
    }
+   m_console->m_warningPrevent = false;
    populateTable();
 }
 
@@ -536,6 +534,15 @@ void JobList::showLogForJob()
    new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
 }
 
+/*
+ * Subroutine to call class to show the log in the database from that job
+ */
+void JobList::showInfoForJob(QTableWidgetItem * /*item*/)
+{
+   QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
+   new Job(m_currentJob, pageSelectorTreeWidgetItem);
+}
+
 /*
  * Cancel a running job
  */
@@ -589,10 +596,12 @@ void JobList::writeSettings()
 void JobList::readSettings()
 {
    m_groupText = "JobListPage";
-   m_splitText = "splitterSizes_1";
+   m_splitText = "splitterSizes_2";
    QSettings settings(m_console->m_dir->name(), "bat");
    settings.beginGroup(m_groupText);
-   m_splitter->restoreState(settings.value(m_splitText).toByteArray());
+   if (settings.contains(m_splitText)) {
+      m_splitter->restoreState(settings.value(m_splitText).toByteArray());
+   }
    filterCopyCheckBox->setCheckState((Qt::CheckState)settings.value("FilterCopyCheckState").toInt());
    filterMigrationCheckBox->setCheckState((Qt::CheckState)settings.value("FilterMigrationCheckState").toInt());
    settings.endGroup();
@@ -641,13 +650,13 @@ void JobList::selectionChanged()
    /* Add Actions */
    mp_tableWidget->addAction(actionRefreshJobList);
    if (m_selectedJobsCount == 1) {
-      mp_tableWidget->addAction(actionListJobid);
       mp_tableWidget->addAction(actionListFilesOnJob);
       mp_tableWidget->addAction(actionListJobMedia);
-      mp_tableWidget->addAction(actionListVolumes);
+      mp_tableWidget->addAction(actionRestartJob);
       mp_tableWidget->addAction(actionRestoreFromJob);
       mp_tableWidget->addAction(actionRestoreFromTime);
       mp_tableWidget->addAction(actionShowLogForJob);
+      mp_tableWidget->addAction(actionShowInfoForJob);
    }
    if (m_selectedJobsCount >= 1) {
       mp_tableWidget->addAction(actionDeleteJob);
@@ -658,7 +667,19 @@ void JobList::selectionChanged()
    if (m_checkCurrentWidget) {
       int row = mp_tableWidget->currentRow();
       QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
-      m_currentJob = jobitem->text();
+      m_currentJob = jobitem->text();    /* get JobId */
+      jobitem = mp_tableWidget->item(row, m_clientIndex);
+      m_clientName = jobitem->text();    /* get Client Name */
+      jobitem = mp_tableWidget->item(row, m_nameIndex);
+      m_jobName = jobitem->text();    /* get Job Name */
+      jobitem = mp_tableWidget->item(row, m_levelIndex);
+      m_levelName = jobitem->text();    /* get level */
+      jobitem = mp_tableWidget->item(row, m_filesetIndex);
+      if (jobitem) {
+         m_filesetName = jobitem->text();    /* get FileSet Name */
+      } else {
+         m_filesetName = "";
+      }
 
       /* include purged action or not */
       jobitem = mp_tableWidget->item(row, m_purgedIndex);
@@ -667,6 +688,7 @@ void JobList::selectionChanged()
       if (purged == tr("No") ) {
          mp_tableWidget->addAction(actionPurgeFiles);
       }*/
+
       /* include restore from time and job action or not */
       jobitem = mp_tableWidget->item(row, m_typeIndex);
       QString type = jobitem->text();
@@ -678,6 +700,7 @@ void JobList::selectionChanged()
             mp_tableWidget->addAction(actionRestoreFromTime);
          }
       }
+
       /* include cancel action or not */
       jobitem = mp_tableWidget->item(row, m_statusIndex);
       QString status = jobitem->text();
@@ -687,3 +710,20 @@ void JobList::selectionChanged()
       }
    }
 }
+
+/*
+ *  Function to prevent the splitter from making index 0 of the size larger than it
+ *  needs to be
+ */
+void JobList::splitterMoved(int /*pos*/, int /*index*/)
+{
+   int frameMax = frame->maximumHeight();
+   QList<int> sizes = m_splitter->sizes();
+   int sizeSum = 0;
+   foreach(int size, sizes) { sizeSum += size; }
+   if (sizes[0] > frameMax) {
+      sizes[0] = frameMax;
+      sizes[1] = sizeSum - frameMax;
+      m_splitter->setSizes(sizes);
+   }
+}