2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
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.
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.
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
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.
29 * Version $Id: joblist.h 4230 2007-02-21 20:07:37Z kerns $
31 * Dirk Bartley, March 2007
34 #include <QAbstractEventDispatcher>
35 #include <QTableWidgetItem>
41 * Constructor for the class
43 JobList::JobList(QString &mediaName, QString &clientname,
44 QTreeWidgetItem *parentTreeWidgetItem)
48 m_mediaName = mediaName;
49 m_clientName = clientname;
50 pgInitialize(parentTreeWidgetItem);
54 if ((m_mediaName != "") || (m_clientName != "")) { m_closeable=true; }
55 m_checkCurrentWidget = true;
58 /* Set Defaults for check and spin for limits */
59 limitCheckBox->setCheckState(Qt::Checked);
60 limitSpinBox->setValue(150);
61 daysCheckBox->setCheckState(Qt::Unchecked);
62 daysSpinBox->setValue(30);
66 * The Meat of the class.
67 * This function will populate the QTableWidget, mp_tablewidget, with
68 * QTableWidgetItems representing the results of a query for what jobs exist on
69 * the media name passed from the constructor stored in m_mediaName.
71 void JobList::populateTable()
75 QBrush blackBrush(Qt::black);
77 /* Can't do this in constructor because not neccesarily conected in constructor */
79 clientsComboBox->addItem("");
80 clientsComboBox->addItems(m_console->client_list);
81 int clientIndex = clientsComboBox->findText(m_clientName, Qt::MatchExactly);
82 if (clientIndex != -1)
83 clientsComboBox->setCurrentIndex(clientIndex);
85 /* Not m_console->volume_list will query database */
86 QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
87 QStringList results, volumeList;
88 if (m_console->sql_cmd(query, results)) {
90 QStringList fieldlist;
91 /* Iterate through the lines of results. */
92 foreach (QString resultline, results) {
93 fieldlist = resultline.split("\t");
94 volumeList.append(fieldlist[0]);
95 } /* foreach resultline */
96 } /* if results from query */
97 volumeComboBox->addItem("");
98 volumeComboBox->addItems(volumeList);
99 int volumeIndex = volumeComboBox->findText(m_mediaName, Qt::MatchExactly);
100 if (volumeIndex != -1) {
101 volumeComboBox->setCurrentIndex(volumeIndex);
103 jobComboBox->addItem("Any");
104 jobComboBox->addItems(m_console->job_list);
105 levelComboBox->addItem("Any");
106 levelComboBox->addItems( QStringList() << "F" << "D" << "I");
107 statusComboBox->addItem("Any");
108 statusComboBox->addItems( QStringList() << "T");
109 purgedComboBox->addItem("Any");
110 purgedComboBox->addItems( QStringList() << "0" << "1");
115 int volumeIndex = volumeComboBox->currentIndex();
116 if (volumeIndex != -1)
117 m_mediaName = volumeComboBox->itemText(volumeIndex);
118 query += "SELECT Job.Jobid AS Id, Job.Name AS JobName, Client.Name AS Client,"
119 " Job.Starttime AS JobStart, Job.Type AS JobType,"
120 " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
121 " Job.JobBytes AS Bytes,"
122 " Job.JobStatus AS Status, Status.JobStatusLong AS Status,"
123 " Job.PurgedFiles AS Purged"
124 " FROM Job,Client,Status";
125 if (m_mediaName != "") {
126 query += ",JobMedia,Media";
128 query += " WHERE Client.ClientId=Job.ClientId AND Job.JobStatus=Status.JobStatus";
129 if (m_mediaName != "") {
130 query += " AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId"
131 " AND Media.VolumeName='" + m_mediaName + "'";
133 int clientIndex = clientsComboBox->currentIndex();
134 if (clientIndex != -1)
135 m_clientName = clientsComboBox->itemText(clientIndex);
136 if (m_clientName != "") {
137 query += " AND Client.Name='" + m_clientName + "'";
139 int jobIndex = jobComboBox->currentIndex();
140 if ((jobIndex != -1) && (jobComboBox->itemText(jobIndex) != "Any")) {
141 query += " AND Job.Name='" + jobComboBox->itemText(jobIndex) + "'";
143 int levelIndex = levelComboBox->currentIndex();
144 if ((levelIndex != -1) && (levelComboBox->itemText(levelIndex) != "Any")) {
145 query += " AND Job.Level='" + levelComboBox->itemText(levelIndex) + "'";
147 int statusIndex = statusComboBox->currentIndex();
148 if ((statusIndex != -1) && (statusComboBox->itemText(statusIndex) != "Any")) {
149 query += " AND Job.JobStatus='" + statusComboBox->itemText(statusIndex) + "'";
151 int purgedIndex = purgedComboBox->currentIndex();
152 if ((purgedIndex != -1) && (purgedComboBox->itemText(purgedIndex) != "Any")) {
153 query += " AND Job.PurgedFiles='" + purgedComboBox->itemText(purgedIndex) + "'";
155 /* If Limit check box For limit by days is checked */
156 if (daysCheckBox->checkState() == Qt::Checked) {
157 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
158 QString since = stamp.toString(Qt::ISODate);
159 query += " AND Job.Starttime>'" + since + "'";
162 query += " ORDER BY Job.Starttime DESC, Job.JobId DESC";
163 /* If Limit check box for limit records returned is checked */
164 if (limitCheckBox->checkState() == Qt::Checked) {
166 limit.setNum(limitSpinBox->value());
167 query += " LIMIT " + limit;
170 /* Set up the Header for the table */
171 QStringList headerlist = (QStringList()
172 << "Job Id" << "Job Name" << "Client" << "Job Starttime" << "Job Type"
173 << "Job Level" << "Job Files" << "Job Bytes" << "Job Status" << "Purged" );
174 m_purgedIndex = headerlist.indexOf("Purged");
175 statusIndex = headerlist.indexOf("Job Status");
177 /* Initialize the QTableWidget */
178 m_checkCurrentWidget = false;
179 mp_tableWidget->clear();
180 m_checkCurrentWidget = true;
181 mp_tableWidget->setColumnCount(headerlist.size());
182 mp_tableWidget->setHorizontalHeaderLabels(headerlist);
184 /* This could be a user preference debug message?? */
185 //printf("Query cmd : %s\n",query.toUtf8().data());
186 if (m_console->sql_cmd(query, results)) {
187 m_resultCount = results.count();
189 QTableWidgetItem* p_tableitem;
191 QStringList fieldlist;
192 mp_tableWidget->setRowCount(results.size());
195 /* Iterate through the record returned from the query */
196 foreach (resultline, results) {
197 fieldlist = resultline.split("\t");
199 bool statusIndexDone = false;
200 QString statusCode("");
201 /* Iterate through fields in the record */
202 foreach (field, fieldlist) {
203 field = field.trimmed(); /* strip leading & trailing spaces */
204 if ((column == statusIndex) && (!statusIndexDone)){
205 statusIndexDone = true;
208 p_tableitem = new QTableWidgetItem(field,1);
209 p_tableitem->setFlags(0);
210 p_tableitem->setForeground(blackBrush);
211 mp_tableWidget->setItem(row, column, p_tableitem);
212 if (column == statusIndex)
213 setStatusColor(p_tableitem, statusCode);
220 /* Resize the columns */
221 mp_tableWidget->resizeColumnsToContents();
222 mp_tableWidget->resizeRowsToContents();
223 mp_tableWidget->verticalHeader()->hide();
224 if ((m_mediaName != "") && (m_resultCount == 0)){
225 /* for context sensitive searches, let the user know if there were no
227 QMessageBox::warning(this, tr("Bat"),
228 tr("The Jobs query returned no results.\n"
229 "Press OK to continue?"), QMessageBox::Ok );
233 void JobList::setStatusColor(QTableWidgetItem *item, QString &field)
235 QString greenchars("TCR");
236 QString redchars("BEf");
237 QString yellowchars("eDAFSMmsjdctp");
238 if (greenchars.contains(field, Qt::CaseSensitive)) {
239 item->setBackground(Qt::green);
240 } else if (redchars.contains(field, Qt::CaseSensitive)) {
241 item->setBackground(Qt::red);
242 } else if (yellowchars.contains(field, Qt::CaseSensitive)){
243 item->setBackground(Qt::yellow);
248 * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
249 * The tree has been populated.
251 void JobList::PgSeltreeWidgetClicked()
260 * Virtual function override of pages function which is called when this page
261 * is visible on the stack
263 void JobList::currentStackItem()
267 m_contextActions.append(actionRefreshJobList);
273 * Virtual Function to return the name for the medialist tree widget
275 void JobList::treeWidgetName(QString &desc)
277 if ((m_mediaName == "") && (m_clientName == "")) {
281 if (m_mediaName != "" ) {
282 desc += "on Volume " + m_mediaName;
284 if (m_clientName != "" ) {
285 desc += "of Client " + m_clientName;
291 * This functions much line tableItemChanged for trees like the page selector,
292 * but I will do much less here
294 void JobList::tableItemChanged(QTableWidgetItem *currentItem, QTableWidgetItem * /*previousItem*/)
296 if (m_checkCurrentWidget) {
297 int row = currentItem->row();
298 QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
299 m_currentJob = jobitem->text();
300 jobitem = mp_tableWidget->item(row, m_purgedIndex);
301 QString purged = jobitem->text();
302 mp_tableWidget->removeAction(actionPurgeFiles);
304 mp_tableWidget->addAction(actionPurgeFiles);
310 * Function to create connections for context sensitive menu for this and
313 void JobList::createConnections()
315 /* connect to the action specific to this pages class that shows up in the
316 * page selector tree */
317 connect(actionRefreshJobList, SIGNAL(triggered()), this,
318 SLOT(populateTable()));
319 connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
320 /* for the tableItemChanged to maintain m_currentJob */
321 connect(mp_tableWidget, SIGNAL(
322 currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
323 this, SLOT(tableItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
325 /* Do what is required for the local context sensitive menu */
328 /* setContextMenuPolicy is required */
329 mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
332 mp_tableWidget->addAction(actionRefreshJobList);
333 mp_tableWidget->addAction(actionLongListJob);
334 mp_tableWidget->addAction(actionListJobid);
335 mp_tableWidget->addAction(actionListFilesOnJob);
336 mp_tableWidget->addAction(actionListJobMedia);
337 mp_tableWidget->addAction(actionListVolumes);
338 mp_tableWidget->addAction(actionDeleteJob);
339 mp_tableWidget->addAction(actionPurgeFiles);
340 mp_tableWidget->addAction(actionRestoreFromJob);
341 mp_tableWidget->addAction(actionRestoreFromTime);
343 /* Make Connections */
344 connect(actionLongListJob, SIGNAL(triggered()), this,
345 SLOT(consoleLongListJob()));
346 connect(actionListJobid, SIGNAL(triggered()), this,
347 SLOT(consoleListJobid()));
348 connect(actionListFilesOnJob, SIGNAL(triggered()), this,
349 SLOT(consoleListFilesOnJob()));
350 connect(actionListJobMedia, SIGNAL(triggered()), this,
351 SLOT(consoleListJobMedia()));
352 connect(actionListVolumes, SIGNAL(triggered()), this,
353 SLOT(consoleListVolumes()));
354 connect(actionDeleteJob, SIGNAL(triggered()), this,
355 SLOT(consoleDeleteJob()));
356 connect(actionPurgeFiles, SIGNAL(triggered()), this,
357 SLOT(consolePurgeFiles()));
358 connect(actionRestoreFromJob, SIGNAL(triggered()), this,
359 SLOT(preRestoreFromJob()));
360 connect(actionRestoreFromTime, SIGNAL(triggered()), this,
361 SLOT(preRestoreFromTime()));
365 * Functions to respond to local context sensitive menu sending console commands
366 * If I could figure out how to make these one function passing a string, Yaaaaaa
368 void JobList::consoleLongListJob()
370 QString cmd("llist jobid=");
374 void JobList::consoleListJobid()
376 QString cmd("list jobid=");
380 void JobList::consoleListFilesOnJob()
382 QString cmd("list files jobid=");
386 void JobList::consoleListJobMedia()
388 QString cmd("list jobmedia jobid=");
392 void JobList::consoleListVolumes()
394 QString cmd("list volumes jobid=");
398 void JobList::consoleDeleteJob()
400 if (QMessageBox::warning(this, tr("Bat"),
401 tr("Are you sure you want to delete?? !!!.\n"
402 "This delete command is used to delete a Job record and all associated catalog"
403 " records that were created. This command operates only on the Catalog"
404 " database and has no effect on the actual data written to a Volume. This"
405 " command can be dangerous and we strongly recommend that you do not use"
406 " it unless you know what you are doing. The Job and all its associated"
407 " records (File and JobMedia) will be deleted from the catalog."
408 "Press OK to proceed with delete operation.?"),
409 QMessageBox::Ok | QMessageBox::Cancel)
410 == QMessageBox::Cancel) { return; }
412 QString cmd("delete job jobid=");
416 void JobList::consolePurgeFiles()
418 if (QMessageBox::warning(this, tr("Bat"),
419 tr("Are you sure you want to purge ?? !!!.\n"
420 "The Purge command will delete associated Catalog database records from Jobs and"
421 " Volumes without considering the retention period. Purge works only on the"
422 " Catalog database and does not affect data written to Volumes. This command can"
423 " be dangerous because you can delete catalog records associated with current"
424 " backups of files, and we recommend that you do not use it unless you know what"
426 "Press OK to proceed with the purge operation?"),
427 QMessageBox::Ok | QMessageBox::Cancel)
428 == QMessageBox::Cancel) { return; }
430 QString cmd("purge files jobid=");
436 * Subroutine to call preRestore to restore from a select job
438 void JobList::preRestoreFromJob()
440 new prerestorePage(m_currentJob, R_JOBIDLIST);
444 * Subroutine to call preRestore to restore from a select job
446 void JobList::preRestoreFromTime()
448 new prerestorePage(m_currentJob, R_JOBDATETIME);