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