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