]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/storage/storage.cpp
9f5dc226cbca9009c186b9c08913220dde69bfdc
[bacula/bacula] / bacula / src / qt-console / storage / storage.cpp
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
6
7    The original author of Bacula is Kern Sibbald, with contributions
8    from many others, a complete list can be found in the file AUTHORS.
9
10    You may use this file and others of this release according to the
11    license defined in the LICENSE file, which includes the Affero General
12    Public License, v3.0 ("AGPLv3") and some additional permissions and
13    terms pursuant to its AGPLv3 Section 7.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19 */
20  
21 /*
22  *
23  *  Storage Class
24  *
25  *   Dirk Bartley, March 2007
26  *
27  */ 
28
29 #include "bat.h"
30 #include <QAbstractEventDispatcher>
31 #include <QMenu>
32 #include "storage.h"
33 #include "content.h"
34 #include "label/label.h"
35 #include "mount/mount.h"
36 #include "status/storstat.h"
37 #include "util/fmtwidgetitem.h"
38
39 Storage::Storage() : Pages()
40 {
41    setupUi(this);
42    pgInitialize(tr("Storage"));
43    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
44    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/package-x-generic.png")));
45
46    /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_storage.h */
47    m_populated = false;
48    m_firstpopulation = true;
49    m_checkcurwidget = true;
50    m_closeable = false;
51    m_currentStorage = "";
52    /* add context sensitive menu items specific to this classto the page
53     * selector tree. m_contextActions is QList of QActions */
54    m_contextActions.append(actionRefreshStorage);
55 }
56
57 Storage::~Storage()
58 {
59    if (m_populated)
60       writeExpandedSettings();
61 }
62
63 /*
64  * The main meat of the class!!  The function that querries the director and 
65  * creates the widgets with appropriate values.
66  */
67 void Storage::populateTree()
68 {
69    if (m_populated)
70       writeExpandedSettings();
71    m_populated = true;
72
73    Freeze frz(*mp_treeWidget); /* disable updating */
74
75    m_checkcurwidget = false;
76    mp_treeWidget->clear();
77    m_checkcurwidget = true;
78
79    QStringList headerlist = (QStringList() << tr("Name") << tr("Id")
80         << tr("Changer") << tr("Slot") << tr("Status") << tr("Enabled") << tr("Pool") 
81         << tr("Media Type") );
82
83    m_topItem = new QTreeWidgetItem(mp_treeWidget);
84    m_topItem->setText(0, tr("Storage"));
85    m_topItem->setData(0, Qt::UserRole, 0);
86    m_topItem->setExpanded(true);
87
88    mp_treeWidget->setColumnCount(headerlist.count());
89    mp_treeWidget->setHeaderLabels(headerlist);
90
91    QSettings settings(m_console->m_dir->name(), "bat");
92    settings.beginGroup("StorageTreeExpanded");
93
94    bool first = true;
95    QString storage_comsep("");
96    QString storageName;
97    foreach(storageName, m_console->storage_list){
98       if (first) {
99          storage_comsep += "'" + storageName + "'";
100          first = false;
101       }
102       else
103          storage_comsep += ",'" + storageName + "'";
104    }
105    if (storage_comsep != "") {
106
107       /* Set up query QString and header QStringList */
108       QString query("SELECT"
109                " Name AS StorageName,"
110                " StorageId AS ID, AutoChanger AS Changer"
111                " FROM Storage "
112                " WHERE StorageId IN (SELECT MAX(StorageId) FROM Storage WHERE");
113       query += " Name IN (" + storage_comsep + ")";
114       query += " GROUP BY Name) ORDER BY Name";
115
116       QStringList results;
117       /* This could be a log item */
118       if (mainWin->m_sqlDebug) {
119          Pmsg1(000, "Storage query cmd : %s\n",query.toUtf8().data());
120       }
121       if (m_console->sql_cmd(query, results)) {
122
123          QStringList fieldlist;
124          foreach (QString resultline, results) {
125             fieldlist = resultline.split("\t");
126             if (fieldlist.size() != 3) {
127                Pmsg1(000, "Unexpected line %s", resultline.toUtf8().data());
128                continue;
129             }
130             storageName = fieldlist.takeFirst();
131             if (m_firstpopulation) {
132                settingsOpenStatus(storageName);
133             }
134             TreeItemFormatter storageItem(*m_topItem, 1);
135             storageItem.setTextFld(0, storageName);
136             if(settings.contains(storageName))
137                storageItem.widget()->setExpanded(settings.value(storageName).toBool());
138             else
139                storageItem.widget()->setExpanded(true);
140
141             int index = 1;
142             QStringListIterator fld(fieldlist);
143  
144             /* storage id */
145             storageItem.setNumericFld(index++, fld.next() );
146
147             /* changer */
148             QString changer = fld.next();
149             storageItem.setBoolFld(index++, changer);
150
151             if (changer == "1")
152                mediaList(storageItem.widget(), fieldlist.first());
153          }
154       }
155    }
156    /* Resize the columns */
157    for(int cnter=0; cnter<headerlist.size(); cnter++) {
158       mp_treeWidget->resizeColumnToContents(cnter);
159    }
160    m_firstpopulation = false;
161 }
162
163 /*
164  * For autochangers    A query to show the tapes in the changer.
165  */
166 void Storage::mediaList(QTreeWidgetItem *parent, const QString &storageID)
167 {
168    QString query("SELECT Media.VolumeName AS Media, Media.Slot AS Slot,"
169                  " Media.VolStatus AS VolStatus, Media.Enabled AS Enabled,"
170                  " Pool.Name AS MediaPool, Media.MediaType AS MediaType" 
171                  " From Media"
172                  " JOIN Pool ON (Media.PoolId=Pool.PoolId)"
173                  " WHERE Media.StorageId='" + storageID + "'"
174                  " AND Media.InChanger<>0"
175                  " ORDER BY Media.Slot");
176
177    QStringList results;
178    /* This could be a log item */
179    if (mainWin->m_sqlDebug) {
180       Pmsg1(000, "Storage query cmd : %s\n",query.toUtf8().data());
181    }
182    if (m_console->sql_cmd(query, results)) {
183       QString resultline;
184       QString field;
185       QStringList fieldlist;
186  
187       foreach (resultline, results) {
188          fieldlist = resultline.split("\t");
189          if (fieldlist.size() < 6)
190              continue; 
191
192          /* Iterate through fields in the record */
193          QStringListIterator fld(fieldlist);
194          int index = 0;
195          TreeItemFormatter fmt(*parent, 2);
196
197          /* volname */
198          fmt.setTextFld(index++, fld.next()); 
199  
200          /* skip the next two columns, unused by media */
201          index += 2;
202
203          /* slot */
204          fmt.setNumericFld(index++, fld.next());
205
206          /* status */
207          fmt.setVolStatusFld(index++, fld.next());
208
209          /* enabled */
210          fmt.setBoolFld(index++, fld.next()); 
211
212          /* pool */
213          fmt.setTextFld(index++, fld.next()); 
214
215          /* media type */
216          fmt.setTextFld(index++, fld.next()); 
217
218       }
219    }
220 }
221
222 /*
223  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
224  * The tree has been populated.
225  */
226 void Storage::PgSeltreeWidgetClicked()
227 {
228    if(!m_populated) {
229       populateTree();
230       createContextMenu();
231    }
232    if (!isOnceDocked()) {
233       dockPage();
234    }
235 }
236
237 /*
238  * Added to set the context menu policy based on currently active treeWidgetItem
239  * signaled by currentItemChanged
240  */
241 void Storage::treeItemChanged(QTreeWidgetItem *currentwidgetitem, QTreeWidgetItem *previouswidgetitem )
242 {
243    /* m_checkcurwidget checks to see if this is during a refresh, which will segfault */
244    if (m_checkcurwidget) {
245       /* The Previous item */
246       if (previouswidgetitem) { /* avoid a segfault if first time */
247          int treedepth = previouswidgetitem->data(0, Qt::UserRole).toInt();
248          if (treedepth == 1){
249             mp_treeWidget->removeAction(actionStatusStorageInConsole);
250             mp_treeWidget->removeAction(actionStatusStorageWindow);
251             mp_treeWidget->removeAction(actionLabelStorage);
252             mp_treeWidget->removeAction(actionMountStorage);
253             mp_treeWidget->removeAction(actionUnMountStorage);
254             mp_treeWidget->removeAction(actionUpdateSlots);
255             mp_treeWidget->removeAction(actionUpdateSlotsScan);
256             mp_treeWidget->removeAction(actionRelease);
257          }
258       }
259
260       int treedepth = currentwidgetitem->data(0, Qt::UserRole).toInt();
261       if (treedepth == 1){
262          /* set a hold variable to the storage name in case the context sensitive
263           * menu is used */
264          m_currentStorage = currentwidgetitem->text(0);
265          m_currentAutoChanger = currentwidgetitem->text(2) == tr("Yes");
266          mp_treeWidget->addAction(actionStatusStorageInConsole);
267          mp_treeWidget->addAction(actionStatusStorageWindow);
268          mp_treeWidget->addAction(actionLabelStorage);
269          mp_treeWidget->addAction(actionMountStorage);
270          mp_treeWidget->addAction(actionUnMountStorage);
271          mp_treeWidget->addAction(actionRelease);
272          QString text;
273          text = tr("Status Storage \"%1\"").arg(m_currentStorage);;
274          actionStatusStorageInConsole->setText(text);
275          text = tr("Status Storage \"%1\" in Window").arg(m_currentStorage);;
276          actionStatusStorageWindow->setText(text);
277          text = tr("Label media in Storage \"%1\"").arg(m_currentStorage);
278          actionLabelStorage->setText(text);
279          text = tr("Mount media in Storage \"%1\"").arg(m_currentStorage);
280          actionMountStorage->setText(text);
281          text = tr("\"UN\" Mount media in Storage \"%1\"").arg(m_currentStorage);
282          text = tr("Release media in Storage \"%1\"").arg(m_currentStorage);
283          actionRelease->setText(text);
284          if (m_currentAutoChanger) {
285             mp_treeWidget->addAction(actionUpdateSlots);
286             mp_treeWidget->addAction(actionUpdateSlotsScan);
287             text = tr("Barcode Scan media in Storage \"%1\"").arg(m_currentStorage);
288             actionUpdateSlots->setText(text);
289             text = tr("Read scan media in Storage \"%1\"").arg( m_currentStorage);
290             actionUpdateSlotsScan->setText(text);
291          }
292       }
293    }
294 }
295
296 /* 
297  * Setup a context menu 
298  * Made separate from populate so that it would not create context menu over and
299  * over as the tree is repopulated.
300  */
301 void Storage::createContextMenu()
302 {
303    mp_treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
304    mp_treeWidget->addAction(actionRefreshStorage);
305    connect(mp_treeWidget, SIGNAL(
306            currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
307            this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
308    /* connect to the action specific to this pages class */
309    connect(actionRefreshStorage, SIGNAL(triggered()), this,
310                 SLOT(populateTree()));
311    connect(actionStatusStorageInConsole, SIGNAL(triggered()), this,
312                 SLOT(consoleStatusStorage()));
313    connect(actionLabelStorage, SIGNAL(triggered()), this,
314                 SLOT(consoleLabelStorage()));
315    connect(actionMountStorage, SIGNAL(triggered()), this,
316                 SLOT(consoleMountStorage()));
317    connect(actionUnMountStorage, SIGNAL(triggered()), this,
318                 SLOT(consoleUnMountStorage()));
319    connect(actionUpdateSlots, SIGNAL(triggered()), this,
320                 SLOT(consoleUpdateSlots()));
321    connect(actionUpdateSlotsScan, SIGNAL(triggered()), this,
322                 SLOT(consoleUpdateSlotsScan()));
323    connect(actionRelease, SIGNAL(triggered()), this,
324                 SLOT(consoleRelease()));
325    connect(actionStatusStorageWindow, SIGNAL(triggered()), this,
326                 SLOT(statusStorageWindow()));
327    connect(mp_treeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
328            this, SLOT(contentWindow()));
329
330 }
331
332 void Storage::contentWindow()
333 {
334    if (m_currentStorage != "" && m_currentAutoChanger) { 
335       QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
336       new Content(m_currentStorage, parentItem);
337    }
338 }
339
340 /*
341  * Virtual function which is called when this page is visible on the stack
342  */
343 void Storage::currentStackItem()
344 {
345    if(!m_populated) {
346       populateTree();
347       /* Create the context menu for the storage tree */
348       createContextMenu();
349    }
350 }
351
352 /*
353  *  Functions to respond to local context sensitive menu sending console commands
354  *  If I could figure out how to make these one function passing a string, Yaaaaaa
355  */
356 void Storage::consoleStatusStorage()
357 {
358    QString cmd("status storage=");
359    cmd += m_currentStorage;
360    consoleCommand(cmd);
361 }
362
363 /* Label Media populating current storage by default */
364 void Storage::consoleLabelStorage()
365 {
366    new labelPage(m_currentStorage);
367 }
368
369 /* Mount currently selected storage */
370 void Storage::consoleMountStorage()
371 {
372    if (m_currentAutoChanger == 0){
373       /* no autochanger, just execute the command in the console */
374       QString cmd("mount storage=");
375       cmd += m_currentStorage;
376       consoleCommand(cmd);
377    } else {
378       setConsoleCurrent();
379       /* if this storage is an autochanger, lets ask for the slot */
380       new mountDialog(m_console, m_currentStorage);
381    }
382 }
383
384 /* Unmount Currently selected storage */
385 void Storage::consoleUnMountStorage()
386 {
387    QString cmd("umount storage=");
388    cmd += m_currentStorage;
389    consoleCommand(cmd);
390 }
391
392 /* Update Slots */
393 void Storage::consoleUpdateSlots()
394 {
395    QString cmd("update slots storage=");
396    cmd += m_currentStorage;
397    consoleCommand(cmd);
398 }
399
400 /* Update Slots Scan*/
401 void Storage::consoleUpdateSlotsScan()
402 {
403    QString cmd("update slots scan storage=");
404    cmd += m_currentStorage;
405    consoleCommand(cmd);
406 }
407
408 /* Release a tape in the drive */
409 void Storage::consoleRelease()
410 {
411    QString cmd("release storage=");
412    cmd += m_currentStorage;
413    consoleCommand(cmd);
414 }
415
416 /*
417  *  Open a status storage window
418  */
419 void Storage::statusStorageWindow()
420 {
421    /* if one exists, then just set it current */
422    bool found = false;
423    foreach(Pages *page, mainWin->m_pagehash) {
424       if (mainWin->currentConsole() == page->console()) {
425          if (page->name() == tr("Storage Status %1").arg(m_currentStorage)) {
426             found = true;
427             page->setCurrent();
428          }
429       }
430    }
431    if (!found) {
432       QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
433       new StorStat(m_currentStorage, parentItem);
434    }
435 }
436
437 /*
438  * Write settings to save expanded states of the pools
439  */
440 void Storage::writeExpandedSettings()
441 {
442    QSettings settings(m_console->m_dir->name(), "bat");
443    settings.beginGroup("StorageTreeExpanded");
444    int childcount = m_topItem->childCount();
445    for (int cnt=0; cnt<childcount; cnt++) {
446       QTreeWidgetItem *item = m_topItem->child(cnt);
447       settings.setValue(item->text(0), item->isExpanded());
448    }
449    settings.endGroup();
450 }
451
452 /*
453  * If first time, then check to see if there were status pages open the last time closed
454  * if so open
455  */
456 void Storage::settingsOpenStatus(QString &storage)
457 {
458    QSettings settings(m_console->m_dir->name(), "bat");
459
460    settings.beginGroup("OpenOnExit");
461    QString toRead = "StorageStatus_" + storage;
462    if (settings.value(toRead) == 1) {
463       if (mainWin->m_sqlDebug) {
464          Pmsg1(000, "Do open Storage Status window for : %s\n", storage.toUtf8().data());
465       }
466       new StorStat(storage, mainWin->getFromHash(this));
467       setCurrent();
468       mainWin->getFromHash(this)->setExpanded(true);
469    } else {
470       if (mainWin->m_sqlDebug) {
471          Pmsg1(000, "Do NOT open Storage Status window for : %s\n", storage.toUtf8().data());
472       }
473    }
474    settings.endGroup();
475 }