/*
- Bacula® - The Network Backup Solution
-
- Copyright (C) 2000-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 plus additions
- that are listed 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.
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ 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: client.cpp 4230 2007-02-21 20:07:37Z kerns $
- *
* Clients Class
*
* Dirk Bartley, March 2007
*
*/
+#include "bat.h"
#include <QAbstractEventDispatcher>
#include <QMenu>
-#include "bat.h"
#include "clients/clients.h"
#include "run/run.h"
+#include "status/clientstat.h"
+#include "util/fmtwidgetitem.h"
-Clients::Clients()
+Clients::Clients() : Pages()
{
setupUi(this);
- m_name = "Clients";
+ m_name = tr("Clients");
pgInitialize();
QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
- thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/network-server.svg")));
+ thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/network-server.png")));
- /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_client.h */
+ /* tableWidget, Storage Tree Tree Widget inherited from ui_client.h */
m_populated = false;
m_checkcurwidget = true;
m_closeable = false;
+ m_firstpopulation = true;
/* add context sensitive menu items specific to this classto the page
* selector tree. m_contextActions is QList of QActions */
m_contextActions.append(actionRefreshClients);
createContextMenu();
- dockPage();
}
Clients::~Clients()
}
/*
- * The main meat of the class!! The function that querries the director and
+ * The main meat of the class!! The function that queries the director and
* creates the widgets with appropriate values.
*/
-void Clients::populateTree()
+void Clients::populateTable()
{
- QTreeWidgetItem *clientItem, *topItem;
+ m_populated = true;
- if (!m_console->preventInUseConnect())
- return;
- m_checkcurwidget = false;
- mp_treeWidget->clear();
- m_checkcurwidget = true;
+ Freeze frz(*tableWidget); /* disable updating*/
- QStringList headerlist = (QStringList() << "Client Name" << "File Retention"
- << "Job Retention" << "AutoPrune" << "ClientId" << "Uname" );
+ QStringList headerlist = (QStringList() << tr("Client Name") << tr("File Retention")
+ << tr("Job Retention") << tr("AutoPrune") << tr("ClientId") << tr("Uname") );
- topItem = new QTreeWidgetItem(mp_treeWidget);
- topItem->setText(0, "Clients");
- topItem->setData(0, Qt::UserRole, 0);
- topItem->setExpanded(true);
+ int sortcol = headerlist.indexOf(tr("Client Name"));
+ Qt::SortOrder sortord = Qt::AscendingOrder;
+ if (tableWidget->rowCount()) {
+ sortcol = tableWidget->horizontalHeader()->sortIndicatorSection();
+ sortord = tableWidget->horizontalHeader()->sortIndicatorOrder();
+ }
- mp_treeWidget->setColumnCount(headerlist.count());
- mp_treeWidget->setHeaderLabels(headerlist);
+ m_checkcurwidget = false;
+ tableWidget->clear();
+ m_checkcurwidget = true;
+ tableWidget->setColumnCount(headerlist.count());
+ tableWidget->setHorizontalHeaderLabels(headerlist);
+ tableWidget->horizontalHeader()->setHighlightSections(false);
+ tableWidget->setRowCount(m_console->client_list.count());
+ tableWidget->verticalHeader()->hide();
+ tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+ tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ tableWidget->setSortingEnabled(false); /* rows move on insert if sorting enabled */
+ bool first = true;
+ QString client_comsep("");
foreach (QString clientName, m_console->client_list){
- clientItem = new QTreeWidgetItem(topItem);
- clientItem->setText(0, clientName);
- clientItem->setData(0, Qt::UserRole, 1);
- clientItem->setExpanded(true);
+ if (first) {
+ client_comsep += "'" + clientName + "'";
+ first = false;
+ }
+ else
+ client_comsep += ",'" + clientName + "'";
+ }
- /* Set up query QString and header QStringList */
+ if (client_comsep != "") {
QString query("");
- query += "SELECT FileRetention, JobRetention, AutoPrune, ClientId, Uname"
+ query += "SELECT Name, FileRetention, JobRetention, AutoPrune, ClientId, Uname"
" FROM Client"
- " WHERE ";
- query += " Name='" + clientName + "'";
- query += " ORDER BY Name";
+ " WHERE ClientId IN (SELECT MAX(ClientId) FROM Client WHERE";
+ query += " Name IN (" + client_comsep + ")";
+ query += " GROUP BY Name) ORDER BY Name";
QStringList results;
- /* This could be a log item */
- if (mainWin->m_sqlDebug) {
+ if (mainWin->m_sqlDebug)
Pmsg1(000, "Clients query cmd : %s\n",query.toUtf8().data());
- }
if (m_console->sql_cmd(query, results)) {
- int resultCount = results.count();
- if (resultCount == 1){
- QString resultline;
- QString field;
- QStringList fieldlist;
- /* there will only be one of these */
- foreach (resultline, results) {
- fieldlist = resultline.split("\t");
- int index = 0;
- /* Iterate through fields in the record */
- foreach (field, fieldlist) {
- field = field.trimmed(); /* strip leading & trailing spaces */
- clientItem->setData(index+1, Qt::UserRole, 1);
- /* Put media fields under the pool tree item */
- clientItem->setData(index+1, Qt::UserRole, 1);
- clientItem->setText(index+1, field);
- index++;
- }
+ int row = 0;
+
+ /* Iterate through the record returned from the query */
+ foreach (QString resultline, results) {
+ QStringList fieldlist = resultline.split("\t");
+
+ if (fieldlist.size() < 5) { // Uname is checked after
+ Pmsg1(0, "Unexpected line %s\n", resultline.toUtf8().data());
+ continue;
+ }
+ if (m_firstpopulation) {
+ settingsOpenStatus(fieldlist[0]);
}
+
+ TableItemFormatter item(*tableWidget, row);
+
+ /* Iterate through fields in the record */
+ QStringListIterator fld(fieldlist);
+ int col = 0;
+
+ /* name */
+ item.setTextFld(col++, fld.next());
+
+ /* file retention */
+ item.setDurationFld(col++, fld.next());
+
+ /* job retention */
+ item.setDurationFld(col++, fld.next());
+
+ /* autoprune */
+ item.setBoolFld(col++, fld.next());
+
+ /* client id */
+ item.setNumericFld(col++, fld.next());
+
+ /* uname */
+ if (fld.hasNext()) {
+ item.setTextFld(col++, fld.next());
+ } else {
+ item.setTextFld(col++, "");
+ }
+
+ row++;
}
}
}
- /* Resize the columns */
- for(int cnter=0; cnter<headerlist.size(); cnter++) {
- mp_treeWidget->resizeColumnToContents(cnter);
+ /* set default sorting */
+ tableWidget->sortByColumn(sortcol, sortord);
+ tableWidget->setSortingEnabled(true);
+
+ /* Resize rows and columns */
+ tableWidget->resizeColumnsToContents();
+ tableWidget->resizeRowsToContents();
+
+ /* make read only */
+ int rcnt = tableWidget->rowCount();
+ int ccnt = tableWidget->columnCount();
+ for(int r=0; r < rcnt; r++) {
+ for(int c=0; c < ccnt; c++) {
+ QTableWidgetItem* item = tableWidget->item(r, c);
+ if (item) {
+ item->setFlags(Qt::ItemFlags(item->flags() & (~Qt::ItemIsEditable)));
+ }
+ }
}
+ m_firstpopulation = false;
}
/*
void Clients::PgSeltreeWidgetClicked()
{
if(!m_populated) {
- populateTree();
- m_populated=true;
+ populateTable();
+ }
+ if (!isOnceDocked()) {
+ dockPage();
}
}
* Added to set the context menu policy based on currently active treeWidgetItem
* signaled by currentItemChanged
*/
-void Clients::treeItemChanged(QTreeWidgetItem *currentwidgetitem, QTreeWidgetItem *previouswidgetitem )
+void Clients::tableItemChanged(QTableWidgetItem *currentwidgetitem, QTableWidgetItem *previouswidgetitem )
{
/* m_checkcurwidget checks to see if this is during a refresh, which will segfault */
if (m_checkcurwidget) {
+ int currentRow = currentwidgetitem->row();
+ QTableWidgetItem *currentrowzeroitem = tableWidget->item(currentRow, 0);
+ m_currentlyselected = currentrowzeroitem->text();
+
/* The Previous item */
if (previouswidgetitem) { /* avoid a segfault if first time */
- int treedepth = previouswidgetitem->data(0, Qt::UserRole).toInt();
- if (treedepth == 1){
- mp_treeWidget->removeAction(actionListJobsofClient);
- mp_treeWidget->removeAction(actionStatusClientInConsole);
- mp_treeWidget->removeAction(actionPurgeJobs);
- mp_treeWidget->removeAction(actionPrune);
- }
+ tableWidget->removeAction(actionListJobsofClient);
+ tableWidget->removeAction(actionStatusClientWindow);
+ tableWidget->removeAction(actionPurgeJobs);
+ tableWidget->removeAction(actionPrune);
}
- int treedepth = currentwidgetitem->data(0, Qt::UserRole).toInt();
- if (treedepth == 1){
+ if (m_currentlyselected.length() != 0) {
/* set a hold variable to the client name in case the context sensitive
* menu is used */
- m_currentlyselected=currentwidgetitem->text(0);
- mp_treeWidget->addAction(actionListJobsofClient);
- mp_treeWidget->addAction(actionStatusClientInConsole);
- mp_treeWidget->addAction(actionPurgeJobs);
- mp_treeWidget->addAction(actionPrune);
+ tableWidget->addAction(actionListJobsofClient);
+ tableWidget->addAction(actionStatusClientWindow);
+ tableWidget->addAction(actionPurgeJobs);
+ tableWidget->addAction(actionPrune);
}
}
}
*/
void Clients::createContextMenu()
{
- mp_treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
- mp_treeWidget->addAction(actionRefreshClients);
- connect(mp_treeWidget, SIGNAL(
- currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
- this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+ tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
+ tableWidget->addAction(actionRefreshClients);
+ /* for the tableItemChanged to maintain m_currentJob */
+ connect(tableWidget, SIGNAL(
+ currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
+ this, SLOT(tableItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
+
/* connect to the action specific to this pages class */
connect(actionRefreshClients, SIGNAL(triggered()), this,
- SLOT(populateTree()));
+ SLOT(populateTable()));
connect(actionListJobsofClient, SIGNAL(triggered()), this,
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,
void Clients::showJobs()
{
QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
- mainWin->createPageJobList("", m_currentlyselected, "", parentItem);
+ mainWin->createPageJobList("", m_currentlyselected, "", "", parentItem);
}
/*
void Clients::currentStackItem()
{
if(!m_populated) {
- populateTree();
- /* Create the context menu for the client tree */
- m_populated=true;
+ populateTable();
+ /* Create the context menu for the client table */
}
}
*/
void Clients::consolePurgeJobs()
{
- if (QMessageBox::warning(this, tr("Bat"),
- tr("Are you sure you want to purge ?? !!!.\n"
+ if (QMessageBox::warning(this, "Bat",
+ tr("Are you sure you want to purge all jobs of client \"%1\" ?\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\n"
-" Is there any way I can get you to Click cancel here. You really don't want to do"
+" Is there any way I can get you to click Cancel here? You really don't want to do"
" this\n\n"
- "Press OK to proceed with the purge operation?"),
- QMessageBox::Ok | QMessageBox::Cancel)
+ "Press OK to proceed with the purge operation?").arg(m_currentlyselected),
+ QMessageBox::Ok | QMessageBox::Cancel,
+ QMessageBox::Cancel)
== QMessageBox::Cancel) { return; }
QString cmd("purge jobs client=");
new prunePage("", m_currentlyselected);
}
+/*
+ * Function responding to action to create new client status window
+ */
+void Clients::statusClientWindow()
+{
+ /* if one exists, then just set it current */
+ bool found = false;
+ foreach(Pages *page, mainWin->m_pagehash) {
+ if (mainWin->currentConsole() == page->console()) {
+ if (page->name() == tr("Client Status %1").arg(m_currentlyselected)) {
+ found = true;
+ page->setCurrent();
+ }
+ }
+ }
+ if (!found) {
+ QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
+ new ClientStat(m_currentlyselected, parentItem);
+ }
+}
+
+/*
+ * If first time, then check to see if there were status pages open the last time closed
+ * if so open
+ */
+void Clients::settingsOpenStatus(QString &client)
+{
+ QSettings settings(m_console->m_dir->name(), "bat");
+
+ settings.beginGroup("OpenOnExit");
+ QString toRead = "ClientStatus_" + client;
+ if (settings.value(toRead) == 1) {
+ new ClientStat(client, mainWin->getFromHash(this));
+ setCurrent();
+ mainWin->getFromHash(this)->setExpanded(true);
+ }
+ settings.endGroup();
+}