]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/clients/clients.cpp
Backport from BEE
[bacula/bacula] / bacula / src / qt-console / clients / clients.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16
17 /*
18  *   Version $Id$
19  *
20  *  Clients Class
21  *
22  *   Dirk Bartley, March 2007
23  *
24  */
25
26 #include "bat.h"
27 #include <QAbstractEventDispatcher>
28 #include <QMenu>
29 #include "clients/clients.h"
30 #include "run/run.h"
31 #include "status/clientstat.h"
32 #include "util/fmtwidgetitem.h"
33
34 Clients::Clients() : Pages()
35 {
36    setupUi(this);
37    m_name = tr("Clients");
38    pgInitialize();
39    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
40    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/network-server.png")));
41
42    /* tableWidget, Storage Tree Tree Widget inherited from ui_client.h */
43    m_populated = false;
44    m_checkcurwidget = true;
45    m_closeable = false;
46    m_firstpopulation = true;
47    /* add context sensitive menu items specific to this classto the page
48     * selector tree. m_contextActions is QList of QActions */
49    m_contextActions.append(actionRefreshClients);
50    createContextMenu();
51 }
52
53 Clients::~Clients()
54 {
55 }
56
57 /*
58  * The main meat of the class!!  The function that queries the director and
59  * creates the widgets with appropriate values.
60  */
61 void Clients::populateTable()
62 {
63    m_populated = true;
64
65    Freeze frz(*tableWidget); /* disable updating*/
66
67    QStringList headerlist = (QStringList() << tr("Client Name") << tr("File Retention")
68        << tr("Job Retention") << tr("AutoPrune") << tr("ClientId") << tr("Uname") );
69
70    int sortcol = headerlist.indexOf(tr("Client Name"));
71    Qt::SortOrder sortord = Qt::AscendingOrder;
72    if (tableWidget->rowCount()) {
73       sortcol = tableWidget->horizontalHeader()->sortIndicatorSection();
74       sortord = tableWidget->horizontalHeader()->sortIndicatorOrder();
75    }
76
77    m_checkcurwidget = false;
78    tableWidget->clear();
79    m_checkcurwidget = true;
80
81    tableWidget->setColumnCount(headerlist.count());
82    tableWidget->setHorizontalHeaderLabels(headerlist);
83    tableWidget->horizontalHeader()->setHighlightSections(false);
84    tableWidget->setRowCount(m_console->client_list.count());
85    tableWidget->verticalHeader()->hide();
86    tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
87    tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
88    tableWidget->setSortingEnabled(false); /* rows move on insert if sorting enabled */
89    bool first = true;
90    QString client_comsep("");
91    foreach (QString clientName, m_console->client_list){
92       if (first) {
93          client_comsep += "'" + clientName + "'";
94          first = false;
95       }
96       else
97          client_comsep += ",'" + clientName + "'";
98    }
99
100    if (client_comsep != "") {
101       QString query("");
102       query += "SELECT Name, FileRetention, JobRetention, AutoPrune, ClientId, Uname"
103            " FROM Client"
104            " WHERE ClientId IN (SELECT MAX(ClientId) FROM Client WHERE";
105       query += " Name IN (" + client_comsep + ")";
106       query += " GROUP BY Name) ORDER BY Name";
107
108       QStringList results;
109       if (mainWin->m_sqlDebug)
110          Pmsg1(000, "Clients query cmd : %s\n",query.toUtf8().data());
111       if (m_console->sql_cmd(query, results)) {
112          int row = 0;
113
114          /* Iterate through the record returned from the query */
115          foreach (QString resultline, results) {
116             QStringList fieldlist = resultline.split("\t");
117
118             if (m_firstpopulation) {
119                settingsOpenStatus(fieldlist[0]);
120             }
121
122             TableItemFormatter item(*tableWidget, row);
123
124             /* Iterate through fields in the record */
125             QStringListIterator fld(fieldlist);
126             int col = 0;
127
128             /* name */
129             item.setTextFld(col++, fld.next());
130
131             /* file retention */
132             item.setDurationFld(col++, fld.next());
133
134             /* job retention */
135             item.setDurationFld(col++, fld.next());
136
137             /* autoprune */
138             item.setBoolFld(col++, fld.next());
139
140             /* client id */
141             item.setNumericFld(col++, fld.next());
142
143             /* uname */
144             item.setTextFld(col++, fld.next());
145
146             row++;
147          }
148       }
149    }
150    /* set default sorting */
151    tableWidget->sortByColumn(sortcol, sortord);
152    tableWidget->setSortingEnabled(true);
153
154    /* Resize rows and columns */
155    tableWidget->resizeColumnsToContents();
156    tableWidget->resizeRowsToContents();
157
158    /* make read only */
159    int rcnt = tableWidget->rowCount();
160    int ccnt = tableWidget->columnCount();
161    for(int r=0; r < rcnt; r++) {
162       for(int c=0; c < ccnt; c++) {
163          QTableWidgetItem* item = tableWidget->item(r, c);
164          if (item) {
165             item->setFlags(Qt::ItemFlags(item->flags() & (~Qt::ItemIsEditable)));
166          }
167       }
168    }
169    m_firstpopulation = false;
170 }
171
172 /*
173  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
174  * The tree has been populated.
175  */
176 void Clients::PgSeltreeWidgetClicked()
177 {
178    if(!m_populated) {
179       populateTable();
180    }
181    if (!isOnceDocked()) {
182       dockPage();
183    }
184 }
185
186 /*
187  * Added to set the context menu policy based on currently active treeWidgetItem
188  * signaled by currentItemChanged
189  */
190 void Clients::tableItemChanged(QTableWidgetItem *currentwidgetitem, QTableWidgetItem *previouswidgetitem )
191 {
192    /* m_checkcurwidget checks to see if this is during a refresh, which will segfault */
193    if (m_checkcurwidget) {
194       int currentRow = currentwidgetitem->row();
195       QTableWidgetItem *currentrowzeroitem = tableWidget->item(currentRow, 0);
196       m_currentlyselected = currentrowzeroitem->text();
197
198       /* The Previous item */
199       if (previouswidgetitem) { /* avoid a segfault if first time */
200          tableWidget->removeAction(actionListJobsofClient);
201          tableWidget->removeAction(actionStatusClientWindow);
202          tableWidget->removeAction(actionPurgeJobs);
203          tableWidget->removeAction(actionPrune);
204       }
205
206       if (m_currentlyselected.length() != 0) {
207          /* set a hold variable to the client name in case the context sensitive
208           * menu is used */
209          tableWidget->addAction(actionListJobsofClient);
210          tableWidget->addAction(actionStatusClientWindow);
211          tableWidget->addAction(actionPurgeJobs);
212          tableWidget->addAction(actionPrune);
213       }
214    }
215 }
216
217 /*
218  * Setup a context menu
219  * Made separate from populate so that it would not create context menu over and
220  * over as the tree is repopulated.
221  */
222 void Clients::createContextMenu()
223 {
224    tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
225    tableWidget->addAction(actionRefreshClients);
226    /* for the tableItemChanged to maintain m_currentJob */
227    connect(tableWidget, SIGNAL(
228            currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
229            this, SLOT(tableItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
230
231    /* connect to the action specific to this pages class */
232    connect(actionRefreshClients, SIGNAL(triggered()), this,
233                 SLOT(populateTable()));
234    connect(actionListJobsofClient, SIGNAL(triggered()), this,
235                 SLOT(showJobs()));
236    connect(actionStatusClientWindow, SIGNAL(triggered()), this,
237                 SLOT(statusClientWindow()));
238    connect(actionPurgeJobs, SIGNAL(triggered()), this,
239                 SLOT(consolePurgeJobs()));
240    connect(actionPrune, SIGNAL(triggered()), this,
241                 SLOT(prune()));
242 }
243
244 /*
245  * Function responding to actionListJobsofClient which calls mainwin function
246  * to create a window of a list of jobs of this client.
247  */
248 void Clients::showJobs()
249 {
250    QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
251    mainWin->createPageJobList("", m_currentlyselected, "", "", parentItem);
252 }
253
254 /*
255  * Function responding to actionListJobsofClient which calls mainwin function
256  * to create a window of a list of jobs of this client.
257  */
258 void Clients::consoleStatusClient()
259 {
260    QString cmd("status client=");
261    cmd += m_currentlyselected;
262    consoleCommand(cmd);
263 }
264
265 /*
266  * Virtual function which is called when this page is visible on the stack
267  */
268 void Clients::currentStackItem()
269 {
270    if(!m_populated) {
271       populateTable();
272       /* Create the context menu for the client table */
273    }
274 }
275
276 /*
277  * Function responding to actionPurgeJobs
278  */
279 void Clients::consolePurgeJobs()
280 {
281    if (QMessageBox::warning(this, "Bat",
282       tr("Are you sure you want to purge all jobs of client \"%1\" ?\n"
283 "The Purge command will delete associated Catalog database records from Jobs and"
284 " Volumes without considering the retention period. Purge  works only on the"
285 " Catalog database and does not affect data written to Volumes. This command can"
286 " be dangerous because you can delete catalog records associated with current"
287 " backups of files, and we recommend that you do not use it unless you know what"
288 " you are doing.\n\n"
289 " Is there any way I can get you to click Cancel here?  You really don't want to do"
290 " this\n\n"
291          "Press OK to proceed with the purge operation?").arg(m_currentlyselected),
292          QMessageBox::Ok | QMessageBox::Cancel,
293          QMessageBox::Cancel)
294       == QMessageBox::Cancel) { return; }
295
296    QString cmd("purge jobs client=");
297    cmd += m_currentlyselected;
298    consoleCommand(cmd);
299 }
300
301 /*
302  * Function responding to actionPrune
303  */
304 void Clients::prune()
305 {
306    new prunePage("", m_currentlyselected);
307 }
308
309 /*
310  * Function responding to action to create new client status window
311  */
312 void Clients::statusClientWindow()
313 {
314    /* if one exists, then just set it current */
315    bool found = false;
316    foreach(Pages *page, mainWin->m_pagehash) {
317       if (mainWin->currentConsole() == page->console()) {
318          if (page->name() == tr("Client Status %1").arg(m_currentlyselected)) {
319             found = true;
320             page->setCurrent();
321          }
322       }
323    }
324    if (!found) {
325       QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
326       new ClientStat(m_currentlyselected, parentItem);
327    }
328 }
329
330 /*
331  * If first time, then check to see if there were status pages open the last time closed
332  * if so open
333  */
334 void Clients::settingsOpenStatus(QString &client)
335 {
336    QSettings settings(m_console->m_dir->name(), "bat");
337
338    settings.beginGroup("OpenOnExit");
339    QString toRead = "ClientStatus_" + client;
340    if (settings.value(toRead) == 1) {
341       new ClientStat(client, mainWin->getFromHash(this));
342       setCurrent();
343       mainWin->getFromHash(this)->setExpanded(true);
344    }
345    settings.endGroup();
346 }