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