]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/medialist/medialist.cpp
Check for job_canceled() in fd_plugin code
[bacula/bacula] / bacula / src / qt-console / medialist / medialist.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
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 and included
11    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 Kern Sibbald.
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 /*
30  *   Version $Id$
31  *
32  *  MediaList Class
33  *
34  *   Dirk Bartley, March 2007
35  *
36  */ 
37
38 #include "bat.h"
39 #include <QAbstractEventDispatcher>
40 #include <QMenu>
41 #include <math.h>
42 #include "medialist.h"
43 #include "mediaedit/mediaedit.h"
44 #include "joblist/joblist.h"
45 #include "relabel/relabel.h"
46 #include "run/run.h"
47 #include "util/fmtwidgetitem.h"
48
49 MediaList::MediaList()
50 {
51    setupUi(this);
52    m_name = tr("Media");
53    pgInitialize();
54    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
55    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/cartridge.png")));
56
57    /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_medialist.h */
58    m_populated = false;
59    m_checkcurwidget = true;
60    m_closeable = false;
61    /* add context sensitive menu items specific to this classto the page
62     * selector tree. m_contextActions is QList of QActions */
63    m_contextActions.append(actionRefreshMediaList);
64    dockPage();
65 }
66
67 MediaList::~MediaList()
68 {
69    if (m_populated)
70       writeExpandedSettings();
71 }
72
73 /*
74  * The main meat of the class!!  The function that querries the director and 
75  * creates the widgets with appropriate values.
76  */
77 void MediaList::populateTree()
78 {
79    if (m_populated)
80       writeExpandedSettings();
81    m_populated = true;
82
83    Freeze frz(*mp_treeWidget); /* disable updating*/
84
85    QStringList headerlist = (QStringList()
86       << tr("Volume Name") << tr("Id") << tr("Status") << tr("Enabled") << tr("Bytes") << tr("Files")
87       << tr("Jobs") << tr("Retention") << tr("Media Type") << tr("Slot") << tr("Use Duration")
88       << tr("Max Jobs") << tr("Max Files") << tr("Max Bytes") << tr("Recycle")
89       << tr("RecyclePool") << tr("Last Written"));
90
91    m_checkcurwidget = false;
92    mp_treeWidget->clear();
93    m_checkcurwidget = true;
94    mp_treeWidget->setColumnCount(headerlist.count());
95    m_topItem = new QTreeWidgetItem(mp_treeWidget);
96    m_topItem->setText(0, tr("Pools"));
97    m_topItem->setData(0, Qt::UserRole, 0);
98    m_topItem->setExpanded(true);
99    
100    mp_treeWidget->setHeaderLabels(headerlist);
101
102    QSettings settings(m_console->m_dir->name(), "bat");
103    settings.beginGroup("MediaListTreeExpanded");
104    QString query;
105
106    QTreeWidgetItem *pooltreeitem;
107
108    /* Comma separated list of pools first */
109    bool first = true;
110    QString pool_comsep("");
111    foreach (QString pool_listItem, m_console->pool_list) {
112       if (first) {
113          pool_comsep += "'" + pool_listItem + "'";
114          first = false;
115       }
116       else
117          pool_comsep += ",'" + pool_listItem + "'";
118    }
119    /* Now use pool_comsep list to perform just one query */
120    if (pool_comsep != "") {
121       query =  "SELECT Pool.Name AS pul,"
122          " Media.VolumeName AS Media, "
123          " Media.MediaId AS Id, Media.VolStatus AS VolStatus,"
124          " Media.Enabled AS Enabled, Media.VolBytes AS Bytes,"
125          " Media.VolFiles AS FileCount, Media.VolJobs AS JobCount,"
126          " Media.VolRetention AS VolumeRetention, Media.MediaType AS MediaType,"
127          " Media.InChanger AS InChanger, Media.Slot AS Slot, "
128          " Media.VolUseDuration AS UseDuration,"
129          " Media.MaxVolJobs AS MaxJobs, Media.MaxVolFiles AS MaxFiles,"
130          " Media.MaxVolBytes AS MaxBytes, Media.Recycle AS Recycle,"
131          " Pol.Name AS RecyclePool, Media.LastWritten AS LastWritten"
132          " FROM Media"
133          " JOIN Pool ON (Media.PoolId=Pool.PoolId)"
134          " LEFT OUTER JOIN Pool AS Pol ON (Media.RecyclePoolId=Pol.PoolId)"
135          " WHERE ";
136       query += " Pool.Name IN (" + pool_comsep + ")";
137       query += " ORDER BY Pool.Name, Media";
138
139       if (mainWin->m_sqlDebug) {
140          Pmsg1(000, "MediaList query cmd : %s\n",query.toUtf8().data());
141       }
142       QStringList results;
143       int counter = 0;
144       if (m_console->sql_cmd(query, results)) {
145          QStringList fieldlist;
146          QString prev_pool("");
147          QString this_pool("");
148
149          /* Iterate through the lines of results. */
150          foreach (QString resultline, results) {
151             fieldlist = resultline.split("\t");
152             this_pool = fieldlist.takeFirst();
153             if (prev_pool != this_pool) {
154                prev_pool = this_pool;
155                pooltreeitem = new QTreeWidgetItem(m_topItem);
156                pooltreeitem->setText(0, this_pool);
157                pooltreeitem->setData(0, Qt::UserRole, 1);
158             }
159             if(settings.contains(this_pool)) {
160                pooltreeitem->setExpanded(settings.value(this_pool).toBool());
161             } else {
162                pooltreeitem->setExpanded(true);
163             }
164
165             if (fieldlist.size() < 18)
166                continue; // some fields missing, ignore row
167
168             int index = 0;
169             TreeItemFormatter mediaitem(*pooltreeitem, 2);
170   
171             /* Iterate through fields in the record */
172             QStringListIterator fld(fieldlist);
173
174             /* volname */
175             mediaitem.setTextFld(index++, fld.next()); 
176
177             /* id */
178             mediaitem.setNumericFld(index++, fld.next()); 
179
180             /* status */
181             mediaitem.setVolStatusFld(index++, fld.next());
182
183             /* enabled */
184             mediaitem.setBoolFld(index++, fld.next());
185
186             /* bytes */
187             mediaitem.setBytesFld(index++, fld.next());
188
189             /* files */
190             mediaitem.setNumericFld(index++, fld.next()); 
191
192             /* jobs */
193             mediaitem.setNumericFld(index++, fld.next()); 
194
195             /* retention */
196             mediaitem.setDurationFld(index++, fld.next());
197
198             /* media type */
199             mediaitem.setTextFld(index++, fld.next()); 
200
201             /* inchanger + slot */
202             int inchanger = fld.next().toInt();
203             if (inchanger) {
204                mediaitem.setNumericFld(index++, fld.next()); 
205             }
206             else {
207                /* volume not in changer, show blank slot */
208                mediaitem.setNumericFld(index++, ""); 
209                fld.next();
210             }
211
212             /* use duration */
213             mediaitem.setDurationFld(index++, fld.next());
214
215             /* max jobs */
216             mediaitem.setNumericFld(index++, fld.next()); 
217
218             /* max files */
219             mediaitem.setNumericFld(index++, fld.next()); 
220
221             /* max bytes */
222             mediaitem.setBytesFld(index++, fld.next());
223
224             /* recycle */
225             mediaitem.setBoolFld(index++, fld.next());
226
227             /* recycle pool */
228             mediaitem.setTextFld(index++, fld.next()); 
229
230             /* last written */
231             mediaitem.setTextFld(index++, fld.next()); 
232
233          } /* foreach resultline */
234          counter += 1;
235       } /* if results from query */
236    } /* foreach pool_listItem */
237    settings.endGroup();
238    /* Resize the columns */
239    for(int cnter=0; cnter<headerlist.count(); cnter++) {
240       mp_treeWidget->resizeColumnToContents(cnter);
241    }
242 }
243
244 /*
245  * Called from the signal of the context sensitive menu!
246  */
247 void MediaList::editVolume()
248 {
249    MediaEdit* edit = new MediaEdit(mainWin->getFromHash(this), m_currentVolumeId);
250    connect(edit, SIGNAL(destroyed()), this, SLOT(populateTree()));
251 }
252
253 /*
254  * Called from the signal of the context sensitive menu!
255  */
256 void MediaList::showJobs()
257 {
258    QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
259    mainWin->createPageJobList(m_currentVolumeName, "", "", "", parentItem);
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 MediaList::PgSeltreeWidgetClicked()
267 {
268    if (!m_populated) {
269       populateTree();
270       createContextMenu();
271    }
272 }
273
274 /*
275  * Added to set the context menu policy based on currently active treeWidgetItem
276  * signaled by currentItemChanged
277  */
278 void MediaList::treeItemChanged(QTreeWidgetItem *currentwidgetitem, QTreeWidgetItem *previouswidgetitem )
279 {
280    /* m_checkcurwidget checks to see if this is during a refresh, which will segfault */
281    if (m_checkcurwidget) {
282       /* The Previous item */
283       if (previouswidgetitem) { /* avoid a segfault if first time */
284          foreach(QAction* mediaAction, mp_treeWidget->actions()) {
285             mp_treeWidget->removeAction(mediaAction);
286          }
287       }
288
289       int treedepth = currentwidgetitem->data(0, Qt::UserRole).toInt();
290       m_currentVolumeName=currentwidgetitem->text(0);
291       mp_treeWidget->addAction(actionRefreshMediaList);
292       if (treedepth == 2){
293          m_currentVolumeId=currentwidgetitem->text(1);
294          mp_treeWidget->addAction(actionEditVolume);
295          mp_treeWidget->addAction(actionListJobsOnVolume);
296          mp_treeWidget->addAction(actionDeleteVolume);
297          mp_treeWidget->addAction(actionPruneVolume);
298          mp_treeWidget->addAction(actionPurgeVolume);
299          mp_treeWidget->addAction(actionRelabelVolume);
300          mp_treeWidget->addAction(actionVolumeFromPool);
301       } else if (treedepth == 1) {
302          mp_treeWidget->addAction(actionAllVolumesFromPool);
303       }
304    }
305 }
306
307 /* 
308  * Setup a context menu 
309  * Made separate from populate so that it would not create context menu over and
310  * over as the tree is repopulated.
311  */
312 void MediaList::createContextMenu()
313 {
314    mp_treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
315    connect(actionEditVolume, SIGNAL(triggered()), this, SLOT(editVolume()));
316    connect(actionListJobsOnVolume, SIGNAL(triggered()), this, SLOT(showJobs()));
317    connect(actionDeleteVolume, SIGNAL(triggered()), this, SLOT(deleteVolume()));
318    connect(actionPurgeVolume, SIGNAL(triggered()), this, SLOT(purgeVolume()));
319    connect(actionPruneVolume, SIGNAL(triggered()), this, SLOT(pruneVolume()));
320    connect(actionRelabelVolume, SIGNAL(triggered()), this, SLOT(relabelVolume()));
321    connect(mp_treeWidget, SIGNAL(
322            currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
323            this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
324    /* connect to the action specific to this pages class */
325    connect(actionRefreshMediaList, SIGNAL(triggered()), this,
326                 SLOT(populateTree()));
327    connect(actionAllVolumes, SIGNAL(triggered()), this, SLOT(allVolumes()));
328    connect(actionAllVolumesFromPool, SIGNAL(triggered()), this, SLOT(allVolumesFromPool()));
329    connect(actionVolumeFromPool, SIGNAL(triggered()), this, SLOT(volumeFromPool()));
330 }
331
332 /*
333  * Virtual function which is called when this page is visible on the stack
334  */
335 void MediaList::currentStackItem()
336 {
337    if(!m_populated) {
338       populateTree();
339       /* Create the context menu for the medialist tree */
340       createContextMenu();
341    }
342 }
343
344 /*
345  * Called from the signal of the context sensitive menu to delete a volume!
346  */
347 void MediaList::deleteVolume()
348 {
349    if (QMessageBox::warning(this, "Bat",
350       tr("Are you sure you want to delete??  !!!.\n"
351 "This delete command is used to delete a Volume record and all associated catalog"
352 " records that were created. This command operates only on the Catalog"
353 " database and has no effect on the actual data written to a Volume. This"
354 " command can be dangerous and we strongly recommend that you do not use"
355 " it unless you know what you are doing.  All Jobs and all associated"
356 " records (File and JobMedia) will be deleted from the catalog."
357       "Press OK to proceed with delete operation.?"),
358       QMessageBox::Ok | QMessageBox::Cancel)
359       == QMessageBox::Cancel) { return; }
360
361    QString cmd("delete volume=");
362    cmd += m_currentVolumeName;
363    consoleCommand(cmd);
364 }
365
366 /*
367  * Called from the signal of the context sensitive menu to purge!
368  */
369 void MediaList::purgeVolume()
370 {
371    if (QMessageBox::warning(this, "Bat",
372       tr("Are you sure you want to purge ??  !!!.\n"
373 "The Purge command will delete associated Catalog database records from Jobs and"
374 " Volumes without considering the retention period. Purge  works only on the"
375 " Catalog database and does not affect data written to Volumes. This command can"
376 " be dangerous because you can delete catalog records associated with current"
377 " backups of files, and we recommend that you do not use it unless you know what"
378 " you are doing.\n"
379       "Press OK to proceed with the purge operation?"),
380       QMessageBox::Ok | QMessageBox::Cancel)
381       == QMessageBox::Cancel) { return; }
382
383    QString cmd("purge volume=");
384    cmd += m_currentVolumeName;
385    consoleCommand(cmd);
386    populateTree();
387 }
388
389 /*
390  * Called from the signal of the context sensitive menu to prune!
391  */
392 void MediaList::pruneVolume()
393 {
394    new prunePage(m_currentVolumeName, "");
395 }
396
397 /*
398  * Called from the signal of the context sensitive menu to relabel!
399  */
400 void MediaList::relabelVolume()
401 {
402    setConsoleCurrent();
403    new relabelDialog(m_console, m_currentVolumeName);
404 }
405
406 /*
407  * Called from the signal of the context sensitive menu to purge!
408  */
409 void MediaList::allVolumesFromPool()
410 {
411    QString cmd = "update volume AllFromPool=" + m_currentVolumeName;
412    consoleCommand(cmd);
413    populateTree();
414 }
415
416 void MediaList::allVolumes()
417 {
418    QString cmd = "update volume allfrompools";
419    consoleCommand(cmd);
420    populateTree();
421 }
422
423 /*
424  * Called from the signal of the context sensitive menu to purge!
425  */
426 void MediaList::volumeFromPool()
427 {
428    QTreeWidgetItem *currentItem = mp_treeWidget->currentItem();
429    QTreeWidgetItem *parent = currentItem->parent();
430    QString pool = parent->text(0);
431    QString cmd;
432    cmd = "update volume=" + m_currentVolumeName + " frompool=" + pool;
433    consoleCommand(cmd);
434    populateTree();
435 }
436
437 /*
438  * Write settings to save expanded states of the pools
439  */
440 void MediaList::writeExpandedSettings()
441 {
442    if (m_topItem) {
443       QSettings settings(m_console->m_dir->name(), "bat");
444       settings.beginGroup("MediaListTreeExpanded");
445       int childcount = m_topItem->childCount();
446       for (int cnt=0; cnt<childcount; cnt++) {
447          QTreeWidgetItem *poolitem = m_topItem->child(cnt);
448          settings.setValue(poolitem->text(0), poolitem->isExpanded());
449       }
450       settings.endGroup();
451    }
452 }