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