1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many 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    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Dirk Bartley, March 2007
22  */
23 
24 #include "bat.h"
25 #include <QAbstractEventDispatcher>
26 #include <QTableWidgetItem>
27 #include "dirstat.h"
28 
29 static bool working = false;         /* prevent timer recursion */
30 
31 /*
32  * Constructor for the class
33  */
DirStat()34 DirStat::DirStat() : Pages()
35 {
36    setupUi(this);
37    m_name = tr("Director Status");
38    pgInitialize();
39    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
40    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/status.png")));
41    m_cursor = new QTextCursor(textEdit->document());
42 
43    m_timer = new QTimer(this);
44    readSettings();
45    m_timer->start(1000);
46 
47    createConnections();
48    setCurrent();
49 }
50 
getFont()51 void DirStat::getFont()
52 {
53    QFont font = textEdit->font();
54 
55    QString dirname;
56    m_console->getDirResName(dirname);
57    QSettings settings(dirname, "bat");
58    settings.beginGroup("Console");
59    font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
60    font.setPointSize(settings.value("consolePointSize", 10).toInt());
61    font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
62    settings.endGroup();
63    textEdit->setFont(font);
64 }
65 
66 /*
67  * Write the m_splitter settings in the destructor
68  */
~DirStat()69 DirStat::~DirStat()
70 {
71    writeSettings();
72 }
73 
74 /*
75  * Populate all tables and header widgets
76  */
populateAll()77 void DirStat::populateAll()
78 {
79    populateHeader();
80    populateTerminated();
81    populateScheduled();
82    populateRunning();
83 }
84 
85 /*
86  *  Timer is triggered, see if is current and repopulate.
87  */
timerTriggered()88 void DirStat::timerTriggered()
89 {
90    double value = timerDisplay->value();
91    value -= 1;
92    if (value <= 0 && !working) {
93       working = true;
94       value = spinBox->value();
95       bool iscurrent = mainWin->tabWidget->currentIndex() == mainWin->tabWidget->indexOf(this);
96       if (((isDocked() && iscurrent) || ((!isDocked()) && isOnceDocked())) && (checkBox->checkState() == Qt::Checked)) {
97          populateAll();
98       }
99       working = false;
100    }
101    timerDisplay->display(value);
102 }
103 
104 /*
105  * Populate header text widget
106  */
populateHeader()107 void DirStat::populateHeader()
108 {
109    QString command = QString(".status dir header");
110    if (mainWin->m_commandDebug)
111       Pmsg1(000, "sending command : %s\n",command.toUtf8().data());
112    QStringList results;
113    textEdit->clear();
114 
115    if (m_console->dir_cmd(command, results)) {
116       foreach (QString line, results) {
117          line += "\n";
118          textEdit->insertPlainText(line);
119       }
120    }
121 }
122 
123 /*
124  * Populate teminated table
125  */
populateTerminated()126 void DirStat::populateTerminated()
127 {
128    QString command = QString(".status dir terminated");
129    if (mainWin->m_commandDebug)
130       Pmsg1(000, "sending command : %s\n",command.toUtf8().data());
131    QStringList results;
132    QBrush blackBrush(Qt::black);
133 
134    terminatedTable->clear();
135    QStringList headerlist = (QStringList()
136       << tr("Job Id") << tr("Job Level") << tr("Job Files")
137       << tr("Job Bytes") << tr("Job Status") << tr("Job Time")
138       << tr("Job Name"));
139    QStringList flaglist = (QStringList()
140       << "R" << "L" << "R" << "R" << "LC"
141       << "L" << "L");
142 
143    terminatedTable->setColumnCount(headerlist.size());
144    terminatedTable->setHorizontalHeaderLabels(headerlist);
145 
146    if (m_console->dir_cmd(command, results)) {
147       int row = 0;
148       QTableWidgetItem* p_tableitem;
149       terminatedTable->setRowCount(results.size());
150       foreach (QString line, results) {
151          /* Iterate through the record returned from the query */
152          QStringList fieldlist = line.split("\t");
153          int column = 0;
154          QString statusCode("");
155          /* Iterate through fields in the record */
156          foreach (QString field, fieldlist) {
157             field = field.trimmed();  /* strip leading & trailing spaces */
158             p_tableitem = new QTableWidgetItem(field, 1);
159             p_tableitem->setForeground(blackBrush);
160             p_tableitem->setFlags(0);
161             if (flaglist[column].contains("R"))
162                p_tableitem->setTextAlignment(Qt::AlignRight);
163             if (flaglist[column].contains("C")) {
164                if (field == "OK")
165                   p_tableitem->setBackground(Qt::green);
166                else
167                   p_tableitem->setBackground(Qt::red);
168             }
169             terminatedTable->setItem(results.size() - row - 1, column, p_tableitem);
170             column += 1;
171          }
172          row += 1;
173       }
174    }
175    terminatedTable->resizeColumnsToContents();
176    terminatedTable->resizeRowsToContents();
177    terminatedTable->verticalHeader()->hide();
178 }
179 
180 /*
181  * Populate scheduled table
182  */
populateScheduled()183 void DirStat::populateScheduled()
184 {
185    QString command = QString(".status dir scheduled");
186    if (mainWin->m_commandDebug)
187       Pmsg1(000, "sending command : %s\n",command.toUtf8().data());
188    QStringList results;
189    QBrush blackBrush(Qt::black);
190 
191    scheduledTable->clear();
192    QStringList headerlist = (QStringList()
193       << tr("Job Level") << tr("Job Type") << tr("Priority") << tr("Job Time")
194       << tr("Job Name") << tr("Volume"));
195    QStringList flaglist = (QStringList()
196       << "L" << "L" << "R" << "L" << "L" << "L");
197 
198    scheduledTable->setColumnCount(headerlist.size());
199    scheduledTable->setHorizontalHeaderLabels(headerlist);
200    scheduledTable->setSelectionBehavior(QAbstractItemView::SelectRows);
201    scheduledTable->setSelectionMode(QAbstractItemView::SingleSelection);
202 
203    if (m_console->dir_cmd(command, results)) {
204       int row = 0;
205       QTableWidgetItem* p_tableitem;
206       scheduledTable->setRowCount(results.size());
207       foreach (QString line, results) {
208          /* Iterate through the record returned from the query */
209          QStringList fieldlist = line.split("\t");
210          int column = 0;
211          QString statusCode("");
212          /* Iterate through fields in the record */
213          foreach (QString field, fieldlist) {
214             field = field.trimmed();  /* strip leading & trailing spaces */
215             p_tableitem = new QTableWidgetItem(field, 1);
216             p_tableitem->setForeground(blackBrush);
217             scheduledTable->setItem(row, column, p_tableitem);
218             column += 1;
219          }
220          row += 1;
221       }
222    }
223    scheduledTable->resizeColumnsToContents();
224    scheduledTable->resizeRowsToContents();
225    scheduledTable->verticalHeader()->hide();
226 }
227 
228 /*
229  * Populate running table
230  */
populateRunning()231 void DirStat::populateRunning()
232 {
233    QString command = QString(".status dir running");
234    if (mainWin->m_commandDebug)
235       Pmsg1(000, "sending command : %s\n",command.toUtf8().data());
236    QStringList results;
237    QBrush blackBrush(Qt::black);
238 
239    runningTable->clear();
240    QStringList headerlist = (QStringList()
241       << tr("Job Id") << tr("Job Level") << tr("Job Data") << tr("Job Info"));
242 
243    runningTable->setColumnCount(headerlist.size());
244    runningTable->setHorizontalHeaderLabels(headerlist);
245    runningTable->setSelectionBehavior(QAbstractItemView::SelectRows);
246 
247    if (m_console->dir_cmd(command, results)) {
248       int row = 0;
249       QTableWidgetItem* p_tableitem;
250       runningTable->setRowCount(results.size());
251       foreach (QString line, results) {
252          /* Iterate through the record returned from the query */
253          QStringList fieldlist = line.split("\t");
254          int column = 0;
255          QString statusCode("");
256          /* Iterate through fields in the record */
257          foreach (QString field, fieldlist) {
258             field = field.trimmed();  /* strip leading & trailing spaces */
259             p_tableitem = new QTableWidgetItem(field, 1);
260             p_tableitem->setForeground(blackBrush);
261             runningTable->setItem(row, column, p_tableitem);
262             column += 1;
263          }
264          row += 1;
265       }
266    }
267    runningTable->resizeColumnsToContents();
268    runningTable->resizeRowsToContents();
269    runningTable->verticalHeader()->hide();
270 }
271 
272 /*
273  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
274  * The tree has been populated.
275  */
PgSeltreeWidgetClicked()276 void DirStat::PgSeltreeWidgetClicked()
277 {
278    if (!m_populated) {
279       populateAll();
280       m_populated=true;
281    }
282    if (!isOnceDocked()) {
283       dockPage();
284    }
285 }
286 
287 /*
288  *  Virtual function override of pages function which is called when this page
289  *  is visible on the stack
290  */
currentStackItem()291 void DirStat::currentStackItem()
292 {
293    populateAll();
294    timerDisplay->display(spinBox->value());
295    if (!m_populated) {
296       m_populated=true;
297    }
298 }
299 
300 /*
301  * Function to create connections for context sensitive menu for this and
302  * the page selector
303  */
createConnections()304 void DirStat::createConnections()
305 {
306    connect(actionRefresh, SIGNAL(triggered()), this, SLOT(populateAll()));
307    connect(actionCancelRunning, SIGNAL(triggered()), this, SLOT(consoleCancelJob()));
308    connect(actionDisableScheduledJob, SIGNAL(triggered()), this, SLOT(consoleDisableJob()));
309    connect(m_timer, SIGNAL(timeout()), this, SLOT(timerTriggered()));
310 
311    scheduledTable->setContextMenuPolicy(Qt::ActionsContextMenu);
312    scheduledTable->addAction(actionRefresh);
313    scheduledTable->addAction(actionDisableScheduledJob);
314    terminatedTable->setContextMenuPolicy(Qt::ActionsContextMenu);
315    terminatedTable->addAction(actionRefresh);
316    runningTable->setContextMenuPolicy(Qt::ActionsContextMenu);
317    runningTable->addAction(actionRefresh);
318    runningTable->addAction(actionCancelRunning);
319 }
320 
321 /*
322  * Save user settings associated with this page
323  */
writeSettings()324 void DirStat::writeSettings()
325 {
326    QSettings settings(m_console->m_dir->name(), "bat");
327    settings.beginGroup(m_groupText);
328    settings.setValue(m_splitText, splitter->saveState());
329    settings.setValue("refreshInterval", spinBox->value());
330    settings.setValue("refreshCheck", checkBox->checkState());
331    settings.endGroup();
332 }
333 
334 /*
335  * Read and restore user settings associated with this page
336  */
readSettings()337 void DirStat::readSettings()
338 {
339    m_groupText = "DirStatPage";
340    m_splitText = "splitterSizes_0";
341    QSettings settings(m_console->m_dir->name(), "bat");
342    settings.beginGroup(m_groupText);
343    if (settings.contains(m_splitText)) { splitter->restoreState(settings.value(m_splitText).toByteArray()); }
344    spinBox->setValue(settings.value("refreshInterval", 28).toInt());
345    checkBox->setCheckState((Qt::CheckState)settings.value("refreshCheck", Qt::Checked).toInt());
346    settings.endGroup();
347 
348    timerDisplay->display(spinBox->value());
349 }
350 
351 /*
352  * Cancel a running job
353  */
consoleCancelJob()354 void DirStat::consoleCancelJob()
355 {
356    QList<int> rowList;
357    QList<QTableWidgetItem *> sitems = runningTable->selectedItems();
358    foreach (QTableWidgetItem *sitem, sitems) {
359       int row = sitem->row();
360       if (!rowList.contains(row)) {
361          rowList.append(row);
362       }
363    }
364 
365    QStringList selectedJobsList;
366    foreach(int row, rowList) {
367       QTableWidgetItem * sitem = runningTable->item(row, 0);
368       selectedJobsList.append(sitem->text());
369    }
370    foreach( QString job, selectedJobsList )
371    {
372       QString cmd("cancel jobid=");
373       cmd += job;
374       consoleCommand(cmd);
375    }
376 }
377 
378 /*
379  * Disable a scheduled Job
380  */
consoleDisableJob()381 void DirStat::consoleDisableJob()
382 {
383    int currentrow = scheduledTable->currentRow();
384    QTableWidgetItem *item = scheduledTable->item(currentrow, 4);
385    if (item) {
386       QString text = item->text();
387       QString cmd("disable job=\"");
388       cmd += text + '"';
389       consoleCommand(cmd);
390    }
391 }
392