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