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 m_checkCurrentWidget = true;
57 /* Set Defaults for check and spin for limits */
58 limitCheckBox->setCheckState(Qt::Checked);
59 limitSpinBox->setValue(150);
60 daysCheckBox->setCheckState(Qt::Unchecked);
61 daysSpinBox->setValue(30);
65 * The Meat of the class.
66 * This function will populate the QTableWidget, mp_tablewidget, with
67 * QTableWidgetItems representing the results of a query for what jobs exist on
68 * the media name passed from the constructor stored in m_mediaName.
70 void JobList::populateTable()
74 QBrush blackBrush(Qt::black);
76 /* Can't do this in constructor because not neccesarily conected in constructor */
78 clientsComboBox->addItem("");
79 clientsComboBox->addItems(m_console->client_list);
80 int clientIndex = clientsComboBox->findText(m_clientName, Qt::MatchExactly);
81 if (clientIndex != -1)
82 clientsComboBox->setCurrentIndex(clientIndex);
84 /* Not m_console->volume_list will query database */
85 QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
86 QStringList results, volumeList;
87 if (m_console->sql_cmd(query, results)) {
89 QStringList fieldlist;
90 /* Iterate through the lines of results. */
91 foreach (QString resultline, results) {
92 fieldlist = resultline.split("\t");
93 volumeList.append(fieldlist[0]);
94 } /* foreach resultline */
95 } /* if results from query */
96 volumeComboBox->addItem("");
97 volumeComboBox->addItems(volumeList);
98 int volumeIndex = volumeComboBox->findText(m_mediaName, Qt::MatchExactly);
99 if (volumeIndex != -1) {
100 volumeComboBox->setCurrentIndex(volumeIndex);
102 jobComboBox->addItem("Any");
103 jobComboBox->addItems(m_console->job_list);
104 levelComboBox->addItem("Any");
105 levelComboBox->addItems( QStringList() << "F" << "D" << "I");
106 statusComboBox->addItem("Any");
107 statusComboBox->addItems( QStringList() << "T");
108 purgedComboBox->addItem("Any");
109 purgedComboBox->addItems( QStringList() << "0" << "1");
112 /* Set up query QString and header QStringList */
116 * NB temporarily remove Media and JobMedia, because one cannot include
117 * those items if one wants to list all jobs. Some jobs never write
118 * to Volumes. To correct this one needs two different SELECT statements
119 * depending on the filter.
120 * Also, note that DISTINCT doesn't work as one intuitively think it
121 * will on PostgreSQL. I believe the use here was incorrect so I
122 * removed it -- at least temporarily.
123 * This comment should be removed when fixed.
125 query += "SELECT Job.Jobid AS Id, Job.Name AS JobName, Client.Name AS Client,"
126 " Job.Starttime AS JobStart, Job.Type AS JobType,"
127 " Job.Level AS BackupLevel, Job.Jobfiles AS FileCount,"
128 " Job.JobBytes AS Bytes,"
129 " Job.JobStatus AS Status, Status.JobStatusLong AS Status,"
130 " Job.PurgedFiles AS Purged"
131 " FROM Job,Client,Status"
132 " WHERE Client.ClientId=Job.ClientId AND Job.JobStatus=Status.JobStatus";
134 int volumeIndex = volumeComboBox->currentIndex();
135 if (volumeIndex != -1)
136 m_mediaName = volumeComboBox->itemText(volumeIndex);
137 if (m_mediaName != "") {
138 query += " AND Media.VolumeName='" + m_mediaName + "'";
142 int clientIndex = clientsComboBox->currentIndex();
143 if (clientIndex != -1)
144 m_clientName = clientsComboBox->itemText(clientIndex);
145 if (m_clientName != "") {
146 query += " AND Client.Name='" + m_clientName + "'";
149 int jobIndex = jobComboBox->currentIndex();
150 if ((jobIndex != -1) && (jobComboBox->itemText(jobIndex) != "Any")) {
151 query += " AND Job.Name='" + jobComboBox->itemText(jobIndex) + "'";
153 int levelIndex = levelComboBox->currentIndex();
154 if ((levelIndex != -1) && (levelComboBox->itemText(levelIndex) != "Any")) {
155 query += " AND Job.Level='" + levelComboBox->itemText(levelIndex) + "'";
157 int statusIndex = statusComboBox->currentIndex();
158 if ((statusIndex != -1) && (statusComboBox->itemText(statusIndex) != "Any")) {
159 query += " AND Job.JobStatus='" + statusComboBox->itemText(statusIndex) + "'";
161 int purgedIndex = purgedComboBox->currentIndex();
162 if ((purgedIndex != -1) && (purgedComboBox->itemText(purgedIndex) != "Any")) {
163 query += " AND Job.PurgedFiles='" + purgedComboBox->itemText(purgedIndex) + "'";
165 /* If Limit check box For limit by days is checked */
166 if (daysCheckBox->checkState() == Qt::Checked) {
167 QDateTime stamp = QDateTime::currentDateTime().addDays(-daysSpinBox->value());
168 QString since = stamp.toString(Qt::ISODate);
169 query += " AND Job.Starttime>'" + since + "'";
172 query += " ORDER BY Job.Starttime DESC";
173 /* If Limit check box for limit records returned is checked */
174 if (limitCheckBox->checkState() == Qt::Checked) {
176 limit.setNum(limitSpinBox->value());
177 query += " LIMIT " + limit;
179 QStringList headerlist = (QStringList()
180 << "Job Id" << "Job Name" << "Client" << "Job Starttime" << "Job Type"
181 << "Job Level" << "Job Files" << "Job Bytes" << "Job Status" << "Purged" );
182 m_purgedIndex = headerlist.indexOf("Purged");
183 statusIndex = headerlist.indexOf("Job Status");
185 /* Initialize the QTableWidget */
186 m_checkCurrentWidget = false;
187 mp_tableWidget->clear();
188 m_checkCurrentWidget = true;
189 mp_tableWidget->setColumnCount(headerlist.size());
190 mp_tableWidget->setHorizontalHeaderLabels(headerlist);
192 /* This could be a user preference debug message?? */
193 //printf("Query cmd : %s\n",query.toUtf8().data());
194 if (m_console->sql_cmd(query, results)) {
195 m_resultCount = results.count();
197 QTableWidgetItem* p_tableitem;
199 QStringList fieldlist;
200 mp_tableWidget->setRowCount(results.size());
203 /* Iterate through the record returned from the query */
204 foreach (resultline, results) {
205 fieldlist = resultline.split("\t");
207 bool statusIndexDone = false;
208 QString statusCode("");
209 /* Iterate through fields in the record */
210 foreach (field, fieldlist) {
211 field = field.trimmed(); /* strip leading & trailing spaces */
212 if ((column == statusIndex) && (!statusIndexDone)){
213 statusIndexDone = true;
216 p_tableitem = new QTableWidgetItem(field,1);
217 p_tableitem->setFlags(0);
218 p_tableitem->setForeground(blackBrush);
219 mp_tableWidget->setItem(row, column, p_tableitem);
220 if (column == statusIndex)
221 setStatusColor(p_tableitem, statusCode);
228 /* Resize the columns */
229 mp_tableWidget->resizeColumnsToContents();
230 mp_tableWidget->resizeRowsToContents();
231 mp_tableWidget->verticalHeader()->hide();
232 if ((m_mediaName != "") && (m_resultCount == 0)){
233 /* for context sensitive searches, let the user know if there were no
235 QMessageBox::warning(this, tr("Bat"),
236 tr("The Jobs query returned no results.\n"
237 "Press OK to continue?"), QMessageBox::Ok );
241 void JobList::setStatusColor(QTableWidgetItem *item, QString &field)
243 QString greenchars("TCR");
244 QString redchars("BEf");
245 QString yellowchars("eDAFSMmsjdctp");
246 if (greenchars.contains(field, Qt::CaseSensitive)) {
247 item->setBackground(Qt::green);
248 } else if (redchars.contains(field, Qt::CaseSensitive)) {
249 item->setBackground(Qt::red);
250 } else if (yellowchars.contains(field, Qt::CaseSensitive)){
251 item->setBackground(Qt::yellow);
256 * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
257 * The tree has been populated.
259 void JobList::PgSeltreeWidgetClicked()
268 * Virtual function override of pages function which is called when this page
269 * is visible on the stack
271 void JobList::currentStackItem()
275 m_contextActions.append(actionRefreshJobList);
281 * Virtual Function to return the name for the medialist tree widget
283 void JobList::treeWidgetName(QString &desc)
285 if ((m_mediaName == "") && (m_clientName == "")) {
289 if (m_mediaName != "" ) {
290 desc += "on Volume " + m_mediaName;
292 if (m_clientName != "" ) {
293 desc += "of Client " + m_clientName;
299 * This functions much line tableItemChanged for trees like the page selector,
300 * but I will do much less here
302 void JobList::tableItemChanged(QTableWidgetItem *currentItem, QTableWidgetItem * /*previousItem*/)
304 if (m_checkCurrentWidget) {
305 int row = currentItem->row();
306 QTableWidgetItem* jobitem = mp_tableWidget->item(row, 0);
307 m_currentJob = jobitem->text();
308 jobitem = mp_tableWidget->item(row, m_purgedIndex);
309 QString purged = jobitem->text();
310 mp_tableWidget->removeAction(actionPurgeFiles);
312 mp_tableWidget->addAction(actionPurgeFiles);
318 * Function to create connections for context sensitive menu for this and
321 void JobList::createConnections()
323 /* connect to the action specific to this pages class that shows up in the
324 * page selector tree */
325 connect(actionRefreshJobList, SIGNAL(triggered()), this,
326 SLOT(populateTable()));
327 connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
328 /* for the tableItemChanged to maintain m_currentJob */
329 connect(mp_tableWidget, SIGNAL(
330 currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
331 this, SLOT(tableItemChanged(QTableWidgetItem *, QTableWidgetItem *)));
333 /* Do what is required for the local context sensitive menu */
336 /* setContextMenuPolicy is required */
337 mp_tableWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
340 mp_tableWidget->addAction(actionRefreshJobList);
341 mp_tableWidget->addAction(actionLongListJob);
342 mp_tableWidget->addAction(actionListJobid);
343 mp_tableWidget->addAction(actionListFilesOnJob);
344 mp_tableWidget->addAction(actionListJobMedia);
345 mp_tableWidget->addAction(actionListVolumes);
346 mp_tableWidget->addAction(actionDeleteJob);
347 mp_tableWidget->addAction(actionPurgeFiles);
348 mp_tableWidget->addAction(actionRestoreFromJob);
349 mp_tableWidget->addAction(actionRestoreFromTime);
351 /* Make Connections */
352 connect(actionLongListJob, SIGNAL(triggered()), this,
353 SLOT(consoleLongListJob()));
354 connect(actionListJobid, SIGNAL(triggered()), this,
355 SLOT(consoleListJobid()));
356 connect(actionListFilesOnJob, SIGNAL(triggered()), this,
357 SLOT(consoleListFilesOnJob()));
358 connect(actionListJobMedia, SIGNAL(triggered()), this,
359 SLOT(consoleListJobMedia()));
360 connect(actionListVolumes, SIGNAL(triggered()), this,
361 SLOT(consoleListVolumes()));
362 connect(actionDeleteJob, SIGNAL(triggered()), this,
363 SLOT(consoleDeleteJob()));
364 connect(actionPurgeFiles, SIGNAL(triggered()), this,
365 SLOT(consolePurgeFiles()));
366 connect(actionRestoreFromJob, SIGNAL(triggered()), this,
367 SLOT(preRestoreFromJob()));
368 connect(actionRestoreFromTime, SIGNAL(triggered()), this,
369 SLOT(preRestoreFromTime()));
373 * Functions to respond to local context sensitive menu sending console commands
374 * If I could figure out how to make these one function passing a string, Yaaaaaa
376 void JobList::consoleLongListJob()
378 QString cmd("llist jobid=");
382 void JobList::consoleListJobid()
384 QString cmd("list jobid=");
388 void JobList::consoleListFilesOnJob()
390 QString cmd("list files jobid=");
394 void JobList::consoleListJobMedia()
396 QString cmd("list jobmedia jobid=");
400 void JobList::consoleListVolumes()
402 QString cmd("list volumes jobid=");
406 void JobList::consoleDeleteJob()
408 if (QMessageBox::warning(this, tr("Bat"),
409 tr("Are you sure you want to delete?? !!!.\n"
410 "This delete command is used to delete a Job record and all associated catalog"
411 " records that were created. This command operates only on the Catalog"
412 " database and has no effect on the actual data written to a Volume. This"
413 " command can be dangerous and we strongly recommend that you do not use"
414 " it unless you know what you are doing. The Job and all its associated"
415 " records (File and JobMedia) will be deleted from the catalog."
416 "Press OK to proceed with delete operation.?"),
417 QMessageBox::Ok | QMessageBox::Cancel)
418 == QMessageBox::Cancel) { return; }
420 QString cmd("delete job jobid=");
424 void JobList::consolePurgeFiles()
426 if (QMessageBox::warning(this, tr("Bat"),
427 tr("Are you sure you want to purge ?? !!!.\n"
428 "The Purge command will delete associated Catalog database records from Jobs and"
429 " Volumes without considering the retention period. Purge works only on the"
430 " Catalog database and does not affect data written to Volumes. This command can"
431 " be dangerous because you can delete catalog records associated with current"
432 " backups of files, and we recommend that you do not use it unless you know what"
434 "Press OK to proceed with the purge operation?"),
435 QMessageBox::Ok | QMessageBox::Cancel)
436 == QMessageBox::Cancel) { return; }
438 QString cmd("purge files jobid=");
444 * Subroutine to call preRestore to restore from a select job
446 void JobList::preRestoreFromJob()
448 new prerestorePage(m_currentJob, R_JOBIDLIST);
452 * Subroutine to call preRestore to restore from a select job
454 void JobList::preRestoreFromTime()
456 new prerestorePage(m_currentJob, R_JOBDATETIME);