]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/medialist/mediaview.cpp
Tweak copyrights
[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 two of the GNU 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 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()
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    QList<QTableWidgetItem*> items = m_tableMedia->selectedItems();
119    QTableWidgetItem *it;
120    int row;
121    int *tab;
122    int nb = items.count();
123    if (!nb) {
124       return false;
125    }
126    tab = (int *) malloc (nb * sizeof(int));
127    memset(tab, 0, sizeof(int)*nb);
128    for (int i = 0; i < nb; ++i) {
129       row = items[i]->row();
130       if (!tab[row]) {
131          tab[row]=1;
132          it = m_tableMedia->item(row, 0);
133          list.append(it->text());
134       }
135    }
136    free(tab);
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 (m_console->sql_cmd(query, results)) {
291       foreach (resultline, results) {
292          fieldlist = resultline.split("\t");
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 //   Pmsg1(000, "MediaView query cmd : %s\n",query.toUtf8().data());
312    m_tableMedia->setSortingEnabled(false); /* Don't sort during insert */
313    results.clear();
314    if (m_console->sql_cmd(query, results)) {
315       int row=0;
316       filterExipired(results);
317       m_tableMedia->setRowCount(results.size());
318
319       foreach (resultline, results) { // should have only one result
320          int index = 0;
321          QString VolBytes, MediaType, LastWritten, VolStatus;
322          fieldlist = resultline.split("\t");
323          if (fieldlist.size() != 10) {
324             continue;
325          }
326          QStringListIterator fld(fieldlist);
327          TableItemFormatter mediaitem(*m_tableMedia, row);
328
329          /* VolumeName */
330          mediaitem.setTextFld(index++, fld.next()); 
331          
332          /* Online */
333          mediaitem.setInChanger(index++, fld.next());
334          fld.next();            // Slot
335
336          MediaType = fld.next();
337          VolStatus = fld.next();
338
339          /* Volume bytes */
340          VolBytes = fld.next();
341          mediaitem.setBytesFld(index++, VolBytes);
342
343          /* Usage */
344          usage = 0;
345          if (hash_size.contains(MediaType) &&
346              hash_size[MediaType] != 0) {
347             usage = VolBytes.toLongLong() * 100 / hash_size[MediaType];
348          }
349          mediaitem.setPercent(index++, usage);
350
351          /* Volstatus */
352          mediaitem.setVolStatusFld(index++, VolStatus);
353
354          /* Pool */
355          mediaitem.setTextFld(index++, fld.next());
356
357          /* MediaType */
358          mediaitem.setTextFld(index++, MediaType);
359
360          LastWritten = fld.next();
361          buf[0] = 0;
362          if (LastWritten != "") {
363             stat = fld.next();  // VolUseDuration
364             t = str_to_utime(LastWritten.toAscii().data());
365             t = t + stat.toULongLong();
366             ttime = t;
367             localtime_r(&ttime, &tm);         
368             strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
369          }
370          
371          /* LastWritten */
372          mediaitem.setTextFld(index++, LastWritten);
373
374          /* When expired */
375          mediaitem.setTextFld(index++, buf);
376          row++;
377       }
378    }
379    m_tableMedia->resizeColumnsToContents();
380    m_tableMedia->resizeRowsToContents();
381    m_tableMedia->verticalHeader()->hide();
382    m_tableMedia->setSortingEnabled(true);
383
384    /* make read only */
385    m_tableMedia->setEditTriggers(QAbstractItemView::NoEditTriggers);
386 }
387
388 /*
389  * When the treeWidgetItem in the page selector tree is singleclicked, Make sure
390  * The tree has been populated.
391  */
392 void MediaView::PgSeltreeWidgetClicked()
393 {
394    if (!m_populated) {
395       populateForm();
396       populateTable();
397    }
398    if (!isOnceDocked()) {
399       dockPage();
400    }
401 }
402
403 /*
404  * Virtual function which is called when this page is visible on the stack
405  */
406 void MediaView::currentStackItem()
407 {
408    if(!m_populated) {
409       populateForm();
410       populateTable();
411    }
412 }
413
414 // /*
415 //  * Called from the signal of the context sensitive menu to relabel!
416 //  */
417 // void MediaView::relabelVolume()
418 // {
419 //    setConsoleCurrent();
420 //    new relabelDialog(m_console, m_currentVolumeName);
421 // }
422 // 
423 // /*
424 //  * Called from the signal of the context sensitive menu to purge!
425 //  */
426 // void MediaView::allVolumesFromPool()
427 // {
428 //    QString cmd = "update volume AllFromPool=" + m_currentVolumeName;
429 //    consoleCommand(cmd);
430 //    populateTable();
431 // }
432 // 
433 // void MediaView::allVolumes()
434 // {
435 //    QString cmd = "update volume allfrompools";
436 //    consoleCommand(cmd);
437 //    populateTable();
438 // }
439 // 
440 //  /*
441 //   * Called from the signal of the context sensitive menu to purge!
442 //   */
443 //  void MediaView::volumeFromPool()
444 //  {
445 //     QTreeWidgetItem *currentItem = mp_treeWidget->currentItem();
446 //     QTreeWidgetItem *parent = currentItem->parent();
447 //     QString pool = parent->text(0);
448 //     QString cmd;
449 //     cmd = "update volume=" + m_currentVolumeName + " frompool=" + pool;
450 //     consoleCommand(cmd);
451 //     populateTable();
452 //  }
453 //