]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
Backport from BEE
[bacula/bacula] / bacula / src / qt-console / mainwin.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 many
7    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    Bacula® is a registered trademark of Kern Sibbald.
15 */
16
17 /*
18  *
19  *  Main Window control for bat (qt-console)
20  *
21  *   Kern Sibbald, January MMVII
22  *
23  */
24
25 #include "bat.h"
26 #include "version.h"
27 #include "joblist/joblist.h"
28 #include "storage/storage.h"
29 #include "fileset/fileset.h"
30 #include "label/label.h"
31 #include "run/run.h"
32 #include "pages.h"
33 #include "restore/restore.h"
34 #include "medialist/medialist.h"
35 #include "joblist/joblist.h"
36 #include "clients/clients.h"
37 #include "restore/restoretree.h"
38 #include "help/help.h"
39 #include "jobs/jobs.h"
40 #include "medialist/mediaview.h"
41 #ifdef HAVE_QWT
42 #include "jobgraphs/jobplot.h"
43 #endif
44 #include "status/dirstat.h"
45 #include "util/fmtwidgetitem.h"
46
47 /*
48  * Daemon message callback
49  */
50 void message_callback(int /* type */, char *msg)
51 {
52    QMessageBox::warning(mainWin, "Bat", msg, QMessageBox::Ok);
53 }
54
55 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
56 {
57    app->setOverrideCursor(QCursor(Qt::WaitCursor));
58    m_isClosing = false;
59    m_waitState = false;
60    m_doConnect = false;
61    m_treeStackTrap = false;
62    m_dtformat = "yyyy-MM-dd HH:mm:ss";
63    mainWin = this;
64    setupUi(this);                     /* Setup UI defined by main.ui (designer) */
65    register_message_callback(message_callback);
66    readPreferences();
67    treeWidget->clear();
68    treeWidget->setColumnCount(1);
69    treeWidget->setHeaderLabel( tr("Select Page") );
70    treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
71    tabWidget->setTabsClosable(true);  /* wait for QT 4.5 */
72    createPages();
73
74    resetFocus(); /* lineEdit->setFocus() */
75
76 #ifndef HAVE_QWT
77    actionJobPlot->setEnabled(false);
78    actionJobPlot->setVisible(false);
79 #endif
80
81    this->show();
82
83    readSettings();
84
85    foreach(Console *console, m_consoleHash) {
86       console->connect_dir();
87    }
88    /*
89     * Note, the notifier is now a global flag, although each notifier
90     *  can be individually turned on and off at a socket level.  Once
91     *  the notifier is turned off, we don't accept anything from anyone
92     *  this prevents unwanted messages from getting into the input
93     *  dialogs such as restore that read from the director and "know"
94     *  what to expect.
95     */
96    m_notify = true;
97    m_currentConsole = (Console*)getFromHash(m_firstItem);
98    QTimer::singleShot(2000, this, SLOT(popLists()));
99    if (m_miscDebug) {
100       QString directoryResourceName;
101       m_currentConsole->getDirResName(directoryResourceName);
102       Pmsg1(100, "Setting initial window to %s\n", directoryResourceName.toUtf8().data());
103    }
104    app->restoreOverrideCursor();
105 }
106
107 void MainWin::popLists()
108 {
109    foreach(Console *console, m_consoleHash) {
110       console->populateLists(true);
111    }
112    m_doConnect = true;
113    connectConsoleSignals();
114    connectSignals();
115    app->restoreOverrideCursor();
116    m_currentConsole->setCurrent();
117 }
118
119 void MainWin::createPages()
120 {
121    DIRRES *dir;
122    QTreeWidgetItem *item, *topItem;
123    m_firstItem = NULL;
124
125    LockRes();
126    foreach_res(dir, R_DIRECTOR) {
127
128       /* Create console tree stacked widget item */
129       m_currentConsole = new Console(tabWidget);
130       m_currentConsole->setDirRes(dir);
131       m_currentConsole->readSettings();
132
133       /* The top tree item representing the director */
134       topItem = new QTreeWidgetItem(treeWidget);
135       topItem->setText(0, dir->name());
136       topItem->setIcon(0, QIcon(":images/server.png"));
137       /* Set background to grey for ease of identification of inactive Director */
138       QBrush greyBrush(Qt::lightGray);
139       topItem->setBackground(0, greyBrush);
140       m_currentConsole->setDirectorTreeItem(topItem);
141       m_consoleHash.insert(topItem, m_currentConsole);
142
143       /* Create Tree Widget Item */
144       item = new QTreeWidgetItem(topItem);
145       item->setText(0, tr("Console"));
146       if (!m_firstItem){ m_firstItem = item; }
147       item->setIcon(0,QIcon(QString::fromUtf8(":images/utilities-terminal.png")));
148
149       /* insert the cosole and tree widget item into the hashes */
150       hashInsert(item, m_currentConsole);
151       m_currentConsole->dockPage();
152
153       /* Set Color of treeWidgetItem for the console
154       * It will be set to green in the console class if the connection is made.
155       */
156       QBrush redBrush(Qt::red);
157       item->setForeground(0, redBrush);
158
159       /*
160        * Create instances in alphabetic order of the rest
161        *  of the classes that will by default exist under each Director.
162        */
163       new bRestore();
164       new Clients();
165       new FileSet();
166       new Jobs();
167       createPageJobList("", "", "", "", NULL);
168 #ifdef HAVE_QWT
169       JobPlotPass pass;
170       pass.use = false;
171       if (m_openPlot)
172          new JobPlot(NULL, pass);
173 #endif
174       new MediaList();
175       new MediaView();
176       new Storage();
177 //    if (m_openBrowser) {
178 //       new restoreTree();
179 //    }
180       if (m_openDirStat) {
181          new DirStat();
182       }
183       treeWidget->expandItem(topItem);
184       tabWidget->setCurrentWidget(m_currentConsole);
185    }
186    UnlockRes();
187 }
188
189 /*
190  * create an instance of the the joblist class on the stack
191  */
192 void MainWin::createPageJobList(const QString &media, const QString &client,
193               const QString &job, const QString &fileset, QTreeWidgetItem *parentTreeWidgetItem)
194 {
195    QTreeWidgetItem *holdItem;
196
197    /* save current tree widget item in case query produces no results */
198    holdItem = treeWidget->currentItem();
199    JobList* joblist = new JobList(media, client, job, fileset, parentTreeWidgetItem);
200    /* If this is a query of jobs on a specific media */
201    if ((media != "") || (client != "") || (job != "") || (fileset != "")) {
202       joblist->setCurrent();
203       /* did query produce results, if not close window and set back to hold */
204       if (joblist->m_resultCount == 0) {
205          joblist->closeStackPage();
206          treeWidget->setCurrentItem(holdItem);
207       }
208    }
209 }
210
211 /*
212  * Handle up and down arrow keys for the command line
213  *  history.
214  */
215 void MainWin::keyPressEvent(QKeyEvent *event)
216 {
217    if (m_cmd_history.size() == 0) {
218       event->ignore();
219       return;
220    }
221    switch (event->key()) {
222    case Qt::Key_Down:
223       if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
224          event->ignore();
225          return;
226       }
227       m_cmd_last++;
228       break;
229    case Qt::Key_Up:
230       if (m_cmd_last == 0) {
231          event->ignore();
232          return;
233       }
234       if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
235          m_cmd_last = m_cmd_history.size() - 1;
236       } else {
237          m_cmd_last--;
238       }
239       break;
240    default:
241       event->ignore();
242       return;
243    }
244    lineEdit->setText(m_cmd_history[m_cmd_last]);
245 }
246
247 void MainWin::connectSignals()
248 {
249    /* Connect signals to slots */
250    connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
251    connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
252    connect(actionBat_Help, SIGNAL(triggered()), this, SLOT(help()));
253    connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
254    connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
255    connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(stackItemChanged(int)));
256    connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closePage(int)));
257    connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
258    connect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
259    connect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
260    connect(actionEstimate, SIGNAL(triggered()), this,  SLOT(estimateButtonClicked()));
261    connect(actionBrowse, SIGNAL(triggered()), this,  SLOT(browseButtonClicked()));
262    connect(actionStatusDirPage, SIGNAL(triggered()), this,  SLOT(statusPageButtonClicked()));
263 #ifdef HAVE_QWT
264    connect(actionJobPlot, SIGNAL(triggered()), this,  SLOT(jobPlotButtonClicked()));
265 #endif
266    connect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
267    connect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
268    connect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
269    connect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closeCurrentPage()));
270    connect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
271    connect(actionRepopLists, SIGNAL(triggered()), this,  SLOT(repopLists()));
272    connect(actionReloadRepop, SIGNAL(triggered()), this,  SLOT(reloadRepopLists()));
273 }
274
275 void MainWin::disconnectSignals()
276 {
277    /* Connect signals to slots */
278    disconnect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
279    disconnect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
280    disconnect(actionBat_Help, SIGNAL(triggered()), this, SLOT(help()));
281    disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
282    disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
283    disconnect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(stackItemChanged(int)));
284    disconnect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closePage(int)));
285    disconnect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
286    disconnect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
287    disconnect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
288    disconnect(actionEstimate, SIGNAL(triggered()), this,  SLOT(estimateButtonClicked()));
289    disconnect(actionBrowse, SIGNAL(triggered()), this,  SLOT(browseButtonClicked()));
290    disconnect(actionStatusDirPage, SIGNAL(triggered()), this,  SLOT(statusPageButtonClicked()));
291 #ifdef HAVE_QWT
292    disconnect(actionJobPlot, SIGNAL(triggered()), this,  SLOT(jobPlotButtonClicked()));
293 #endif
294    disconnect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
295    disconnect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
296    disconnect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
297    disconnect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closeCurrentPage()));
298    disconnect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
299    disconnect(actionRepopLists, SIGNAL(triggered()), this,  SLOT(repopLists()));
300    disconnect(actionReloadRepop, SIGNAL(triggered()), this,  SLOT(reloadRepopLists()));
301 }
302
303 /*
304  *  Enter wait state
305  */
306 void MainWin::waitEnter()
307 {
308    if (m_waitState || m_isClosing) {
309       return;
310    }
311    m_waitState = true;
312    if (mainWin->m_connDebug) Pmsg0(000, "Entering Wait State\n");
313    app->setOverrideCursor(QCursor(Qt::WaitCursor));
314    disconnectSignals();
315    disconnectConsoleSignals(m_currentConsole);
316    m_waitTreeItem = treeWidget->currentItem();
317 }
318
319 /*
320  *  Leave wait state
321  */
322 void MainWin::waitExit()
323 {
324    if (!m_waitState || m_isClosing) {
325       return;
326    }
327    if (mainWin->m_connDebug) Pmsg0(000, "Exiting Wait State\n");
328    if (m_waitTreeItem && (m_waitTreeItem != treeWidget->currentItem())) {
329       treeWidget->setCurrentItem(m_waitTreeItem);
330    }
331    if (m_doConnect) {
332       connectSignals();
333       connectConsoleSignals();
334    }
335    app->restoreOverrideCursor();
336    m_waitState = false;
337 }
338
339 void MainWin::connectConsoleSignals()
340 {
341    connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect_dir()));
342    connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
343    connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
344 }
345
346 void MainWin::disconnectConsoleSignals(Console *console)
347 {
348    disconnect(actionConnect, SIGNAL(triggered()), console, SLOT(connect_dir()));
349    disconnect(actionMessages, SIGNAL(triggered()), console, SLOT(messages()));
350    disconnect(actionSelectFont, SIGNAL(triggered()), console, SLOT(set_font()));
351 }
352
353
354 /*
355  * Two functions to respond to menu items to repop lists and execute reload and repopulate
356  * the lists for jobs, clients, filesets .. ..
357  */
358 void MainWin::repopLists()
359 {
360    m_currentConsole->populateLists(false);
361 }
362 void MainWin::reloadRepopLists()
363 {
364    QString cmd = "reload";
365    m_currentConsole->consoleCommand(cmd);
366    m_currentConsole->populateLists(false);
367 }
368
369 /*
370  * Reimplementation of QWidget closeEvent virtual function
371  */
372 void MainWin::closeEvent(QCloseEvent *event)
373 {
374    m_isClosing = true;
375    writeSettings();
376    /* Remove all groups from settings for OpenOnExit so that we can start some of the status windows */
377    foreach(Console *console, m_consoleHash){
378       QSettings settings(console->m_dir->name(), "bat");
379       settings.beginGroup("OpenOnExit");
380       settings.remove("");
381       settings.endGroup();
382    }
383    /* close all non console pages, this will call settings in destructors */
384    while (m_consoleHash.count() < m_pagehash.count()) {
385       foreach(Pages *page, m_pagehash) {
386          if (page !=  page->console()) {
387             QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(page);
388             if (pageSelectorTreeWidgetItem->childCount() == 0) {
389                page->console()->setCurrent();
390                page->closeStackPage();
391             }
392          }
393       }
394    }
395    foreach(Console *console, m_consoleHash){
396       console->writeSettings();
397       console->terminate();
398       console->closeStackPage();
399    }
400    event->accept();
401 }
402
403 void MainWin::writeSettings()
404 {
405    QSettings settings("bacula.org", "bat");
406
407    settings.beginGroup("MainWin");
408    settings.setValue("winSize", size());
409    settings.setValue("winPos", pos());
410    settings.setValue("state", saveState());
411    settings.endGroup();
412
413 }
414
415 void MainWin::readSettings()
416 {
417    QSettings settings("bacula.org", "bat");
418
419    settings.beginGroup("MainWin");
420    resize(settings.value("winSize", QSize(1041, 801)).toSize());
421    move(settings.value("winPos", QPoint(200, 150)).toPoint());
422    restoreState(settings.value("state").toByteArray());
423    settings.endGroup();
424 }
425
426 /*
427  * This subroutine is called with an item in the Page Selection window
428  *   is clicked
429  */
430 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
431 {
432    /* Is this a page that has been inserted into the hash  */
433    Pages* page = getFromHash(item);
434    if (page) {
435       int stackindex = tabWidget->indexOf(page);
436
437       if (stackindex >= 0) {
438          tabWidget->setCurrentWidget(page);
439       }
440       page->dockPage();
441       /* run the virtual function in case this class overrides it */
442       page->PgSeltreeWidgetClicked();
443    } else {
444       Dmsg0(000, "Page not in hash");
445    }
446 }
447
448 /*
449  * Called with a change of the highlighed tree widget item in the page selector.
450  */
451 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
452 {
453    if (m_isClosing) return; /* if closing the application, do nothing here */
454
455    Pages *previousPage, *nextPage;
456    Console *previousConsole = NULL;
457    Console *nextConsole;
458
459    /* remove all actions before adding actions appropriate for new page */
460    foreach(QAction* pageAction, treeWidget->actions()) {
461       treeWidget->removeAction(pageAction);
462    }
463
464    /* first determine the next item */
465
466    /* knowing the treeWidgetItem, get the page from the hash */
467    nextPage = getFromHash(currentitem);
468    nextConsole = m_consoleHash.value(currentitem);
469    /* Is this a page that has been inserted into the hash  */
470    if (nextPage) {
471       nextConsole = nextPage->console();
472       /* then is it a treeWidgetItem representing a director */
473    } else if (nextConsole) {
474       /* let the next page BE the console */
475       nextPage = nextConsole;
476    } else {
477       /* Should never get here */
478       nextPage = NULL;
479       nextConsole = NULL;
480    }
481
482    /* The Previous item */
483
484    /* this condition prevents a segfault.  The first time there is no previousitem*/
485    if (previousitem) {
486       if (m_treeStackTrap == false) { /* keep track of previous items for going Back */
487          m_treeWidgetStack.append(previousitem);
488       }
489       /* knowing the treeWidgetItem, get the page from the hash */
490       previousPage = getFromHash(previousitem);
491       previousConsole = m_consoleHash.value(previousitem);
492       if (previousPage) {
493          previousConsole = previousPage->console();
494       } else if (previousConsole) {
495          previousPage = previousConsole;
496       }
497       if ((previousPage) || (previousConsole)) {
498          if (nextConsole != previousConsole) {
499             /* remove connections to the current console */
500             disconnectConsoleSignals(previousConsole);
501             QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
502             QBrush greyBrush(Qt::lightGray);
503             dirItem->setBackground(0, greyBrush);
504          }
505       }
506    }
507
508    /* process the current (next) item */
509
510    if ((nextPage) || (nextConsole)) {
511       if (nextConsole != previousConsole) {
512          /* make connections to the current console */
513          m_currentConsole = nextConsole;
514          connectConsoleSignals();
515          setMessageIcon();
516          /* Set director's tree widget background to magenta for ease of identification */
517          QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
518          QBrush magentaBrush(Qt::magenta);
519          dirItem->setBackground(0, magentaBrush);
520       }
521       /* set the value for the currently active console */
522       int stackindex = tabWidget->indexOf(nextPage);
523       nextPage->firstUseDock();
524
525       /* Is this page currently on the stack or is it undocked */
526       if (stackindex >= 0) {
527          /* put this page on the top of the stack */
528          tabWidget->setCurrentIndex(stackindex);
529       } else {
530          /* it is undocked, raise it to the front */
531          nextPage->raise();
532       }
533       /* for the page selectors menu action to dock or undock, set the text */
534       nextPage->setContextMenuDockText();
535
536       treeWidget->addAction(actionToggleDock);
537       /* if this page is closeable, and it has no childern, then add that action */
538       if ((nextPage->isCloseable()) && (currentitem->child(0) == NULL))
539          treeWidget->addAction(actionClosePage);
540
541       /* Add the actions to the Page Selectors tree widget that are part of the
542        * current items list of desired actions regardless of whether on top of stack*/
543       treeWidget->addActions(nextPage->m_contextActions);
544    }
545 }
546
547 void MainWin::labelButtonClicked()
548 {
549    new labelPage();
550 }
551
552 void MainWin::runButtonClicked()
553 {
554    new runPage("");
555 }
556
557 void MainWin::estimateButtonClicked()
558 {
559    new estimatePage();
560 }
561
562 void MainWin::browseButtonClicked()
563 {
564 //   new restoreTree();
565 }
566
567 void MainWin::statusPageButtonClicked()
568 {
569    /* if one exists, then just set it current */
570    bool found = false;
571    foreach(Pages *page, m_pagehash) {
572       if (m_currentConsole == page->console()) {
573          if (page->name() == tr("Director Status")) {
574             found = true;
575             page->setCurrent();
576          }
577       }
578    }
579    if (!found) {
580       new DirStat();
581    }
582 }
583
584 void MainWin::restoreButtonClicked()
585 {
586    new prerestorePage();
587    if (mainWin->m_miscDebug) Pmsg0(000, "in restoreButtonClicked after prerestorePage\n");
588 }
589
590 void MainWin::jobPlotButtonClicked()
591 {
592 #ifdef HAVE_QWT
593    JobPlotPass pass;
594    pass.use = false;
595    new JobPlot(NULL, pass);
596 #endif
597 }
598
599 /*
600  * The user just finished typing a line in the command line edit box
601  */
602 void MainWin::input_line()
603 {
604    int conn;
605    QString cmdStr = lineEdit->text();    /* Get the text */
606    lineEdit->clear();                    /* clear the lineEdit box */
607    if (m_currentConsole->is_connected()) {
608       if (m_currentConsole->findDirComm(conn)) {
609          m_currentConsole->consoleCommand(cmdStr, conn);
610       } else {
611          /* Use consoleCommand to allow typing anything */
612          m_currentConsole->consoleCommand(cmdStr);
613       }
614    } else {
615       set_status(tr("Director not connected. Click on connect button."));
616    }
617    m_cmd_history.append(cmdStr);
618    m_cmd_last = -1;
619    if (treeWidget->currentItem() != getFromHash(m_currentConsole))
620       m_currentConsole->setCurrent();
621 }
622
623
624 void MainWin::about()
625 {
626    QMessageBox::about(this, tr("About bat"),
627       tr("<br><h2>Bat %1 (%2), by Dirk H Bartley and Kern Sibbald</h2>"
628          "<p>Copyright &copy; 2007-%3 Free Software Foundation Europe e.V."
629          "<p>Improved by Bacula Systems SA."
630          "<p>The <b>bat</b> is an administrative console"
631          " interface to the Director.").arg(VERSION).arg(BDATE).arg(BYEAR));
632 }
633
634 void MainWin::help()
635 {
636    Help::displayFile("index.html");
637 }
638
639 void MainWin::set_statusf(const char *fmt, ...)
640 {
641    va_list arg_ptr;
642    char buf[1000];
643    va_start(arg_ptr, fmt);
644    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
645    va_end(arg_ptr);
646    set_status(buf);
647 }
648
649 void MainWin::set_status_ready()
650 {
651    set_status(tr(" Ready"));
652 }
653
654 void MainWin::set_status(const QString &str)
655 {
656    statusBar()->showMessage(str);
657 }
658
659 void MainWin::set_status(const char *buf)
660 {
661    statusBar()->showMessage(buf);
662 }
663
664 /*
665  * Function to respond to the button bar button to undock
666  */
667 void MainWin::undockWindowButton()
668 {
669    Pages* page = (Pages*)tabWidget->currentWidget();
670    if (page) {
671       page->togglePageDocking();
672    }
673 }
674
675 /*
676  * Function to respond to action on page selector context menu to toggle the
677  * dock status of the window associated with the page selectors current
678  * tree widget item.
679  */
680 void MainWin::toggleDockContextWindow()
681 {
682    QTreeWidgetItem *currentitem = treeWidget->currentItem();
683
684    /* Is this a page that has been inserted into the hash  */
685    if (getFromHash(currentitem)) {
686       Pages* page = getFromHash(currentitem);
687       if (page) {
688          page->togglePageDocking();
689       }
690    }
691 }
692
693 /*
694  * This function is called when the stack item is changed.  Call
695  * the virtual function here.  Avoids a window being undocked leaving
696  * a window at the top of the stack unpopulated.
697  */
698 void MainWin::stackItemChanged(int)
699 {
700    if (m_isClosing) return; /* if closing the application, do nothing here */
701    Pages* page = (Pages*)tabWidget->currentWidget();
702    /* run the virtual function in case this class overrides it */
703    if (page) {
704       page->currentStackItem();
705    }
706    if (!m_waitState) {
707       disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
708       disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
709       treeWidget->setCurrentItem(getFromHash(page));
710       connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
711       connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
712    }
713 }
714
715 /*
716  * Function to simplify insertion of QTreeWidgetItem <-> Page association
717  * into a double direction hash.
718  */
719 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
720 {
721    m_pagehash.insert(item, page);
722    m_widgethash.insert(page, item);
723 }
724
725 /*
726  * Function to simplify removal of QTreeWidgetItem <-> Page association
727  * into a double direction hash.
728  */
729 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
730 {
731    /* I had all sorts of return status checking code here.  Do we have a log
732     * level capability in bat.  I would have left it in but it used printf's
733     * and it should really be some kind of log level facility ???
734     * ******FIXME********/
735    m_pagehash.remove(item);
736    m_widgethash.remove(page);
737 }
738
739 /*
740  * Function to retrieve a Page* when the item in the page selector's tree is
741  * known.
742  */
743 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
744 {
745    return m_pagehash.value(item);
746 }
747
748 /*
749  * Function to retrieve the page selectors tree widget item when the page is
750  * known.
751  */
752 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
753 {
754    return m_widgethash.value(page);
755 }
756
757 void MainWin::closeCurrentPage()
758 {
759    closePage(-1);
760 }
761
762 /*
763  * Function to respond to action on page selector context menu to close the
764  * current window.
765  */
766 void MainWin::closePage(int item)
767 {
768    QTreeWidgetItem *currentitem;
769    Pages *page = NULL;
770
771    if (item >= 0) {
772      page = (Pages *)tabWidget->widget(item);
773    } else {
774       currentitem = treeWidget->currentItem();
775       /* Is this a page that has been inserted into the hash  */
776       if (getFromHash(currentitem)) {
777          page = getFromHash(currentitem);
778       }
779    }
780
781    if (page) {
782       if (page->isCloseable()) {
783          page->closeStackPage();
784       } else {
785          page->hidePage();
786       }
787    }
788 }
789
790 /* Quick function to return the current console */
791 Console *MainWin::currentConsole()
792 {
793    return m_currentConsole;
794 }
795
796 /* Quick function to return the tree item for the director */
797 QTreeWidgetItem *MainWin::currentTopItem()
798 {
799    return m_currentConsole->directorTreeItem();
800 }
801
802 /* Preferences menu item clicked */
803 void MainWin::setPreferences()
804 {
805    prefsDialog prefs;
806    prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
807    prefs.connDebug->setCheckState(m_connDebug ? Qt::Checked : Qt::Unchecked);
808    prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
809    prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
810    prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
811    prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
812    prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
813    prefs.recordSpinBox->setValue(m_recordLimitVal);
814    prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
815    prefs.daysSpinBox->setValue(m_daysLimitVal);
816    prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
817    prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
818    prefs.executeLongCheckBox->setCheckState(m_longList ? Qt::Checked : Qt::Unchecked);
819    prefs.rtPopDirCheckBox->setCheckState(m_rtPopDirDebug ? Qt::Checked : Qt::Unchecked);
820    prefs.rtDirCurICCheckBox->setCheckState(m_rtDirCurICDebug ? Qt::Checked : Qt::Unchecked);
821    prefs.rtDirICCheckBox->setCheckState(m_rtDirICDebug ? Qt::Checked : Qt::Unchecked);
822    prefs.rtFileTabICCheckBox->setCheckState(m_rtFileTabICDebug ? Qt::Checked : Qt::Unchecked);
823    prefs.rtVerTabICCheckBox->setCheckState(m_rtVerTabICDebug ? Qt::Checked : Qt::Unchecked);
824    prefs.rtUpdateFTCheckBox->setCheckState(m_rtUpdateFTDebug ? Qt::Checked : Qt::Unchecked);
825    prefs.rtUpdateVTCheckBox->setCheckState(m_rtUpdateVTDebug ? Qt::Checked : Qt::Unchecked);
826    prefs.rtChecksCheckBox->setCheckState(m_rtChecksDebug ? Qt::Checked : Qt::Unchecked);
827    prefs.rtIconStateCheckBox->setCheckState(m_rtIconStateDebug ? Qt::Checked : Qt::Unchecked);
828    prefs.rtRestore1CheckBox->setCheckState(m_rtRestore1Debug ? Qt::Checked : Qt::Unchecked);
829    prefs.rtRestore2CheckBox->setCheckState(m_rtRestore2Debug ? Qt::Checked : Qt::Unchecked);
830    prefs.rtRestore3CheckBox->setCheckState(m_rtRestore3Debug ? Qt::Checked : Qt::Unchecked);
831    switch (ItemFormatterBase::getBytesConversion()) {
832    case ItemFormatterBase::BYTES_CONVERSION_NONE:
833       prefs.radioConvertOff->setChecked(Qt::Checked);
834       break;
835    case ItemFormatterBase::BYTES_CONVERSION_IEC:
836       prefs.radioConvertIEC->setChecked(Qt::Checked);
837       break;
838    default:
839       prefs.radioConvertStandard->setChecked(Qt::Checked);
840       break;
841    }
842    prefs.openPlotCheckBox->setCheckState(m_openPlot ? Qt::Checked : Qt::Unchecked);
843 #ifndef HAVE_QWT
844    prefs.openPlotCheckBox->setVisible(false);
845 #endif
846    prefs.openBrowserCheckBox->setCheckState(m_openBrowser ? Qt::Checked : Qt::Unchecked);
847    prefs.openDirStatCheckBox->setCheckState(m_openDirStat ? Qt::Checked : Qt::Unchecked);
848    prefs.exec();
849 }
850
851 /* Preferences dialog */
852 prefsDialog::prefsDialog() : QDialog()
853 {
854    setupUi(this);
855 }
856
857 void prefsDialog::accept()
858 {
859    this->hide();
860    mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
861    mainWin->m_connDebug = this->connDebug->checkState() == Qt::Checked;
862    mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
863    mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
864    mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
865    mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
866    mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
867    mainWin->m_recordLimitVal = this->recordSpinBox->value();
868    mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
869    mainWin->m_daysLimitVal = this->daysSpinBox->value();
870    mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
871    mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
872    mainWin->m_longList = this->executeLongCheckBox->checkState() == Qt::Checked;
873
874    mainWin->m_rtPopDirDebug = this->rtPopDirCheckBox->checkState() == Qt::Checked;
875    mainWin->m_rtDirCurICDebug = this->rtDirCurICCheckBox->checkState() == Qt::Checked;
876    mainWin->m_rtDirICDebug = this->rtDirICCheckBox->checkState() == Qt::Checked;
877    mainWin->m_rtFileTabICDebug = this->rtFileTabICCheckBox->checkState() == Qt::Checked;
878    mainWin->m_rtVerTabICDebug = this->rtVerTabICCheckBox->checkState() == Qt::Checked;
879    mainWin->m_rtUpdateFTDebug = this->rtUpdateFTCheckBox->checkState() == Qt::Checked;
880    mainWin->m_rtUpdateVTDebug = this->rtUpdateVTCheckBox->checkState() == Qt::Checked;
881    mainWin->m_rtChecksDebug = this->rtChecksCheckBox->checkState() == Qt::Checked;
882    mainWin->m_rtIconStateDebug = this->rtIconStateCheckBox->checkState() == Qt::Checked;
883    mainWin->m_rtRestore1Debug = this->rtRestore1CheckBox->checkState() == Qt::Checked;
884    mainWin->m_rtRestore2Debug = this->rtRestore2CheckBox->checkState() == Qt::Checked;
885    mainWin->m_rtRestore3Debug = this->rtRestore3CheckBox->checkState() == Qt::Checked;
886    if (this->radioConvertOff->isChecked()) {
887       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_NONE);
888    } else if (this->radioConvertIEC->isChecked()){
889       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_IEC);
890    } else {
891       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_SI);
892    }
893    mainWin->m_openPlot = this->openPlotCheckBox->checkState() == Qt::Checked;
894    mainWin->m_openBrowser = this->openBrowserCheckBox->checkState() == Qt::Checked;
895    mainWin->m_openDirStat = this->openDirStatCheckBox->checkState() == Qt::Checked;
896
897    QSettings settings("www.bacula.org", "bat");
898    settings.beginGroup("Debug");
899    settings.setValue("commDebug", mainWin->m_commDebug);
900    settings.setValue("connDebug", mainWin->m_connDebug);
901    settings.setValue("displayAll", mainWin->m_displayAll);
902    settings.setValue("sqlDebug", mainWin->m_sqlDebug);
903    settings.setValue("commandDebug", mainWin->m_commandDebug);
904    settings.setValue("miscDebug", mainWin->m_miscDebug);
905    settings.endGroup();
906    settings.beginGroup("JobList");
907    settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
908    settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
909    settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
910    settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
911    settings.endGroup();
912    settings.beginGroup("Timers");
913    settings.setValue("checkMessages", mainWin->m_checkMessages);
914    settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
915    settings.endGroup();
916    settings.beginGroup("Misc");
917    settings.setValue("longList", mainWin->m_longList);
918    settings.setValue("byteConvert", ItemFormatterBase::getBytesConversion());
919    settings.setValue("openplot", mainWin->m_openPlot);
920    settings.setValue("openbrowser", mainWin->m_openBrowser);
921    settings.setValue("opendirstat", mainWin->m_openDirStat);
922    settings.endGroup();
923    settings.beginGroup("RestoreTree");
924    settings.setValue("rtPopDirDebug", mainWin->m_rtPopDirDebug);
925    settings.setValue("rtDirCurICDebug", mainWin->m_rtDirCurICDebug);
926    settings.setValue("rtDirCurICRetDebug", mainWin->m_rtDirICDebug);
927    settings.setValue("rtFileTabICDebug", mainWin->m_rtFileTabICDebug);
928    settings.setValue("rtVerTabICDebug", mainWin->m_rtVerTabICDebug);
929    settings.setValue("rtUpdateFTDebug", mainWin->m_rtUpdateFTDebug);
930    settings.setValue("rtUpdateVTDebug", mainWin->m_rtUpdateVTDebug);
931    settings.setValue("rtChecksDebug", mainWin->m_rtChecksDebug);
932    settings.setValue("rtIconStateDebug", mainWin->m_rtIconStateDebug);
933    settings.setValue("rtRestore1Debug", mainWin->m_rtRestore1Debug);
934    settings.setValue("rtRestore2Debug", mainWin->m_rtRestore2Debug);
935    settings.setValue("rtRestore3Debug", mainWin->m_rtRestore3Debug);
936    settings.endGroup();
937 }
938
939 void prefsDialog::reject()
940 {
941    this->hide();
942    mainWin->set_status(tr("Canceled"));
943 }
944
945 /* read preferences for the prefences dialog box */
946 void MainWin::readPreferences()
947 {
948    QSettings settings("www.bacula.org", "bat");
949    settings.beginGroup("Debug");
950    m_commDebug = settings.value("commDebug", false).toBool();
951    m_connDebug = settings.value("connDebug", false).toBool();
952    m_displayAll = settings.value("displayAll", false).toBool();
953    m_sqlDebug = settings.value("sqlDebug", false).toBool();
954    m_commandDebug = settings.value("commandDebug", false).toBool();
955    m_miscDebug = settings.value("miscDebug", false).toBool();
956    settings.endGroup();
957    settings.beginGroup("JobList");
958    m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
959    m_recordLimitVal = settings.value("recordLimitVal", 50).toInt();
960    m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
961    m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
962    settings.endGroup();
963    settings.beginGroup("Timers");
964    m_checkMessages = settings.value("checkMessages", false).toBool();
965    m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();
966    settings.endGroup();
967    settings.beginGroup("Misc");
968    m_longList = settings.value("longList", false).toBool();
969    ItemFormatterBase::setBytesConversion(
970          (ItemFormatterBase::BYTES_CONVERSION) settings.value("byteConvert",
971          ItemFormatterBase::BYTES_CONVERSION_IEC).toInt());
972    m_openPlot = settings.value("openplot", false).toBool();
973    m_openBrowser = settings.value("openbrowser", false).toBool();
974    m_openDirStat = settings.value("opendirstat", false).toBool();
975    settings.endGroup();
976    settings.beginGroup("RestoreTree");
977    m_rtPopDirDebug = settings.value("rtPopDirDebug", false).toBool();
978    m_rtDirCurICDebug = settings.value("rtDirCurICDebug", false).toBool();
979    m_rtDirICDebug = settings.value("rtDirCurICRetDebug", false).toBool();
980    m_rtFileTabICDebug = settings.value("rtFileTabICDebug", false).toBool();
981    m_rtVerTabICDebug = settings.value("rtVerTabICDebug", false).toBool();
982    m_rtUpdateFTDebug = settings.value("rtUpdateFTDebug", false).toBool();
983    m_rtUpdateVTDebug = settings.value("rtUpdateVTDebug", false).toBool();
984    m_rtChecksDebug = settings.value("rtChecksDebug", false).toBool();
985    m_rtIconStateDebug = settings.value("rtIconStateDebug", false).toBool();
986    m_rtRestore1Debug = settings.value("rtRestore1Debug", false).toBool();
987    m_rtRestore2Debug = settings.value("rtRestore2Debug", false).toBool();
988    m_rtRestore3Debug = settings.value("rtRestore3Debug", false).toBool();
989    settings.endGroup();
990 }
991
992 void MainWin::setMessageIcon()
993 {
994    if (m_currentConsole->is_messagesPending())
995       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-pending.png")));
996    else
997       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-new.png")));
998 }
999
1000 void MainWin::goToPreviousPage()
1001 {
1002    m_treeStackTrap = true;
1003    bool done = false;
1004    while (!done) {
1005       /* If stack list is emtpty, then done */
1006       if (m_treeWidgetStack.isEmpty()) {
1007          done = true;
1008       } else {
1009          QTreeWidgetItem* testItem = m_treeWidgetStack.takeLast();
1010          QTreeWidgetItemIterator it(treeWidget);
1011          /* lets avoid a segfault by setting an item current that no longer exists */
1012          while (*it) {
1013             if (*it == testItem) {
1014                if (testItem != treeWidget->currentItem()) {
1015                   treeWidget->setCurrentItem(testItem);
1016                   done = true;
1017                }
1018                break;
1019             }
1020             ++it;
1021          }
1022       }
1023    }
1024    m_treeStackTrap = false;
1025 }