]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/restore/brestore.cpp
bat: Use current set of jobids for directories
[bacula/bacula] / bacula / src / qt-console / restore / brestore.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2009 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 /*
30  *
31  *  bRestore Class  (Eric's brestore)
32  *
33  *   Kern Sibbald, January MMVII
34  *
35  */ 
36
37 #include "bat.h"
38 #include "restore.h"
39 #include "util/fmtwidgetitem.h"
40
41 bRestore::bRestore()
42 {
43    m_name = tr("bRestore");
44    m_client = "";
45    setupUi(this);
46    pgInitialize();
47    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
48    thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
49    m_populated = false;
50    m_current = NULL;
51    RestoreList->setAcceptDrops(true);
52 }
53
54 void bRestore::setClient()
55 {
56    Pmsg0(000, "Repopulating client table\n");
57    // Select the same client, don't touch
58    if (m_client == ClientList->currentText()) {
59       return;
60    }
61    m_client = ClientList->currentText();
62    FileList->clearContents();
63    FileRevisions->clearContents();
64    JobList->clear();
65    JobList->setEnabled(true);
66    LocationEntry->clear();
67    m_path = "";
68    m_pathid = 0;
69
70    if (ClientList->currentIndex() < 1) {
71       JobList->setEnabled(false);
72       return;
73    }
74
75    JobList->addItem("Job list for " + m_client);
76
77    QString jobQuery =
78       "SELECT Job.Jobid AS JobId, Job.StartTime AS StartTime,"
79       " Job.Level AS Level,"
80       " Job.Name AS Name"
81       " FROM Job JOIN Client USING (ClientId)"
82       " WHERE"
83       " Job.JobStatus IN ('T','W') AND Job.Type='B' AND"
84       " Client.Name='" + m_client + "' ORDER BY StartTime DESC" ;
85
86    QString job;
87    QStringList results;
88    if (m_console->sql_cmd(jobQuery, results)) {
89       QStringList fieldlist;
90
91       /* Iterate through the record returned from the query */
92       foreach (QString resultline, results) {
93          fieldlist = resultline.split("\t");
94          job = fieldlist[1] + " " + fieldlist[3] + "(" + fieldlist[2] + ") " + fieldlist[0];
95          JobList->addItem(job, QVariant(fieldlist[0]));
96       }
97    }
98 }
99
100
101 void bRestore::setJob()
102 {
103    if (JobList->currentIndex() < 1) {
104       FileList->clearContents();
105       FileList->setRowCount(0);
106       FileRevisions->clearContents();
107       FileRevisions->setRowCount(0);
108       return ;
109    }
110    QStringList results;
111    QVariant tmp = JobList->itemData(JobList->currentIndex(), Qt::UserRole);
112
113    m_jobids = tmp.toString();
114    QString cmd = ".bvfs_get_jobids jobid=" + m_jobids;
115    if (MergeChk->checkState() == Qt::Checked) {
116       cmd.append(" all");
117    }
118
119    m_console->dir_cmd(cmd, results);
120
121    if (results.size() < 1) {
122       FileList->clearContents();
123       FileList->setRowCount(0);
124       FileRevisions->clearContents();
125       FileRevisions->setRowCount(0);
126       return;
127    }
128
129    m_jobids = results.at(0);
130    cmd = ".bvfs_update jobid=" + m_jobids;
131    m_console->dir_cmd(cmd, results);
132
133    Pmsg1(0, "jobids=%s\n", m_jobids.toLocal8Bit().constData());
134
135    displayFiles(m_pathid, QString(""));
136    Pmsg0(000, "update done\n");
137 }
138
139 extern int decode_stat(char *buf, struct stat *statp, int32_t *LinkFI);
140
141 void bRestore::displayFiles(int64_t pathid, QString path)
142 {
143    QString arg;
144    QStringList results;
145    QStringList fieldlist;
146    struct stat statp;
147    int32_t LinkFI;
148    int nb;
149    int row=0;
150    Freeze frz_lst(*FileList); /* disable updating*/
151    Freeze frz_rev(*FileRevisions); /* disable updating*/
152    FileList->clearContents();
153    FileRevisions->clearContents();
154    FileRevisions->setRowCount(0);
155
156    if (pathid > 0) {
157       arg = " pathid=" + QString().setNum(pathid);
158
159       if (path == "..") {
160          if (m_path == "/") {
161             m_path = "";
162          } else {
163             m_path.remove(QRegExp("[^/]+/$"));
164          }
165
166       } else if (path == "/" && m_path == "") {
167          m_path += path;
168
169       } else if (path != "/" && path != ".") {
170          m_path += path;
171       }
172    } else {
173       m_path = path;
174       arg = " path=\"" + m_path + "\"";
175    }
176    LocationEntry->setText(m_path);
177
178    QString q = ".bvfs_lsdir jobid=" + m_jobids + arg;
179    if (m_console->dir_cmd(q, results)) {
180       nb = results.size();
181       FileList->setRowCount(nb);
182       foreach (QString resultline, results) {
183          int col=0;
184          //PathId, FilenameId, fileid, jobid, lstat, path
185          fieldlist = resultline.split("\t");
186          TableItemFormatter item(*FileList, row++);
187          item.setFileType(col++, QString("folder")); // folder or file
188          item.setTextFld(col++, fieldlist.at(5)); // path
189          decode_stat(fieldlist.at(4).toLocal8Bit().data(), 
190                      &statp, &LinkFI);
191          item.setDateFld(col++, statp.st_mtime); // date
192          fieldlist.replace(3, m_jobids);      // use current jobids selection
193          item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t")); // keep info
194       }
195    }
196
197    results.clear();
198    q = ".bvfs_lsfiles jobid=" + m_jobids + arg;
199    if (m_console->dir_cmd(q, results)) {
200       FileList->setRowCount(results.size() + nb);
201       foreach (QString resultline, results) {
202          int col=1;            // skip icon
203          //PathId, FilenameId, fileid, jobid, lstat, name
204          fieldlist = resultline.split("\t");
205          TableItemFormatter item(*FileList, row++);
206          item.setTextFld(col++, fieldlist.at(5)); // name
207          decode_stat(fieldlist.at(4).toLocal8Bit().data(), 
208                      &statp, &LinkFI);
209          item.setBytesFld(col++, QString().setNum(statp.st_size));
210          item.setDateFld(col++, statp.st_mtime);
211          item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t")); // keep info
212       }
213    }
214    FileList->verticalHeader()->hide();
215    FileList->resizeColumnsToContents();
216    FileList->resizeRowsToContents();
217    FileList->setEditTriggers(QAbstractItemView::NoEditTriggers);
218 }
219
220 void bRestore::PgSeltreeWidgetClicked()
221 {
222    if(!m_populated) {
223       setupPage();
224    }
225    if (!isOnceDocked()) {
226       dockPage();
227    }
228 }
229
230 void bRestore::displayFileVersion(QString pathid, QString fnid, 
231                                   QString client, QString filename)
232 {
233    int row=0;
234    struct stat statp;
235    int32_t LinkFI;
236    Freeze frz_rev(*FileRevisions); /* disable updating*/
237    FileRevisions->clearContents();
238    
239    QString q = ".bvfs_versions jobid=" + m_jobids +
240       " pathid=" + pathid + 
241       " fnid=" + fnid + 
242       " client=" + client;
243
244    if (VersionsChk->checkState() == Qt::Checked) {
245       q.append(" versions");
246    }
247
248    QStringList results;
249    QStringList fieldlist;
250    QString tmp;
251    if (m_console->dir_cmd(q, results)) {
252       FileRevisions->setRowCount(results.size());
253       foreach (QString resultline, results) {
254          int col=0;
255          // 0        1          2        3      4    5      6        7
256          //PathId, FilenameId, fileid, jobid, lstat, Md5, VolName, Inchanger
257          fieldlist = resultline.split("\t");
258          TableItemFormatter item(*FileRevisions, row++);
259          item.setInChanger(col++, fieldlist.at(7));    // inchanger
260          item.setTextFld(col++, fieldlist.at(6)); // Volume
261          item.setNumericFld(col++, fieldlist.at(3)); // JobId
262          decode_stat(fieldlist.at(4).toLocal8Bit().data(), 
263                      &statp, &LinkFI);
264          item.setBytesFld(col++, QString().setNum(statp.st_size)); // size
265          item.setDateFld(col++, statp.st_mtime); // date
266          item.setTextFld(col++, fieldlist.at(5)); // chksum
267
268          // Adjust the fieldlist for drag&drop
269          fieldlist.removeLast(); // inchanger
270          fieldlist.removeLast(); // volname
271          fieldlist.removeLast(); // md5
272          fieldlist << m_path + filename;
273          item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t")); // keep info
274       }
275    }
276    FileRevisions->verticalHeader()->hide();
277    FileRevisions->resizeColumnsToContents();
278    FileRevisions->resizeRowsToContents();
279    FileRevisions->setEditTriggers(QAbstractItemView::NoEditTriggers);
280 }
281
282 void bRestore::showInfoForFile(QTableWidgetItem *widget)
283 {
284    m_current = widget;
285    QTableWidgetItem *first = FileList->item(widget->row(), 1);
286    QStringList lst = first->data(Qt::UserRole).toString().split("\t");
287    if (lst.at(1) == "0") {      // no filenameid, should be a path
288       displayFiles(lst.at(0).toLongLong(), lst.at(5));
289    } else {
290       displayFileVersion(lst.at(0), lst.at(1), m_client, lst.at(5));
291    }
292 }
293
294 void bRestore::applyLocation()
295 {
296    displayFiles(0, LocationEntry->text());
297 }
298
299 void bRestore::clearVersions(QTableWidgetItem *item)
300 {
301    if (item != m_current) {
302       FileRevisions->clearContents();
303       FileRevisions->setRowCount(0);
304    }
305    m_current = item ;
306 }
307
308 void bRestore::clearRestoreList()
309 {
310    RestoreList->clearContents();
311    RestoreList->setRowCount(0);
312 }
313
314 void bRestore::setupPage()
315 {
316    ClientList->addItem("Client list");
317    ClientList->addItems(m_console->client_list);
318    connect(ClientList, SIGNAL(currentIndexChanged(int)), this, SLOT(setClient()));
319    connect(JobList, SIGNAL(currentIndexChanged(int)), this, SLOT(setJob()));
320    connect(FileList, SIGNAL(itemClicked(QTableWidgetItem*)), 
321            this, SLOT(clearVersions(QTableWidgetItem *)));
322    connect(FileList, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), 
323            this, SLOT(showInfoForFile(QTableWidgetItem *)));
324    connect(LocationBp, SIGNAL(pressed()), this, SLOT(applyLocation()));
325    connect(MergeChk, SIGNAL(clicked()), this, SLOT(setJob()));
326    connect(ClearBp, SIGNAL(clicked()), this, SLOT(clearRestoreList()));
327    m_populated = true;
328 }
329
330 bRestore::~bRestore()
331 {
332 }
333
334 void bRestoreTable::mousePressEvent(QMouseEvent *event)
335 {
336    QTableWidget::mousePressEvent(event);
337
338    if (event->button() == Qt::LeftButton) {
339       dragStartPosition = event->pos();
340    }
341 }
342
343 // This event permits to send set custom data on drag&drop
344 // Don't forget to call original class if we are not interested
345 void bRestoreTable::mouseMoveEvent(QMouseEvent *event)
346 {
347    int lastrow=-1;
348
349    // Look just for drag&drop
350    if (!(event->buttons() & Qt::LeftButton)) {
351       QTableWidget::mouseMoveEvent(event);
352       return;
353    }
354    if ((event->pos() - dragStartPosition).manhattanLength()
355        < QApplication::startDragDistance())
356    {
357       QTableWidget::mouseMoveEvent(event);
358       return;
359    }
360
361    QList<QTableWidgetItem *> lst = selectedItems();
362    qDebug() << this << " selectedItems: " << lst;
363    if (lst.isEmpty()) {
364       return;
365    }
366
367    QDrag *drag = new QDrag(this);
368    QMimeData *mimeData = new QMimeData;
369    for (int i=0; i < lst.size(); i++) {
370       if (lastrow != lst[i]->row()) {
371          lastrow = lst[i]->row();
372          QTableWidgetItem *it = item(lastrow, 1);
373          mimeData->setText(it->data(Qt::UserRole).toString());
374          break;                  // at this time, we do it one by one
375       }
376    }
377    drag->setMimeData(mimeData);
378    drag->exec();
379 }
380
381 // This event is called when the drag item enters in the destination area
382 void bRestoreTable::dragEnterEvent(QDragEnterEvent *event)
383 {
384    if (event->source() == this) {
385       event->ignore();
386       return;
387    }
388    if (event->mimeData()->hasText()) {
389       event->acceptProposedAction();
390    } else {
391       event->ignore();
392    }
393 }
394
395 // It should not be essential to redefine this event, but it
396 // doesn't work if not defined
397 void bRestoreTable::dragMoveEvent(QDragMoveEvent *event)
398 {
399    if (event->mimeData()->hasText()) {
400       event->acceptProposedAction();
401    } else {
402       event->ignore();
403    }
404 }
405
406 void bRestoreTable::dropEvent(QDropEvent *event)
407 {
408    int col=1;
409    struct stat statp;
410    int32_t LinkFI;
411    if (event->mimeData()->hasText()) {
412       TableItemFormatter item(*this, rowCount());
413       setRowCount(rowCount() + 1);
414       QStringList fields = event->mimeData()->text().split("\t");
415       if (fields.size() != 6) {
416          event->ignore();
417          return;
418       }
419       if (fields.at(1) == "0") {
420          item.setFileType(0, "folder");
421       }
422       item.setTextFld(col++, fields.at(5)); // filename
423       decode_stat(fields.at(4).toLocal8Bit().data(), 
424                   &statp, &LinkFI);
425       item.setBytesFld(col++, QString().setNum(statp.st_size)); // size
426       item.setDateFld(col++, statp.st_mtime); // date
427       item.setNumericFld(col++, fields.at(3)); // jobid
428       item.setNumericFld(col++, fields.at(2)); // fileid
429       item.widget(1)->setData(Qt::UserRole, event->mimeData()->text());
430       event->acceptProposedAction();
431    } else {
432       event->ignore();
433    }
434 }
435