]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/joblist/joblist.cpp
Prevent connecting with the Console::m_at_main_prompt member.
[bacula/bacula] / bacula / src / qt-console / joblist / joblist.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *   Version $Id: joblist.h 4230 2007-02-21 20:07:37Z kerns $
30  *
31  *   Dirk Bartley, March 2007
32  */
33  
34 #include <QAbstractEventDispatcher>
35 #include <QTableWidgetItem>
36 #include "bat.h"
37 #include "joblist.h"
38 #include "restore.h"
39 #include "joblog/joblog.h"
40
41 /*
42  * Constructor for the class
43  */
44 JobList::JobList(QString &mediaName, QString &clientname,
45          QTreeWidgetItem *parentTreeWidgetItem)
46 {
47    setupUi(this);
48    m_name = "Clients";
49    m_mediaName = mediaName;
50    m_clientName = clientname;
51    pgInitialize(parentTreeWidgetItem);
52    m_resultCount = 0;
53    m_populated = false;
54    m_closeable = false;
55    if ((m_mediaName != "") || (m_clientName != "")) { m_closeable=true; }
56    m_checkCurrentWidget = true;
57    createConnections();
58
59    /* Set Defaults for check and spin for limits */
60    limitCheckBox->setCheckState(Qt::Checked);
61    limitSpinBox->setValue(150);
62    daysCheckBox->setCheckState(Qt::Unchecked);
63    daysSpinBox->setValue(30);
64 }
65
66 /*
67  * The Meat of the class.
68  * This function will populate the QTableWidget, mp_tablewidget, with
69  * QTableWidgetItems representing the results of a query for what jobs exist on
70  * the media name passed from the constructor stored in m_mediaName.
71  */
72 void JobList::populateTable()
73 {
74    QStringList results;
75    QString resultline;
76    QBrush blackBrush(Qt::black);
77
78    if (!m_console->preventInUseConnect())
79        return;
80
81    /* Can't do this in constructor because not neccesarily conected in constructor */
82    if (!m_populated) {
83       clientsComboBox->addItem("Any");
84       clientsComboBox->addItems(m_console->client_list);
85       int clientIndex = clientsComboBox->findText(m_clientName, Qt::MatchExactly);
86       if (clientIndex != -1)
87          clientsComboBox->setCurrentIndex(clientIndex);
88
89       /* Not m_console->volume_list will query database */
90       QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
91       QStringList results, volumeList;
92       if (m_console->sql_cmd(query, results)) {
93          QString field;
94          QStringList fieldlist;
95          /* Iterate through the lines of results. */
96          foreach (QString resultline, results) {
97             fieldlist = resultline.split("\t");
98             volumeList.append(fieldlist[0]);
99          } /* foreach resultline */
100       } /* if results from query */
101       volumeComboBox->addItem("Any");
102       volumeComboBox->addItems(volumeList);
103       int volumeIndex = volumeComboBox->findText(m_mediaName, Qt::MatchExactly);
104       if (volumeIndex != -1) {
105          volumeComboBox->setCurrentIndex(volumeIndex);
106       }
107       jobComboBox->addItem("Any");
108       jobComboBox->addItems(m_console->job_list);
109       levelComboBox->addItem("Any");
110       levelComboBox->addItems( QStringList() << "F" << "D" << "I");
111       purgedComboBox->addItem("Any");
112       purgedComboBox->addItems( QStringList() << "0" << "1");
113       statusComboBox->addItem("Any");
114       QString statusQuery("SELECT JobStatusLong FROM Status");
115       QStringList statusResults, statusLongList;
116       if (m_console->sql_cmd(statusQuery, statusResults)) {
117          QString field;
118          QStringList fieldlist;
119          /* Iterate through the lines of results. */
120          foreach (QString resultline, statusResults) {
121             fieldlist = resultline.split("\t");
122             statusLongList.append(fieldlist[0]);
123          } /* foreach resultline */
124       } /* if results from statusquery */
125       statusComboBox->addItems(statusLongList);
126    }
127
128    /* Set up query */
129    QString query("");
130    int volumeIndex = volumeComboBox->currentIndex();
131    if (volumeIndex != -1)
132       m_mediaName = volumeComboBox->itemText(volumeIndex);
133    query += "SELECT DISTINCT Job.Jobid AS Id, Job.Name AS JobName, Client.Name AS Client,"
134             " Job.Starttime AS JobStart, Job.Type AS JobType,"
135             " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
136             " Job.JobBytes AS Bytes,"
137             " Job.JobStatus AS Status, Status.JobStatusLong AS StatusLong,"
138             " Job.PurgedFiles AS Purged"
139             " FROM Job,Client,Status";
140    if (m_mediaName != "Any") {
141       query += ",JobMedia,Media";
142    }
143    query += " WHERE Client.ClientId=Job.ClientId AND Job.JobStatus=Status.JobStatus";
144    if (m_mediaName != "Any") {
145       query += " AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId"
146                " AND Media.VolumeName='" + m_mediaName + "'";
147    }
148    int clientIndex = clientsComboBox->currentIndex();
149    if (clientIndex != -1)
150       m_clientName = clientsComboBox->itemText(clientIndex);
151    if (m_clientName != "Any") {
152       query += " AND Client.Name='" + m_clientName + "'";
153    }
154    int jobIndex = jobComboBox->currentIndex();
155    if ((jobIndex != -1) && (jobComboBox->itemText(jobIndex) != "Any")) {
156       query += " AND Job.Name='" + jobComboBox->itemText(jobIndex) + "'";
157    }
158    int levelIndex = levelComboBox->currentIndex();
159    if ((levelIndex != -1) && (levelComboBox->itemText(levelIndex) != "Any")) {
160       query += " AND Job.Level='" + levelComboBox->itemText(levelIndex) + "'";
161    }
162    int statusIndex = statusComboBox->currentIndex();
163    if ((statusIndex != -1) && (statusComboBox->itemText(statusIndex) != "Any")) {
164       query += " AND Status.JobStatusLong='" + statusComboBox->itemText(statusIndex) + "'";
165    }
166    int purgedIndex = purgedComboBox->currentIndex();
167    if ((purgedIndex != -1) && (purgedComboBox->itemText(purgedIndex) != "Any")) {
168       query += " AND Job.PurgedFiles='" + purgedComboBox->itemText(purgedIndex) + "'";
169    }
170    /* If Limit check box For limit by days is checked  */
171    if (daysCheckBox->checkState() == Qt::Checked) {
172       QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
173       QString since = stamp.toString(Qt::ISODate);
174       query += " AND Job.Starttime>'" + since + "'";
175    }
176    /* Descending */
177    query += " ORDER BY Job.Starttime DESC, Job.JobId DESC";
178    /* If Limit check box for limit records returned is checked  */
179    if (limitCheckBox->checkState() == Qt::Checked) {
180       QString limit;
181       limit.setNum(limitSpinBox->value());
182       query += " LIMIT " + limit;
183    }
184
185    /* Set up the Header for the table */
186    QStringList headerlist = (QStringList()
187       << "Job Id" << "Job Name" << "Client" << "Job Starttime" << "Job Type" 
188       << "Job Level" << "Job Files" << "Job Bytes" << "Job Status"  << "Purged" );
189    m_purgedIndex = headerlist.indexOf("Purged");
190    statusIndex = headerlist.indexOf("Job Status");
191
192    /* Initialize the QTableWidget */
193    m_checkCurrentWidget = false;
194    mp_tableWidget->clear();
195    m_checkCurrentWidget = true;
196    mp_tableWidget->setColumnCount(headerlist.size());
197    mp_tableWidget->setHorizontalHeaderLabels(headerlist);
198
199    /*  This could be a user preference debug message?? */
200    //printf("Query cmd : %s\n",query.toUtf8().data());
201    if (m_console->sql_cmd(query, results)) {
202       m_resultCount = results.count();
203
204       QTableWidgetItem* p_tableitem;
205       QString field;
206       QStringList fieldlist;
207       mp_tableWidget->setRowCount(results.size());
208
209       int row = 0;
210       /* Iterate through the record returned from the query */
211       foreach (resultline, results) {
212          fieldlist = resultline.split("\t");
213          int column = 0;
214          bool statusIndexDone = false;
215          QString statusCode("");
216          /* Iterate through fields in the record */
217          foreach (field, fieldlist) {
218             field = field.trimmed();  /* strip leading & trailing spaces */
219             if ((column == statusIndex) && (!statusIndexDone)){
220                statusIndexDone = true;
221                statusCode = field;
222             } else {
223                p_tableitem = new QTableWidgetItem(field,1);
224                p_tableitem->setFlags(0);
225                p_tableitem->setForeground(blackBrush);
226                mp_tableWidget->setItem(row, column, p_tableitem);
227                if (column == statusIndex)
228                   setStatusColor(p_tableitem, statusCode);
229                column++;
230             }
231          }
232          row++;
233       }
234    } 
235    /* Resize the columns */
236    mp_tableWidget->resizeColumnsToContents();
237    mp_tableWidget->resizeRowsToContents();
238    mp_tableWidget->verticalHeader()->hide();
239    if ((m_mediaName != "Any") && (m_resultCount == 0)){
240       /* for context sensitive searches, let the user know if there were no
241        * results */
242       QMessageBox::warning(this, tr("Bat"),
243           tr("The Jobs query returned no results.\n"
244          "Press OK to continue?"), QMessageBox::Ok );
245    }
246 }
247
248 void JobList::setStatusColor(QTableWidgetItem *item, QString &field)
249 {
250    QString greenchars("TCR");
251    QString redchars("BEf");
252    QString yellowchars("eDAFSMmsjdctp");
253    if (greenchars.contains(field, Qt::CaseSensitive)) {
254       item->setBackground(Qt::green);
255    } else if (redchars.contains(field, Qt::CaseSensitive)) {
256       item->setBackground(Qt::red);
257    } else if (yellowchars.contains(field, Qt::CaseSensitive)){ 
258       item->setBackground(Qt::yellow);
259    }
260 }
261
262 /*
263  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
264  * The tree has been populated.
265  */
266 void JobList::PgSeltreeWidgetClicked()
267 {
268    populateTable();
269    if (!m_populated) {
270       m_populated=true;
271    }
272 }
273
274 /*
275  *  Virtual function override of pages function which is called when this page
276  *  is visible on the stack
277  */
278 void JobList::currentStackItem()
279 {
280    if (!m_populated) {
281       populateTable();
282       m_contextActions.append(actionRefreshJobList);
283       m_populated=true;
284    }
285 }
286
287 /*
288  * Virtual Function to return the name for the medialist tree widget
289  */
290 void JobList::treeWidgetName(QString &desc)
291 {
292    if ((m_mediaName == "") && (m_clientName == "")) {
293       desc = "Jobs";
294    } else {
295       desc = "Jobs ";
296       if (m_mediaName != "" ) {
297          desc += "on Volume " + m_mediaName;
298       }
299       if (m_clientName != "" ) {
300          desc += "of Client " + m_clientName;
301       }
302    }
303 }
304
305 /*
306  * This functions much line tableItemChanged for trees like the page selector,
307  * but I will do much less here
308  */
309 void JobList::tableItemChanged(QTableWidgetItem *currentItem, QTableWidgetItem * /*previousItem*/)
310 {
311    if (m_checkCurrentWidget) {
312       int row = currentItem->row();
313       QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
314       m_currentJob = jobitem->text();
315       jobitem = mp_tableWidget->item(row, m_purgedIndex);
316       QString purged = jobitem->text();
317       mp_tableWidget->removeAction(actionPurgeFiles);
318       if (purged == "0") {
319          mp_tableWidget->addAction(actionPurgeFiles);
320       }
321    }
322 }
323
324 /*
325  * Function to create connections for context sensitive menu for this and
326  * the page selector
327  */
328 void JobList::createConnections()
329 {
330    /* connect to the action specific to this pages class that shows up in the 
331     * page selector tree */
332    connect(actionRefreshJobList, SIGNAL(triggered()), this,
333                 SLOT(populateTable()));
334    connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
335    /* for the tableItemChanged to maintain m_currentJob */
336    connect(mp_tableWidget, SIGNAL(
337            currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
338            this, SLOT(tableItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
339
340    /* Do what is required for the local context sensitive menu */
341
342
343    /* setContextMenuPolicy is required */
344    mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
345
346    /* Add Actions */
347    mp_tableWidget->addAction(actionRefreshJobList);
348    mp_tableWidget->addAction(actionLongListJob);
349    mp_tableWidget->addAction(actionListJobid);
350    mp_tableWidget->addAction(actionListFilesOnJob);
351    mp_tableWidget->addAction(actionListJobMedia);
352    mp_tableWidget->addAction(actionListVolumes);
353    mp_tableWidget->addAction(actionDeleteJob);
354    mp_tableWidget->addAction(actionPurgeFiles);
355    mp_tableWidget->addAction(actionRestoreFromJob);
356    mp_tableWidget->addAction(actionRestoreFromTime);
357    mp_tableWidget->addAction(actionShowLogForJob);
358
359    /* Make Connections */
360    connect(actionLongListJob, SIGNAL(triggered()), this,
361                 SLOT(consoleLongListJob()));
362    connect(actionListJobid, SIGNAL(triggered()), this,
363                 SLOT(consoleListJobid()));
364    connect(actionListFilesOnJob, SIGNAL(triggered()), this,
365                 SLOT(consoleListFilesOnJob()));
366    connect(actionListJobMedia, SIGNAL(triggered()), this,
367                 SLOT(consoleListJobMedia()));
368    connect(actionListVolumes, SIGNAL(triggered()), this,
369                 SLOT(consoleListVolumes()));
370    connect(actionDeleteJob, SIGNAL(triggered()), this,
371                 SLOT(consoleDeleteJob()));
372    connect(actionPurgeFiles, SIGNAL(triggered()), this,
373                 SLOT(consolePurgeFiles()));
374    connect(actionRestoreFromJob, SIGNAL(triggered()), this,
375                 SLOT(preRestoreFromJob()));
376    connect(actionRestoreFromTime, SIGNAL(triggered()), this,
377                 SLOT(preRestoreFromTime()));
378    connect(actionShowLogForJob, SIGNAL(triggered()), this,
379                 SLOT(showLogForJob()));
380 }
381
382 /*
383  * Functions to respond to local context sensitive menu sending console commands
384  * If I could figure out how to make these one function passing a string, Yaaaaaa
385  */
386 void JobList::consoleLongListJob()
387 {
388    QString cmd("llist jobid=");
389    cmd += m_currentJob;
390    consoleCommand(cmd);
391 }
392 void JobList::consoleListJobid()
393 {
394    QString cmd("list jobid=");
395    cmd += m_currentJob;
396    consoleCommand(cmd);
397 }
398 void JobList::consoleListFilesOnJob()
399 {
400    QString cmd("list files jobid=");
401    cmd += m_currentJob;
402    consoleCommand(cmd);
403 }
404 void JobList::consoleListJobMedia()
405 {
406    QString cmd("list jobmedia jobid=");
407    cmd += m_currentJob;
408    consoleCommand(cmd);
409 }
410 void JobList::consoleListVolumes()
411 {
412    QString cmd("list volumes jobid=");
413    cmd += m_currentJob;
414    consoleCommand(cmd);
415 }
416 void JobList::consoleDeleteJob()
417 {
418    if (QMessageBox::warning(this, tr("Bat"),
419       tr("Are you sure you want to delete??  !!!.\n"
420 "This delete command is used to delete a Job record and all associated catalog"
421 " records that were created. This command operates only on the Catalog"
422 " database and has no effect on the actual data written to a Volume. This"
423 " command can be dangerous and we strongly recommend that you do not use"
424 " it unless you know what you are doing.  The Job and all its associated"
425 " records (File and JobMedia) will be deleted from the catalog."
426       "Press OK to proceed with delete operation.?"),
427       QMessageBox::Ok | QMessageBox::Cancel)
428       == QMessageBox::Cancel) { return; }
429
430    QString cmd("delete job jobid=");
431    cmd += m_currentJob;
432    consoleCommand(cmd);
433 }
434 void JobList::consolePurgeFiles()
435 {
436    if (QMessageBox::warning(this, tr("Bat"),
437       tr("Are you sure you want to purge ??  !!!.\n"
438 "The Purge command will delete associated Catalog database records from Jobs and"
439 " Volumes without considering the retention period. Purge  works only on the"
440 " Catalog database and does not affect data written to Volumes. This command can"
441 " be dangerous because you can delete catalog records associated with current"
442 " backups of files, and we recommend that you do not use it unless you know what"
443 " you are doing.\n"
444       "Press OK to proceed with the purge operation?"),
445       QMessageBox::Ok | QMessageBox::Cancel)
446       == QMessageBox::Cancel) { return; }
447
448    QString cmd("purge files jobid=");
449    cmd += m_currentJob;
450    consoleCommand(cmd);
451 }
452
453 /*
454  * Subroutine to call preRestore to restore from a select job
455  */
456 void JobList::preRestoreFromJob()
457 {
458    new prerestorePage(m_currentJob, R_JOBIDLIST);
459 }
460
461 /*
462  * Subroutine to call preRestore to restore from a select job
463  */
464 void JobList::preRestoreFromTime()
465 {
466    new prerestorePage(m_currentJob, R_JOBDATETIME);
467 }
468
469 /*
470  * Subroutine to call class to show the log in the database from that job
471  */
472 void JobList::showLogForJob()
473 {
474    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
475    new JobLog(m_currentJob, pageSelectorTreeWidgetItem);
476 }