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