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