]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
Fix another bat seg fault
[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
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28
29 /*
30  *
31  *  Main Window control for bat (qt-console)
32  *
33  *   Kern Sibbald, January MMVII
34  *
35  */ 
36
37 #include "bat.h"
38 #include "version.h"
39 #include "joblist/joblist.h"
40 #include "storage/storage.h"
41 #include "fileset/fileset.h"
42 #include "label/label.h"
43 #include "run/run.h"
44 #include "pages.h"
45 #include "restore/restore.h"
46 #include "medialist/medialist.h"
47 #include "joblist/joblist.h"
48 #include "clients/clients.h"
49 #include "restore/restoretree.h"
50 #include "help/help.h"
51 #include "jobs/jobs.h"
52 #include "medialist/mediaview.h"
53 #ifdef HAVE_QWT
54 #include "jobgraphs/jobplot.h"
55 #endif
56 #include "status/dirstat.h"
57 #include "util/fmtwidgetitem.h"
58
59 /* 
60  * Daemon message callback
61  */
62 void message_callback(int /* type */, char *msg)
63 {
64    QMessageBox::warning(mainWin, "Bat", msg, QMessageBox::Ok);
65 }
66
67 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
68 {
69    app->setOverrideCursor(QCursor(Qt::WaitCursor));
70    m_isClosing = false;
71    m_waitState = false;
72    m_doConnect = false;
73    m_treeStackTrap = false;
74    m_dtformat = "yyyy-MM-dd HH:mm:ss";
75    mainWin = this;
76    setupUi(this);                     /* Setup UI defined by main.ui (designer) */
77    register_message_callback(message_callback);
78    readPreferences();
79    treeWidget->clear();
80    treeWidget->setColumnCount(1);
81    treeWidget->setHeaderLabel( tr("Select Page") );
82    treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
83    // tabWidget->setTabsClosable(true);  /* wait for QT 4.5 */
84    createPages();
85
86    resetFocus(); /* lineEdit->setFocus() */
87
88 #ifndef HAVE_QWT
89    actionJobPlot->setEnabled(false);
90    actionJobPlot->setVisible(false);
91 #endif
92
93    this->show();
94
95    readSettings();
96
97    foreach(Console *console, m_consoleHash) {
98       console->connect_dir();
99    }
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(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
260    connect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
261    connect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
262    connect(actionEstimate, SIGNAL(triggered()), this,  SLOT(estimateButtonClicked()));
263    connect(actionBrowse, SIGNAL(triggered()), this,  SLOT(browseButtonClicked()));
264    connect(actionStatusDirPage, SIGNAL(triggered()), this,  SLOT(statusPageButtonClicked()));
265 #ifdef HAVE_QWT
266    connect(actionJobPlot, SIGNAL(triggered()), this,  SLOT(jobPlotButtonClicked()));
267 #endif
268    connect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
269    connect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
270    connect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
271    connect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closePage()));
272    connect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
273    connect(actionRepopLists, SIGNAL(triggered()), this,  SLOT(repopLists()));
274    connect(actionReloadRepop, SIGNAL(triggered()), this,  SLOT(reloadRepopLists()));
275 }
276
277 void MainWin::disconnectSignals()
278 {
279    /* Connect signals to slots */
280    disconnect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
281    disconnect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
282    disconnect(actionBat_Help, SIGNAL(triggered()), this, SLOT(help()));
283    disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
284    disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
285    disconnect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(stackItemChanged(int)));
286    disconnect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
287    disconnect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
288    disconnect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
289    disconnect(actionEstimate, SIGNAL(triggered()), this,  SLOT(estimateButtonClicked()));
290    disconnect(actionBrowse, SIGNAL(triggered()), this,  SLOT(browseButtonClicked()));
291    disconnect(actionStatusDirPage, SIGNAL(triggered()), this,  SLOT(statusPageButtonClicked()));
292 #ifdef HAVE_QWT
293    disconnect(actionJobPlot, SIGNAL(triggered()), this,  SLOT(jobPlotButtonClicked()));
294 #endif
295    disconnect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
296    disconnect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
297    disconnect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
298    disconnect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closePage()));
299    disconnect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
300    disconnect(actionRepopLists, SIGNAL(triggered()), this,  SLOT(repopLists()));
301    disconnect(actionReloadRepop, SIGNAL(triggered()), this,  SLOT(reloadRepopLists()));
302 }
303
304 /*
305  *  Enter wait state
306  */
307 void MainWin::waitEnter()
308 {
309    if (m_waitState){ 
310       if (mainWin->m_connDebug)
311          Pmsg0(000, "Should Never Get Here DANGER DANGER, for now I'll return\n");
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    m_waitState = false;
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 }
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    if (getFromHash(item)) {
437       Pages* page = getFromHash(item);
438       int stackindex=tabWidget->indexOf(page);
439
440       if (stackindex >= 0) {
441          tabWidget->setCurrentWidget(page);
442       }
443       /* run the virtual function in case this class overrides it */
444       page->PgSeltreeWidgetClicked();
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>The <b>bat</b> is an administrative console"
630          " interface to the Director.").arg(VERSION).arg(BDATE).arg(BYEAR));
631 }
632
633 void MainWin::help()
634 {
635    Help::displayFile("index.html");
636 }
637
638 void MainWin::set_statusf(const char *fmt, ...)
639 {
640    va_list arg_ptr;
641    char buf[1000];
642    int len;
643    va_start(arg_ptr, fmt);
644    len = 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    page->togglePageDocking();
671 }
672
673 /*
674  * Function to respond to action on page selector context menu to toggle the 
675  * dock status of the window associated with the page selectors current
676  * tree widget item.
677  */
678 void MainWin::toggleDockContextWindow()
679 {
680    QTreeWidgetItem *currentitem = treeWidget->currentItem();
681    
682    /* Is this a page that has been inserted into the hash  */
683    if (getFromHash(currentitem)) {
684       Pages* page = getFromHash(currentitem);
685       page->togglePageDocking();
686    }
687 }
688
689 /*
690  * This function is called when the stack item is changed.  Call
691  * the virtual function here.  Avoids a window being undocked leaving
692  * a window at the top of the stack unpopulated.
693  */
694 void MainWin::stackItemChanged(int)
695 {
696    if (m_isClosing) return; /* if closing the application, do nothing here */
697    Pages* page = (Pages*)tabWidget->currentWidget();
698    /* run the virtual function in case this class overrides it */
699    page->currentStackItem();
700    if (!m_waitState) {
701       disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
702       disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
703       treeWidget->setCurrentItem(getFromHash(page));
704       connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
705       connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
706    }
707 }
708
709 /*
710  * Function to simplify insertion of QTreeWidgetItem <-> Page association
711  * into a double direction hash.
712  */
713 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
714 {
715    m_pagehash.insert(item, page);
716    m_widgethash.insert(page, item);
717 }
718
719 /*
720  * Function to simplify removal of QTreeWidgetItem <-> Page association
721  * into a double direction hash.
722  */
723 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
724 {
725    /* I had all sorts of return status checking code here.  Do we have a log
726     * level capability in bat.  I would have left it in but it used printf's
727     * and it should really be some kind of log level facility ???
728     * ******FIXME********/
729    m_pagehash.remove(item);
730    m_widgethash.remove(page);
731 }
732
733 /*
734  * Function to retrieve a Page* when the item in the page selector's tree is
735  * known.
736  */
737 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
738 {
739    return m_pagehash.value(item);
740 }
741
742 /*
743  * Function to retrieve the page selectors tree widget item when the page is
744  * known.
745  */
746 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
747 {
748    return m_widgethash.value(page);
749 }
750
751 /*
752  * Function to respond to action on page selector context menu to close the
753  * current window.
754  */
755 void MainWin::closePage()
756 {
757    QTreeWidgetItem *currentitem = treeWidget->currentItem();
758    
759    /* Is this a page that has been inserted into the hash  */
760    if (getFromHash(currentitem)) {
761       Pages* page = getFromHash(currentitem);
762       if (page->isCloseable()) {
763          page->closeStackPage();
764       }
765    }
766 }
767
768 /* Quick function to return the current console */
769 Console *MainWin::currentConsole()
770 {
771    return m_currentConsole;
772 }
773
774 /* Quick function to return the tree item for the director */
775 QTreeWidgetItem *MainWin::currentTopItem()
776 {
777    return m_currentConsole->directorTreeItem();
778 }
779
780 /* Preferences menu item clicked */
781 void MainWin::setPreferences()
782 {
783    prefsDialog prefs;
784    prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
785    prefs.connDebug->setCheckState(m_connDebug ? Qt::Checked : Qt::Unchecked);
786    prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
787    prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
788    prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
789    prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
790    prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
791    prefs.recordSpinBox->setValue(m_recordLimitVal);
792    prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
793    prefs.daysSpinBox->setValue(m_daysLimitVal);
794    prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
795    prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
796    prefs.executeLongCheckBox->setCheckState(m_longList ? Qt::Checked : Qt::Unchecked);
797    prefs.rtPopDirCheckBox->setCheckState(m_rtPopDirDebug ? Qt::Checked : Qt::Unchecked);
798    prefs.rtDirCurICCheckBox->setCheckState(m_rtDirCurICDebug ? Qt::Checked : Qt::Unchecked);
799    prefs.rtDirICCheckBox->setCheckState(m_rtDirICDebug ? Qt::Checked : Qt::Unchecked);
800    prefs.rtFileTabICCheckBox->setCheckState(m_rtFileTabICDebug ? Qt::Checked : Qt::Unchecked);
801    prefs.rtVerTabICCheckBox->setCheckState(m_rtVerTabICDebug ? Qt::Checked : Qt::Unchecked);
802    prefs.rtUpdateFTCheckBox->setCheckState(m_rtUpdateFTDebug ? Qt::Checked : Qt::Unchecked);
803    prefs.rtUpdateVTCheckBox->setCheckState(m_rtUpdateVTDebug ? Qt::Checked : Qt::Unchecked);
804    prefs.rtChecksCheckBox->setCheckState(m_rtChecksDebug ? Qt::Checked : Qt::Unchecked);
805    prefs.rtIconStateCheckBox->setCheckState(m_rtIconStateDebug ? Qt::Checked : Qt::Unchecked);
806    prefs.rtRestore1CheckBox->setCheckState(m_rtRestore1Debug ? Qt::Checked : Qt::Unchecked);
807    prefs.rtRestore2CheckBox->setCheckState(m_rtRestore2Debug ? Qt::Checked : Qt::Unchecked);
808    prefs.rtRestore3CheckBox->setCheckState(m_rtRestore3Debug ? Qt::Checked : Qt::Unchecked);
809    switch (ItemFormatterBase::getBytesConversion()) {
810    case ItemFormatterBase::BYTES_CONVERSION_NONE:
811       prefs.radioConvertOff->setChecked(Qt::Checked);
812       break;
813    case ItemFormatterBase::BYTES_CONVERSION_IEC:
814       prefs.radioConvertIEC->setChecked(Qt::Checked);
815       break;
816    default:
817       prefs.radioConvertStandard->setChecked(Qt::Checked);
818       break;
819    }
820    prefs.openPlotCheckBox->setCheckState(m_openPlot ? Qt::Checked : Qt::Unchecked);
821 #ifndef HAVE_QWT
822    prefs.openPlotCheckBox->setVisible(false);
823 #endif
824    prefs.openBrowserCheckBox->setCheckState(m_openBrowser ? Qt::Checked : Qt::Unchecked);
825    prefs.openDirStatCheckBox->setCheckState(m_openDirStat ? Qt::Checked : Qt::Unchecked);
826    prefs.exec();
827 }
828
829 /* Preferences dialog */
830 prefsDialog::prefsDialog()
831 {
832    setupUi(this);
833 }
834
835 void prefsDialog::accept()
836 {
837    this->hide();
838    mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
839    mainWin->m_connDebug = this->connDebug->checkState() == Qt::Checked;
840    mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
841    mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
842    mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
843    mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
844    mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
845    mainWin->m_recordLimitVal = this->recordSpinBox->value();
846    mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
847    mainWin->m_daysLimitVal = this->daysSpinBox->value();
848    mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
849    mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
850    mainWin->m_longList = this->executeLongCheckBox->checkState() == Qt::Checked;
851
852    mainWin->m_rtPopDirDebug = this->rtPopDirCheckBox->checkState() == Qt::Checked;
853    mainWin->m_rtDirCurICDebug = this->rtDirCurICCheckBox->checkState() == Qt::Checked;
854    mainWin->m_rtDirICDebug = this->rtDirICCheckBox->checkState() == Qt::Checked;
855    mainWin->m_rtFileTabICDebug = this->rtFileTabICCheckBox->checkState() == Qt::Checked;
856    mainWin->m_rtVerTabICDebug = this->rtVerTabICCheckBox->checkState() == Qt::Checked;
857    mainWin->m_rtUpdateFTDebug = this->rtUpdateFTCheckBox->checkState() == Qt::Checked;
858    mainWin->m_rtUpdateVTDebug = this->rtUpdateVTCheckBox->checkState() == Qt::Checked;
859    mainWin->m_rtChecksDebug = this->rtChecksCheckBox->checkState() == Qt::Checked;
860    mainWin->m_rtIconStateDebug = this->rtIconStateCheckBox->checkState() == Qt::Checked;
861    mainWin->m_rtRestore1Debug = this->rtRestore1CheckBox->checkState() == Qt::Checked;
862    mainWin->m_rtRestore2Debug = this->rtRestore2CheckBox->checkState() == Qt::Checked;
863    mainWin->m_rtRestore3Debug = this->rtRestore3CheckBox->checkState() == Qt::Checked;
864    if (this->radioConvertOff->isChecked()) {
865       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_NONE);
866    } else if (this->radioConvertIEC->isChecked()){
867       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_IEC);
868    } else {
869       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_SI);
870    }
871    mainWin->m_openPlot = this->openPlotCheckBox->checkState() == Qt::Checked;
872    mainWin->m_openBrowser = this->openBrowserCheckBox->checkState() == Qt::Checked;
873    mainWin->m_openDirStat = this->openDirStatCheckBox->checkState() == Qt::Checked;
874
875    QSettings settings("www.bacula.org", "bat");
876    settings.beginGroup("Debug");
877    settings.setValue("commDebug", mainWin->m_commDebug);
878    settings.setValue("connDebug", mainWin->m_connDebug);
879    settings.setValue("displayAll", mainWin->m_displayAll);
880    settings.setValue("sqlDebug", mainWin->m_sqlDebug);
881    settings.setValue("commandDebug", mainWin->m_commandDebug);
882    settings.setValue("miscDebug", mainWin->m_miscDebug);
883    settings.endGroup();
884    settings.beginGroup("JobList");
885    settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
886    settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
887    settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
888    settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
889    settings.endGroup();
890    settings.beginGroup("Timers");
891    settings.setValue("checkMessages", mainWin->m_checkMessages);
892    settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
893    settings.endGroup();
894    settings.beginGroup("Misc");
895    settings.setValue("longList", mainWin->m_longList);
896    settings.setValue("byteConvert", ItemFormatterBase::getBytesConversion());
897    settings.setValue("openplot", mainWin->m_openPlot);
898    settings.setValue("openbrowser", mainWin->m_openBrowser);
899    settings.setValue("opendirstat", mainWin->m_openDirStat);
900    settings.endGroup();
901    settings.beginGroup("RestoreTree");
902    settings.setValue("rtPopDirDebug", mainWin->m_rtPopDirDebug);
903    settings.setValue("rtDirCurICDebug", mainWin->m_rtDirCurICDebug);
904    settings.setValue("rtDirCurICRetDebug", mainWin->m_rtDirICDebug);
905    settings.setValue("rtFileTabICDebug", mainWin->m_rtFileTabICDebug);
906    settings.setValue("rtVerTabICDebug", mainWin->m_rtVerTabICDebug);
907    settings.setValue("rtUpdateFTDebug", mainWin->m_rtUpdateFTDebug);
908    settings.setValue("rtUpdateVTDebug", mainWin->m_rtUpdateVTDebug);
909    settings.setValue("rtChecksDebug", mainWin->m_rtChecksDebug);
910    settings.setValue("rtIconStateDebug", mainWin->m_rtIconStateDebug);
911    settings.setValue("rtRestore1Debug", mainWin->m_rtRestore1Debug);
912    settings.setValue("rtRestore2Debug", mainWin->m_rtRestore2Debug);
913    settings.setValue("rtRestore3Debug", mainWin->m_rtRestore3Debug);
914    settings.endGroup();
915 }
916
917 void prefsDialog::reject()
918 {
919    this->hide();
920    mainWin->set_status(tr("Canceled"));
921 }
922
923 /* read preferences for the prefences dialog box */
924 void MainWin::readPreferences()
925 {
926    QSettings settings("www.bacula.org", "bat");
927    settings.beginGroup("Debug");
928    m_commDebug = settings.value("commDebug", false).toBool();
929    m_connDebug = settings.value("connDebug", false).toBool();
930    m_displayAll = settings.value("displayAll", false).toBool();
931    m_sqlDebug = settings.value("sqlDebug", false).toBool();
932    m_commandDebug = settings.value("commandDebug", false).toBool();
933    m_miscDebug = settings.value("miscDebug", false).toBool();
934    settings.endGroup();
935    settings.beginGroup("JobList");
936    m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
937    m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
938    m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
939    m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
940    settings.endGroup();
941    settings.beginGroup("Timers");
942    m_checkMessages = settings.value("checkMessages", false).toBool();
943    m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();
944    settings.endGroup();
945    settings.beginGroup("Misc");
946    m_longList = settings.value("longList", false).toBool();
947    ItemFormatterBase::setBytesConversion(
948          (ItemFormatterBase::BYTES_CONVERSION) settings.value("byteConvert", 
949          ItemFormatterBase::BYTES_CONVERSION_IEC).toInt());
950    m_openPlot = settings.value("openplot", false).toBool();
951    m_openBrowser = settings.value("openbrowser", false).toBool();
952    m_openDirStat = settings.value("opendirstat", false).toBool();
953    settings.endGroup();
954    settings.beginGroup("RestoreTree");
955    m_rtPopDirDebug = settings.value("rtPopDirDebug", false).toBool();
956    m_rtDirCurICDebug = settings.value("rtDirCurICDebug", false).toBool();
957    m_rtDirICDebug = settings.value("rtDirCurICRetDebug", false).toBool();
958    m_rtFileTabICDebug = settings.value("rtFileTabICDebug", false).toBool();
959    m_rtVerTabICDebug = settings.value("rtVerTabICDebug", false).toBool();
960    m_rtUpdateFTDebug = settings.value("rtUpdateFTDebug", false).toBool();
961    m_rtUpdateVTDebug = settings.value("rtUpdateVTDebug", false).toBool();
962    m_rtChecksDebug = settings.value("rtChecksDebug", false).toBool();
963    m_rtIconStateDebug = settings.value("rtIconStateDebug", false).toBool();
964    m_rtRestore1Debug = settings.value("rtRestore1Debug", false).toBool();
965    m_rtRestore2Debug = settings.value("rtRestore2Debug", false).toBool();
966    m_rtRestore3Debug = settings.value("rtRestore3Debug", false).toBool();
967    settings.endGroup();
968 }
969
970 void MainWin::setMessageIcon()
971 {
972    if (m_currentConsole->is_messagesPending())
973       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-pending.png")));
974    else
975       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-new.png")));
976 }
977
978 void MainWin::goToPreviousPage()
979 {
980    m_treeStackTrap = true;
981    bool done = false;
982    while (!done) {
983       /* If stack list is emtpty, then done */
984       if (m_treeWidgetStack.isEmpty()) {
985          done = true;
986       } else {
987          QTreeWidgetItem* testItem = m_treeWidgetStack.takeLast();
988          QTreeWidgetItemIterator it(treeWidget);
989          /* lets avoid a segfault by setting an item current that no longer exists */
990          while (*it) {
991             if (*it == testItem) {
992                if (testItem != treeWidget->currentItem()) {
993                   treeWidget->setCurrentItem(testItem);
994                   done = true;
995                }
996                break;
997             }
998             ++it;
999          }
1000       }
1001    }
1002    m_treeStackTrap = false;
1003 }