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