]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/medialist/mediaview.cpp
Backport from BEE
[bacula/bacula] / bacula / src / qt-console / medialist / mediaview.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    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    Bacula® is a registered trademark of Kern Sibbald.
15 */
16
17 #include "bat.h"
18 #include <QAbstractEventDispatcher>
19 #include <QMenu>
20 #include <math.h>
21 #include "mediaview.h"
22 #include "mediaedit/mediaedit.h"
23 #include "mediainfo/mediainfo.h"
24 #include "joblist/joblist.h"
25 #include "relabel/relabel.h"
26 #include "run/run.h"
27 #include "util/fmtwidgetitem.h"
28
29 MediaView::MediaView() : Pages()
30 {
31    setupUi(this);
32    m_name = tr("Media");
33    pgInitialize();
34    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
35    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/cartridge.png")));
36    connect(m_pbApply, SIGNAL(pressed()), this, SLOT(applyPushed()));
37    connect(m_pbEdit, SIGNAL(pressed()), this, SLOT(editPushed()));
38    connect(m_pbPurge, SIGNAL(pressed()), this, SLOT(purgePushed()));
39    connect(m_pbDelete, SIGNAL(pressed()), this, SLOT(deletePushed()));
40    connect(m_pbPrune, SIGNAL(pressed()), this, SLOT(prunePushed()));
41    connect(m_tableMedia, SIGNAL(itemDoubleClicked(QTableWidgetItem*)),
42            this, SLOT(showInfoForMedia(QTableWidgetItem *)));
43
44    /* mp_treeWidget, Storage Tree Tree Widget inherited from ui_medialist.h */
45    m_populated = false;
46    m_checkcurwidget = true;
47    m_closeable = false;
48 }
49
50 void MediaView::showInfoForMedia(QTableWidgetItem * item)
51 {
52    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
53    int row = item->row();
54    QString vol = m_tableMedia->item(row, 0)->text();
55    new MediaInfo(pageSelectorTreeWidgetItem, vol);
56 //   connect(j, SIGNAL(destroyed()), this, SLOT(populateTree()));
57 }
58
59 MediaView::~MediaView()
60 {
61 }
62
63 void MediaView::applyPushed()
64 {
65    populateTable();
66 }
67
68 void MediaView::editPushed()
69 {
70    QStringList sel;
71    QString cmd;
72    getSelection(sel);
73
74    for(int i=0; i<sel.count(); i++) {
75       cmd = sel.at(i);
76       new MediaEdit(mainWin->getFromHash(this), cmd);
77    }
78 }
79
80 void MediaView::purgePushed()
81 {
82    if (QMessageBox::warning(this, "Bat",
83       tr("Are you sure you want to purge ??  !!!.\n"
84 "The Purge command will delete associated Catalog database records from Jobs and"
85 " Volumes without considering the retention period. Purge  works only on the"
86 " Catalog database and does not affect data written to Volumes. This command can"
87 " be dangerous because you can delete catalog records associated with current"
88 " backups of files, and we recommend that you do not use it unless you know what"
89 " you are doing.\n"
90       "Press OK to proceed with the purge operation?"),
91       QMessageBox::Ok | QMessageBox::Cancel)
92       == QMessageBox::Cancel) { return; }
93
94    QStringList lst;
95    QString cmd;
96    getSelection(lst);
97    for(int i=0; i<lst.count(); i++) {
98       cmd = "purge volume=" + lst.at(i);
99       consoleCommand(cmd);
100    }
101    populateTable();
102 }
103
104 bool MediaView::getSelection(QStringList &list)
105 {
106    int i, nb, nr_rows, row;
107    bool *tab;
108    QTableWidgetItem *it;
109    QList<QTableWidgetItem*> items = m_tableMedia->selectedItems();
110
111    /*
112     * See if anything is selected.
113     */
114    nb = items.count();
115    if (!nb) {
116       return false;
117    }
118
119    /*
120     * Create a nibble map for each row so we can see if its
121     * selected or not.
122     */
123    nr_rows = m_tableMedia->rowCount();
124    tab = (bool *)malloc (nr_rows * sizeof(bool));
125    memset(tab, 0, sizeof(bool) * nr_rows);
126
127    for (i = 0; i < nb; ++i) {
128       row = items[i]->row();
129       if (!tab[row]) {
130          tab[row] = true;
131          it = m_tableMedia->item(row, 0);
132          list.append(it->text());
133       }
134    }
135    free(tab);
136
137    return list.count() > 0;
138 }
139
140 void MediaView::prunePushed()
141 {
142    QStringList sel;
143    QString cmd;
144    getSelection(sel);
145
146    for(int i=0; i<sel.count(); i++) {
147       cmd = "prune volume=" + sel.at(i);
148       consoleCommand(cmd);
149    }
150 }
151
152
153 void MediaView::deletePushed()
154 {
155    if (QMessageBox::warning(this, "Bat",
156       tr("Are you sure you want to delete??  !!!.\n"
157 "This delete command is used to delete a Volume record and all associated catalog"
158 " records that were created. This command operates only on the Catalog"
159 " database and has no effect on the actual data written to a Volume. This"
160 " command can be dangerous and we strongly recommend that you do not use"
161 " it unless you know what you are doing.  All Jobs and all associated"
162 " records (File and JobMedia) will be deleted from the catalog."
163       "Press OK to proceed with delete operation.?"),
164       QMessageBox::Ok | QMessageBox::Cancel)
165       == QMessageBox::Cancel) { return; }
166
167    QStringList lst;
168    QString cmd;
169    getSelection(lst);
170    for(int i=0; i<lst.count(); i++) {
171       cmd = "delete volume=" + lst.at(i);
172       consoleCommand(cmd);
173    }
174    populateTable();
175 }
176
177 void MediaView::populateForm()
178 {
179    m_cbPool->clear();
180    m_cbPool->addItem("");
181    m_cbPool->addItems(m_console->pool_list);
182
183    m_cbStatus->clear();
184    m_cbStatus->addItem("");
185    m_cbStatus->addItems(m_console->volstatus_list);
186
187    m_cbMediaType->clear();
188    m_cbMediaType->addItem("");
189    m_cbMediaType->addItems(m_console->mediatype_list);
190
191    m_cbLocation->clear();
192    m_cbLocation->addItem("");
193    m_cbLocation->addItems(m_console->location_list);
194 }
195
196 /*
197  * If chkExpired button is checked, we can remove all non Expired
198  * entries
199  */
200 void MediaView::filterExipired(QStringList &list)
201 {
202    utime_t t, now = time(NULL);
203    QString resultline, stat, LastWritten;
204    QStringList fieldlist;
205
206    /* We should now in advance how many rows we will have */
207    if (m_chkExpired->isChecked()) {
208       for (int i=list.size() -1; i >= 0; i--) {
209          fieldlist = list.at(i).split("\t");
210          ASSERT(fieldlist.size() != 9);
211          LastWritten = fieldlist.at(7);
212          if (LastWritten == "") {
213             list.removeAt(i);
214
215          } else {
216             stat = fieldlist.at(8);
217             t = str_to_utime(LastWritten.toAscii().data());
218             t = t + stat.toULongLong();
219             if (t > now) {
220                list.removeAt(i);
221             }
222          }
223       }
224    }
225 }
226
227 /*
228  * The main meat of the class!!  The function that querries the director and
229  * creates the widgets with appropriate values.
230  */
231 void MediaView::populateTable()
232 {
233    utime_t t;
234    time_t ttime;
235    QString stat, resultline, query;
236    QString str_usage;
237    QHash<QString, float> hash_size;
238    QStringList fieldlist, results;
239    char buf[256];
240    float usage;
241    struct tm tm;
242
243    m_populated = true;
244
245    Freeze frz(*m_tableMedia); /* disable updating*/
246    QStringList where;
247    QString cmd;
248    if (m_cbPool->currentText() != "") {
249       cmd = " Pool.Name = '" + m_cbPool->currentText() + "'";
250       where.append(cmd);
251    }
252
253    if (m_cbStatus->currentText() != "") {
254       cmd = " Media.VolStatus = '" + m_cbStatus->currentText() + "'";
255       where.append(cmd);
256    }
257
258    if (m_cbStatus->currentText() != "") {
259       cmd = " Media.VolStatus = '" + m_cbStatus->currentText() + "'";
260       where.append(cmd);
261    }
262
263    if (m_cbMediaType->currentText() != "") {
264       cmd = " Media.MediaType = '" + m_cbMediaType->currentText() + "'";
265       where.append(cmd);
266    }
267
268    if (m_cbLocation->currentText() != "") {
269       cmd = " Location.Location = '" + m_cbLocation->currentText() + "'";
270       where.append(cmd);
271    }
272
273    if (m_textName->text() != "") {
274       cmd = " Media.VolumeName like '%" + m_textName->text() + "%'";
275       where.append(cmd);
276    }
277
278    if (where.size() > 0) {
279       cmd = " WHERE " + where.join(" AND ");
280    } else {
281       cmd = "";
282    }
283
284    query =
285       "SELECT AVG(VolBytes) AS size, COUNT(1) as nb, "
286       "MediaType  FROM Media "
287       "WHERE VolStatus IN ('Full', 'Used') "
288       "GROUP BY MediaType";
289
290    if (mainWin->m_sqlDebug) {
291       Pmsg1(000, "MediaView query cmd : %s\n",query.toUtf8().data());
292    }
293    if (m_console->sql_cmd(query, results)) {
294       foreach (resultline, results) {
295          fieldlist = resultline.split("\t");
296          if (fieldlist.at(1).toInt() >= 1) {
297             //           MediaType
298             hash_size[fieldlist.at(2)]
299                = fieldlist.at(0).toFloat();
300          }
301       }
302    }
303
304    m_tableMedia->clearContents();
305    query =
306       "SELECT VolumeName, InChanger, "
307       "Slot, MediaType, VolStatus, VolBytes, Pool.Name,  "
308       "LastWritten, Media.VolRetention "
309       "FROM Media JOIN Pool USING (PoolId) "
310       "LEFT JOIN Location ON (Media.LocationId=Location.LocationId) "
311       + cmd +
312       " ORDER BY VolumeName LIMIT " + m_sbLimit->cleanText();
313
314    m_tableMedia->sortByColumn(0, Qt::AscendingOrder);
315    m_tableMedia->setSortingEnabled(false); /* Don't sort during insert */
316    results.clear();
317    if (mainWin->m_sqlDebug) {
318       Pmsg1(000, "MediaView query cmd : %s\n",query.toUtf8().data());
319    }
320    if (m_console->sql_cmd(query, results)) {
321       int row=0;
322       filterExipired(results);
323       m_tableMedia->setRowCount(results.size());
324
325       foreach (resultline, results) { // should have only one result
326          int index = 0;
327          QString VolBytes, MediaType, LastWritten, VolStatus;
328          fieldlist = resultline.split("\t");
329          if (fieldlist.size() != 10) {
330             continue;
331          }
332          QStringListIterator fld(fieldlist);
333          TableItemFormatter mediaitem(*m_tableMedia, row);
334
335          /* VolumeName */
336          mediaitem.setTextFld(index++, fld.next());
337
338          /* Online */
339          mediaitem.setInChanger(index++, fld.next());
340
341          /* Slot */
342          mediaitem.setNumericFld(index++, fld.next());
343
344          MediaType = fld.next();
345          VolStatus = fld.next();
346
347          /* Volume bytes */
348          VolBytes = fld.next();
349          mediaitem.setBytesFld(index++, VolBytes);
350
351          /* Usage */
352          usage = 0;
353          if (hash_size.contains(MediaType) &&
354              hash_size[MediaType] != 0) {
355             usage = VolBytes.toLongLong() * 100 / hash_size[MediaType];
356          }
357          mediaitem.setPercent(index++, usage);
358
359          /* Volstatus */
360          mediaitem.setVolStatusFld(index++, VolStatus);
361
362          /* Pool */
363          mediaitem.setTextFld(index++, fld.next());
364
365          /* MediaType */
366          mediaitem.setTextFld(index++, MediaType);
367
368          LastWritten = fld.next();
369          buf[0] = 0;
370          if (LastWritten != "") {
371             stat = fld.next();  // VolUseDuration
372             t = str_to_utime(LastWritten.toAscii().data());
373             t = t + stat.toULongLong();
374             ttime = t;
375             localtime_r(&ttime, &tm);
376             strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
377          }
378
379          /* LastWritten */
380          mediaitem.setTextFld(index++, LastWritten);
381
382          /* When expired */
383          mediaitem.setTextFld(index++, buf);
384          row++;
385       }
386    }
387    m_tableMedia->resizeColumnsToContents();
388    m_tableMedia->resizeRowsToContents();
389    m_tableMedia->verticalHeader()->hide();
390    m_tableMedia->setSortingEnabled(true);
391
392    /* make read only */
393    m_tableMedia->setEditTriggers(QAbstractItemView::NoEditTriggers);
394 }
395
396 /*
397  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
398  * The tree has been populated.
399  */
400 void MediaView::PgSeltreeWidgetClicked()
401 {
402    if (!m_populated) {
403       populateForm();
404       populateTable();
405    }
406    if (!isOnceDocked()) {
407       dockPage();
408    }
409 }
410
411 /*
412  * Virtual function which is called when this page is visible on the stack
413  */
414 void MediaView::currentStackItem()
415 {
416    if(!m_populated) {
417       populateForm();
418       populateTable();
419    }
420 }
421
422 // /*
423 //  * Called from the signal of the context sensitive menu to relabel!
424 //  */
425 // void MediaView::relabelVolume()
426 // {
427 //    setConsoleCurrent();
428 //    new relabelDialog(m_console, m_currentVolumeName);
429 // }
430 //
431 // /*
432 //  * Called from the signal of the context sensitive menu to purge!
433 //  */
434 // void MediaView::allVolumesFromPool()
435 // {
436 //    QString cmd = "update volume AllFromPool=" + m_currentVolumeName;
437 //    consoleCommand(cmd);
438 //    populateTable();
439 // }
440 //
441 // void MediaView::allVolumes()
442 // {
443 //    QString cmd = "update volume allfrompools";
444 //    consoleCommand(cmd);
445 //    populateTable();
446 // }
447 //
448 //  /*
449 //   * Called from the signal of the context sensitive menu to purge!
450 //   */
451 //  void MediaView::volumeFromPool()
452 //  {
453 //     QTreeWidgetItem *currentItem = mp_treeWidget->currentItem();
454 //     QTreeWidgetItem *parent = currentItem->parent();
455 //     QString pool = parent->text(0);
456 //     QString cmd;
457 //     cmd = "update volume=" + m_currentVolumeName + " frompool=" + pool;
458 //     consoleCommand(cmd);
459 //     populateTable();
460 //  }
461 //