From f9a917934c9bfcf1b9b502a096b6babfb852b20d Mon Sep 17 00:00:00 2001 From: Dirk H Bartley Date: Sun, 9 Mar 2008 15:10:43 +0000 Subject: [PATCH] Add new status client window. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6565 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/qt-console/bat.pro.in | 5 + bacula/src/qt-console/clients/clients.cpp | 13 + bacula/src/qt-console/clients/clients.h | 1 + bacula/src/qt-console/clients/clients.ui | 32 +- bacula/src/qt-console/status/clientstat.cpp | 306 ++++++++++++++++++++ bacula/src/qt-console/status/clientstat.h | 73 +++++ bacula/src/qt-console/status/clientstat.ui | 198 +++++++++++++ 7 files changed, 625 insertions(+), 3 deletions(-) create mode 100644 bacula/src/qt-console/status/clientstat.cpp create mode 100644 bacula/src/qt-console/status/clientstat.h create mode 100644 bacula/src/qt-console/status/clientstat.ui diff --git a/bacula/src/qt-console/bat.pro.in b/bacula/src/qt-console/bat.pro.in index a35ea14666..8007f2fa00 100644 --- a/bacula/src/qt-console/bat.pro.in +++ b/bacula/src/qt-console/bat.pro.in @@ -44,6 +44,7 @@ FORMS += joblog/joblog.ui jobs/jobs.ui FORMS += help/help.ui FORMS += jobgraphs/jobplotcontrols.ui FORMS += status/dirstat.ui +FORMS += status/clientstat.ui # Main directory HEADERS += mainwin.h bat.h bat_conf.h qstd.h pages.h @@ -129,6 +130,10 @@ SOURCES += help/help.cpp HEADERS += status/dirstat.h SOURCES += status/dirstat.cpp +## Status Client +HEADERS += status/clientstat.h +SOURCES += status/clientstat.cpp + INSTALLS += bins INSTALLS += confs diff --git a/bacula/src/qt-console/clients/clients.cpp b/bacula/src/qt-console/clients/clients.cpp index 96f2d2eac0..2727005b6c 100644 --- a/bacula/src/qt-console/clients/clients.cpp +++ b/bacula/src/qt-console/clients/clients.cpp @@ -40,6 +40,7 @@ #include "bat.h" #include "clients/clients.h" #include "run/run.h" +#include "status/clientstat.h" Clients::Clients() { @@ -163,6 +164,7 @@ void Clients::treeItemChanged(QTreeWidgetItem *currentwidgetitem, QTreeWidgetIte if (treedepth == 1){ mp_treeWidget->removeAction(actionListJobsofClient); mp_treeWidget->removeAction(actionStatusClientInConsole); + mp_treeWidget->removeAction(actionStatusClientWindow); mp_treeWidget->removeAction(actionPurgeJobs); mp_treeWidget->removeAction(actionPrune); } @@ -175,6 +177,7 @@ void Clients::treeItemChanged(QTreeWidgetItem *currentwidgetitem, QTreeWidgetIte m_currentlyselected=currentwidgetitem->text(0); mp_treeWidget->addAction(actionListJobsofClient); mp_treeWidget->addAction(actionStatusClientInConsole); + mp_treeWidget->addAction(actionStatusClientWindow); mp_treeWidget->addAction(actionPurgeJobs); mp_treeWidget->addAction(actionPrune); } @@ -200,6 +203,8 @@ void Clients::createContextMenu() SLOT(showJobs())); connect(actionStatusClientInConsole, SIGNAL(triggered()), this, SLOT(consoleStatusClient())); + connect(actionStatusClientWindow, SIGNAL(triggered()), this, + SLOT(statusClientWindow())); connect(actionPurgeJobs, SIGNAL(triggered()), this, SLOT(consolePurgeJobs())); connect(actionPrune, SIGNAL(triggered()), this, @@ -270,3 +275,11 @@ void Clients::prune() { new prunePage("", m_currentlyselected); } + +/* + * Function responding to action to create new client status window + */ +void Clients::statusClientWindow() +{ + new ClientStat(m_currentlyselected); +} diff --git a/bacula/src/qt-console/clients/clients.h b/bacula/src/qt-console/clients/clients.h index 6b4b77a879..d7a9982279 100644 --- a/bacula/src/qt-console/clients/clients.h +++ b/bacula/src/qt-console/clients/clients.h @@ -55,6 +55,7 @@ private slots: void populateTree(); void showJobs(); void consoleStatusClient(); + void statusClientWindow(); void consolePurgeJobs(); void prune(); diff --git a/bacula/src/qt-console/clients/clients.ui b/bacula/src/qt-console/clients/clients.ui index cd8e91acca..b00486c22f 100644 --- a/bacula/src/qt-console/clients/clients.ui +++ b/bacula/src/qt-console/clients/clients.ui @@ -13,14 +13,32 @@ Client Tree - + 9 - + + 9 + + + 9 + + + 9 + + + 6 + + 6 - + + + + 1 + + + @@ -78,6 +96,14 @@ Open the diaolog to prune for this client. + + + :/images/status.png + + + Status Client Window + + diff --git a/bacula/src/qt-console/status/clientstat.cpp b/bacula/src/qt-console/status/clientstat.cpp new file mode 100644 index 0000000000..54e9aedb6e --- /dev/null +++ b/bacula/src/qt-console/status/clientstat.cpp @@ -0,0 +1,306 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2007-2008 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 John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Version $Id: clientstat.cpp 5880 2007-11-09 01:20:40Z bartleyd2 $ + * + * Dirk Bartley, March 2007 + */ + +#include +#include +#include "bat.h" +#include "clientstat.h" + +/* + * .status client=XXX header + * .status client=XXX running + * .status client=XXX terminated + */ + +/* + * Constructor for the class + */ +ClientStat::ClientStat(QString &client) +{ + m_client = client; + setupUi(this); + m_name = tr("Director Status"); + m_closeable = true; + pgInitialize(); + QTreeWidgetItem* thisitem = mainWin->getFromHash(this); + thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/status.png"))); + m_cursor = new QTextCursor(textEdit->document()); + + readSettings(); + dockPage(); + m_timer = new QTimer(this); + QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(timerTriggered())); + m_timer->start(mainWin->m_refreshStatusDirInterval*1000); + + createConnections(); +} + +void ClientStat::getFont() +{ + QFont font = textEdit->font(); + + QString dirname; + m_console->getDirResName(dirname); + QSettings settings(dirname, "bat"); + settings.beginGroup("Console"); + font.setFamily(settings.value("consoleFont", "Courier").value()); + font.setPointSize(settings.value("consolePointSize", 10).toInt()); + font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool()); + settings.endGroup(); + textEdit->setFont(font); +} + +/* + * Write the m_splitter settings in the destructor + */ +ClientStat::~ClientStat() +{ + writeSettings(); +} + +/* + * Populate all tables and header widgets + */ +void ClientStat::populateAll() +{ + if (!m_console->preventInUseConnect()) + return; + populateHeader(); + populateTerminated(); + populateRunning(); +} + +/* + * Timer is triggered, see if is current and repopulate. + */ +void ClientStat::timerTriggered() +{ + bool iscurrent = mainWin->stackedWidget->currentIndex() == mainWin->stackedWidget->indexOf(this); + if (((isDocked() && iscurrent) || (!isDocked())) && mainWin->m_refreshStatusDir) { + if (m_console->is_ready()) + populateAll(); + } +} + +/* + * Populate header text widget + */ +void ClientStat::populateHeader() +{ + QString command = QString(".status client=\"" + m_client + "\" header"); + QStringList results; + textEdit->clear(); + + if (m_console->dir_cmd(command, results)) { + foreach (QString line, results) { + line += "\n"; + textEdit->insertPlainText(line); + } + } +} + +/* + * Populate teminated table + */ +void ClientStat::populateTerminated() +{ + QString command = QString(".status client=\"" + m_client + "\" terminated"); + QStringList results; + QBrush blackBrush(Qt::black); + + terminatedTable->clear(); + QStringList headerlist = (QStringList() + << tr("Job Id") << tr("Job Level") << tr("Job Files") + << tr("Job Bytes") << tr("Job Status") << tr("Job Time") + << tr("Job Name")); + QStringList flaglist = (QStringList() + << "R" << "L" << "R" << "R" << "LC" + << "L" << "L"); + + terminatedTable->setColumnCount(headerlist.size()); + terminatedTable->setHorizontalHeaderLabels(headerlist); + + if (m_console->dir_cmd(command, results)) { + int row = 0; + QTableWidgetItem* p_tableitem; + terminatedTable->setRowCount(results.size()); + foreach (QString line, results) { + /* Iterate through the record returned from the query */ + QStringList fieldlist = line.split("\t"); + int column = 0; + QString statusCode(""); + /* Iterate through fields in the record */ + foreach (QString field, fieldlist) { + field = field.trimmed(); /* strip leading & trailing spaces */ + p_tableitem = new QTableWidgetItem(field, 1); + p_tableitem->setForeground(blackBrush); + p_tableitem->setFlags(0); + if (flaglist[column].contains("R")) + p_tableitem->setTextAlignment(Qt::AlignRight); + if (flaglist[column].contains("C")) + if (field == "OK") + p_tableitem->setBackground(Qt::green); + else + p_tableitem->setBackground(Qt::red); + terminatedTable->setItem(row, column, p_tableitem); + column += 1; + } + row += 1; + } + } + terminatedTable->resizeColumnsToContents(); + terminatedTable->resizeRowsToContents(); + terminatedTable->verticalHeader()->hide(); +} + +/* + * Populate running table + */ +void ClientStat::populateRunning() +{ + QString command = QString(".status client=\"" + m_client + "\" running"); + Pmsg1(000, "Clients running cmd : %s\n",command.toUtf8().data()); + QStringList results; + QBrush blackBrush(Qt::black); + + runningTable->clear(); + QStringList headerlist = (QStringList() + << tr("Job Id") << tr("Job Level") << tr("Job Data") << tr("Job Info")); + + runningTable->setColumnCount(headerlist.size()); + runningTable->setHorizontalHeaderLabels(headerlist); + + if (m_console->dir_cmd(command, results)) { + int row = 0; + QTableWidgetItem* p_tableitem; + runningTable->setRowCount(results.size()); + foreach (QString line, results) { + /* Iterate through the record returned from the query */ + QStringList fieldlist = line.split("\t"); + int column = 0; + QString statusCode(""); + /* Iterate through fields in the record */ + foreach (QString field, fieldlist) { + field = field.trimmed(); /* strip leading & trailing spaces */ + p_tableitem = new QTableWidgetItem(field, 1); + p_tableitem->setForeground(blackBrush); + p_tableitem->setFlags(0); + runningTable->setItem(row, column, p_tableitem); + column += 1; + } + row += 1; + } + } + runningTable->resizeColumnsToContents(); + runningTable->resizeRowsToContents(); + runningTable->verticalHeader()->hide(); +} + +/* + * When the treeWidgetItem in the page selector tree is singleclicked, Make sure + * The tree has been populated. + */ +void ClientStat::PgSeltreeWidgetClicked() +{ + if (!m_populated) { + populateAll(); + m_populated=true; + } +} + +/* + * Virtual function override of pages function which is called when this page + * is visible on the stack + */ +void ClientStat::currentStackItem() +{ + populateAll(); + if (!m_populated) { + m_populated=true; + } +} + +/* + * Function to create connections for context sensitive menu for this and + * the page selector + */ +void ClientStat::createConnections() +{ + connect(actionRefresh, SIGNAL(triggered()), this, + SLOT(populateAll())); + connect(actionCancelRunning, SIGNAL(triggered()), this, + SLOT(consoleCancelJob())); + + runningTable->setContextMenuPolicy(Qt::ActionsContextMenu); + runningTable->addAction(actionRefresh); + runningTable->addAction(actionCancelRunning); +} + +/* + * Save user settings associated with this page + */ +void ClientStat::writeSettings() +{ + QSettings settings(m_console->m_dir->name(), "bat"); + settings.beginGroup(m_groupText); + settings.setValue(m_splitText, splitter->saveState()); + settings.endGroup(); +} + +/* + * Read and restore user settings associated with this page + */ +void ClientStat::readSettings() +{ + m_groupText = "ClientStatPage"; + m_splitText = "splitterSizes_0"; + QSettings settings(m_console->m_dir->name(), "bat"); + settings.beginGroup(m_groupText); + splitter->restoreState(settings.value(m_splitText).toByteArray()); + settings.endGroup(); +} + +/* + * Cancel a running job + */ +void ClientStat::consoleCancelJob() +{ + int currentrow = runningTable->currentRow(); + QTableWidgetItem *item = runningTable->item(currentrow, 0); + if (item) { + QString text = item->text(); + QString cmd("cancel jobid="); + cmd += text; + consoleCommand(cmd); + } +} diff --git a/bacula/src/qt-console/status/clientstat.h b/bacula/src/qt-console/status/clientstat.h new file mode 100644 index 0000000000..a2ab3f13dc --- /dev/null +++ b/bacula/src/qt-console/status/clientstat.h @@ -0,0 +1,73 @@ +#ifndef _CLIENTSTAT_H_ +#define _CLIENTSTAT_H_ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2007-2007 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 John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Version $Id: clientstat.h 5372 2007-08-17 12:17:04Z kerns $ + * + * Dirk Bartley, March 2007 + */ + +#include +#include "ui_clientstat.h" +#include "console.h" +#include "pages.h" + +class ClientStat : public Pages, public Ui::ClientStatForm +{ + Q_OBJECT + +public: + ClientStat(QString&); + ~ClientStat(); + virtual void PgSeltreeWidgetClicked(); + virtual void currentStackItem(); + +public slots: + void populateHeader(); + void populateTerminated(); + void populateRunning(); + void populateAll(); + +private slots: + void timerTriggered(); + void consoleCancelJob(); + +private: + void createConnections(); + void writeSettings(); + void readSettings(); + bool m_populated; + QTextCursor *m_cursor; + void getFont(); + QString m_groupText, m_splitText; + QTimer *m_timer; + QString m_client; +}; + +#endif /* _CLIENTSTAT_H_ */ diff --git a/bacula/src/qt-console/status/clientstat.ui b/bacula/src/qt-console/status/clientstat.ui new file mode 100644 index 0000000000..1af11ec46d --- /dev/null +++ b/bacula/src/qt-console/status/clientstat.ui @@ -0,0 +1,198 @@ + + ClientStatForm + + + + 0 + 0 + 504 + 410 + + + + Form + + + + 9 + + + 9 + + + 9 + + + 9 + + + 6 + + + 6 + + + + + Qt::Vertical + + + + + 200 + 0 + + + + + 0 + 0 + + + + + 16777215 + 100 + + + + + 1 + 0 + + + + Qt::StrongFocus + + + false + + + + + + + + + + + + Qt::ScrollBarAsNeeded + + + QTextEdit::AutoNone + + + false + + + + + + QTextEdit::NoWrap + + + true + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::LeftToRight + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:13pt; font-weight:600;">Running Jobs</span></p></body></html> + + + Qt::AlignCenter + + + + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::LeftToRight + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:13pt; font-weight:600;">Terminated Jobs</span></p></body></html> + + + Qt::AlignCenter + + + + + + + + + + + + + + :/images/view-refresh.png + + + Refresh + + + + + :/images/utilities-terminal.png + + + Cancel Running Job + + + + + + + + -- 2.39.5