2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
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
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.
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
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.
31 * bRestore Class (Eric's brestore)
33 * Kern Sibbald, January MMVII
39 #include "util/fmtwidgetitem.h"
43 m_name = tr("bRestore");
47 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
48 thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
51 RestoreList->setAcceptDrops(true);
54 void bRestore::setClient()
56 Pmsg0(000, "Repopulating client table\n");
57 // Select the same client, don't touch
58 if (m_client == ClientList->currentText()) {
61 m_client = ClientList->currentText();
62 FileList->clearContents();
63 FileRevisions->clearContents();
65 JobList->setEnabled(true);
66 LocationEntry->clear();
70 if (ClientList->currentIndex() < 1) {
71 JobList->setEnabled(false);
75 JobList->addItem("Job list for " + m_client);
78 "SELECT Job.Jobid AS JobId, Job.StartTime AS StartTime,"
79 " Job.Level AS Level,"
81 " FROM Job JOIN Client USING (ClientId)"
83 " Job.JobStatus IN ('T','W') AND Job.Type='B' AND"
84 " Client.Name='" + m_client + "' ORDER BY StartTime DESC" ;
88 if (m_console->sql_cmd(jobQuery, results)) {
89 QStringList fieldlist;
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]));
101 void bRestore::setJob()
103 if (JobList->currentIndex() < 1) {
104 FileList->clearContents();
105 FileList->setRowCount(0);
106 FileRevisions->clearContents();
107 FileRevisions->setRowCount(0);
111 QVariant tmp = JobList->itemData(JobList->currentIndex(), Qt::UserRole);
113 m_jobids = tmp.toString();
114 QString cmd = ".bvfs_get_jobids jobid=" + m_jobids;
115 if (MergeChk->checkState() == Qt::Checked) {
119 m_console->dir_cmd(cmd, results);
121 if (results.size() < 1) {
122 FileList->clearContents();
123 FileList->setRowCount(0);
124 FileRevisions->clearContents();
125 FileRevisions->setRowCount(0);
129 m_jobids = results.at(0);
130 cmd = ".bvfs_update jobid=" + m_jobids;
131 m_console->dir_cmd(cmd, results);
133 Pmsg1(0, "jobids=%s\n", m_jobids.toLocal8Bit().constData());
135 displayFiles(m_pathid, QString(""));
136 Pmsg0(000, "update done\n");
139 extern int decode_stat(char *buf, struct stat *statp, int32_t *LinkFI);
141 void bRestore::displayFiles(int64_t pathid, QString path)
145 QStringList fieldlist;
150 Freeze frz_lst(*FileList); /* disable updating*/
151 Freeze frz_rev(*FileRevisions); /* disable updating*/
152 FileList->clearContents();
153 FileRevisions->clearContents();
154 FileRevisions->setRowCount(0);
157 arg = " pathid=" + QString().setNum(pathid);
163 m_path.remove(QRegExp("[^/]+/$"));
166 } else if (path == "/" && m_path == "") {
169 } else if (path != "/" && path != ".") {
174 arg = " path=\"" + m_path + "\"";
176 LocationEntry->setText(m_path);
178 QString q = ".bvfs_lsdir jobid=" + m_jobids + arg;
179 if (m_console->dir_cmd(q, results)) {
181 FileList->setRowCount(nb);
182 foreach (QString resultline, results) {
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(),
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
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(),
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
214 FileList->verticalHeader()->hide();
215 FileList->resizeColumnsToContents();
216 FileList->resizeRowsToContents();
217 FileList->setEditTriggers(QAbstractItemView::NoEditTriggers);
220 void bRestore::PgSeltreeWidgetClicked()
225 if (!isOnceDocked()) {
230 void bRestore::displayFileVersion(QString pathid, QString fnid,
231 QString client, QString filename)
236 Freeze frz_rev(*FileRevisions); /* disable updating*/
237 FileRevisions->clearContents();
239 QString q = ".bvfs_versions jobid=" + m_jobids +
240 " pathid=" + pathid +
244 if (VersionsChk->checkState() == Qt::Checked) {
245 q.append(" versions");
249 QStringList fieldlist;
251 if (m_console->dir_cmd(q, results)) {
252 FileRevisions->setRowCount(results.size());
253 foreach (QString resultline, results) {
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(),
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
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
276 FileRevisions->verticalHeader()->hide();
277 FileRevisions->resizeColumnsToContents();
278 FileRevisions->resizeRowsToContents();
279 FileRevisions->setEditTriggers(QAbstractItemView::NoEditTriggers);
282 void bRestore::showInfoForFile(QTableWidgetItem *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));
290 displayFileVersion(lst.at(0), lst.at(1), m_client, lst.at(5));
294 void bRestore::applyLocation()
296 displayFiles(0, LocationEntry->text());
299 void bRestore::clearVersions(QTableWidgetItem *item)
301 if (item != m_current) {
302 FileRevisions->clearContents();
303 FileRevisions->setRowCount(0);
308 void bRestore::clearRestoreList()
310 RestoreList->clearContents();
311 RestoreList->setRowCount(0);
314 void bRestore::setupPage()
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()));
330 bRestore::~bRestore()
334 void bRestoreTable::mousePressEvent(QMouseEvent *event)
336 QTableWidget::mousePressEvent(event);
338 if (event->button() == Qt::LeftButton) {
339 dragStartPosition = event->pos();
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)
349 // Look just for drag&drop
350 if (!(event->buttons() & Qt::LeftButton)) {
351 QTableWidget::mouseMoveEvent(event);
354 if ((event->pos() - dragStartPosition).manhattanLength()
355 < QApplication::startDragDistance())
357 QTableWidget::mouseMoveEvent(event);
361 QList<QTableWidgetItem *> lst = selectedItems();
362 qDebug() << this << " selectedItems: " << lst;
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
377 drag->setMimeData(mimeData);
381 // This event is called when the drag item enters in the destination area
382 void bRestoreTable::dragEnterEvent(QDragEnterEvent *event)
384 if (event->source() == this) {
388 if (event->mimeData()->hasText()) {
389 event->acceptProposedAction();
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)
399 if (event->mimeData()->hasText()) {
400 event->acceptProposedAction();
406 void bRestoreTable::dropEvent(QDropEvent *event)
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) {
419 if (fields.at(1) == "0") {
420 item.setFileType(0, "folder");
422 item.setTextFld(col++, fields.at(5)); // filename
423 decode_stat(fields.at(4).toLocal8Bit().data(),
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();