]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
Tweak bat debug code
[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 two of the GNU 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 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(5000, 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
155       /* Set Color of treeWidgetItem for the console
156       * It will be set to green in the console class if the connection is made.
157       */
158       QBrush redBrush(Qt::red);
159       item->setForeground(0, redBrush);
160
161       /*
162        * Create instances in alphabetic order of the rest 
163        *  of the classes that will by default exist under each Director.  
164        */
165 //      new bRestore();
166       new Clients();
167       new FileSet();
168       new Jobs();
169       createPageJobList("", "", "", "", NULL);
170 #ifdef HAVE_QWT
171       JobPlotPass pass;
172       pass.use = false;
173       if (m_openPlot)
174          new JobPlot(NULL, pass);
175 #endif
176       new MediaList();
177       new MediaView();
178       new Storage();
179       if (m_openBrowser)
180          new restoreTree();
181       if (m_openDirStat)
182          new DirStat();
183
184       treeWidget->expandItem(topItem);
185       tabWidget->setCurrentWidget(m_currentConsole);
186       m_currentConsole->undockPage();
187       m_currentConsole->dockPage();
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    m_waitState = false;
328    if (mainWin->m_connDebug) Pmsg0(000, "Exiting Wait State\n");
329    if (m_waitTreeItem != treeWidget->currentItem())
330       treeWidget->setCurrentItem(m_waitTreeItem);
331    if (m_doConnect) {
332       connectSignals();
333       connectConsoleSignals();
334    }
335    app->restoreOverrideCursor();
336 }
337
338 void MainWin::connectConsoleSignals()
339 {
340    connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect_dir()));
341    connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
342    connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
343 }
344
345 void MainWin::disconnectConsoleSignals(Console *console)
346 {
347    disconnect(actionConnect, SIGNAL(triggered()), console, SLOT(connect_dir()));
348    disconnect(actionMessages, SIGNAL(triggered()), console, SLOT(messages()));
349    disconnect(actionSelectFont, SIGNAL(triggered()), console, SLOT(set_font()));
350 }
351
352
353 /* 
354  * Two functions to respond to menu items to repop lists and execute reload and repopulate
355  * the lists for jobs, clients, filesets .. ..
356  */
357 void MainWin::repopLists()
358 {
359    m_currentConsole->populateLists(false);
360 }
361 void MainWin::reloadRepopLists()
362 {
363    QString cmd = "reload";
364    m_currentConsole->consoleCommand(cmd);
365    m_currentConsole->populateLists(false);
366 }
367
368 /* 
369  * Reimplementation of QWidget closeEvent virtual function   
370  */
371 void MainWin::closeEvent(QCloseEvent *event)
372 {
373    m_isClosing = true;
374    writeSettings();
375    /* Remove all groups from settings for OpenOnExit so that we can start some of the status windows */
376    foreach(Console *console, m_consoleHash){
377       QSettings settings(console->m_dir->name(), "bat");
378       settings.beginGroup("OpenOnExit");
379       settings.remove("");
380       settings.endGroup();
381    }
382    /* close all non console pages, this will call settings in destructors */
383    while (m_consoleHash.count() < m_pagehash.count()) {
384       foreach(Pages *page, m_pagehash) {
385          if (page !=  page->console()) {
386             QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(page);
387             if (pageSelectorTreeWidgetItem->childCount() == 0) {
388                page->console()->setCurrent();
389                page->closeStackPage();
390             }
391          }
392       }
393    }
394    foreach(Console *console, m_consoleHash){
395       console->writeSettings();
396       console->terminate();
397       console->closeStackPage();
398    }
399    event->accept();
400 }
401
402 void MainWin::writeSettings()
403 {
404    QSettings settings("bacula.org", "bat");
405
406    settings.beginGroup("MainWin");
407    settings.setValue("winSize", size());
408    settings.setValue("winPos", pos());
409    settings.setValue("state", saveState());
410    settings.endGroup();
411
412 }
413
414 void MainWin::readSettings()
415
416    QSettings settings("bacula.org", "bat");
417
418    settings.beginGroup("MainWin");
419    resize(settings.value("winSize", QSize(1041, 801)).toSize());
420    move(settings.value("winPos", QPoint(200, 150)).toPoint());
421    restoreState(settings.value("state").toByteArray());
422    settings.endGroup();
423 }
424
425 /*
426  * This subroutine is called with an item in the Page Selection window
427  *   is clicked 
428  */
429 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
430 {
431    /* Is this a page that has been inserted into the hash  */
432    if (getFromHash(item)) {
433       Pages* page = getFromHash(item);
434       int stackindex=tabWidget->indexOf(page);
435
436       if (stackindex >= 0) {
437          tabWidget->setCurrentWidget(page);
438       }
439       /* run the virtual function in case this class overrides it */
440       page->PgSeltreeWidgetClicked();
441    }
442 }
443
444 /*
445  * Called with a change of the highlighed tree widget item in the page selector.
446  */
447 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
448 {
449    if (m_isClosing) return; /* if closing the application, do nothing here */
450
451    Pages *previousPage, *nextPage;
452    Console *previousConsole = NULL;
453    Console *nextConsole;
454
455    /* remove all actions before adding actions appropriate for new page */
456    foreach(QAction* pageAction, treeWidget->actions()) {
457       treeWidget->removeAction(pageAction);
458    }
459
460    /* first determine the next item */
461
462    /* knowing the treeWidgetItem, get the page from the hash */
463    nextPage = getFromHash(currentitem);
464    nextConsole = m_consoleHash.value(currentitem);
465    /* Is this a page that has been inserted into the hash  */
466    if (nextPage) {
467       nextConsole = nextPage->console();
468       /* then is it a treeWidgetItem representing a director */
469    } else if (nextConsole) {
470       /* let the next page BE the console */
471       nextPage = nextConsole;
472    } else {
473       /* Should never get here */
474       nextPage = NULL;
475       nextConsole = NULL;
476    }
477           
478    /* The Previous item */
479
480    /* this condition prevents a segfault.  The first time there is no previousitem*/
481    if (previousitem) {
482       if (m_treeStackTrap == false) { /* keep track of previous items for going Back */
483          m_treeWidgetStack.append(previousitem);
484       }
485       /* knowing the treeWidgetItem, get the page from the hash */
486       previousPage = getFromHash(previousitem);
487       previousConsole = m_consoleHash.value(previousitem);
488       if (previousPage) {
489          previousConsole = previousPage->console();
490       } else if (previousConsole) {
491          previousPage = previousConsole;
492       }
493       if ((previousPage) || (previousConsole)) {
494          if (nextConsole != previousConsole) {
495             /* remove connections to the current console */
496             disconnectConsoleSignals(previousConsole);
497             QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
498             QBrush greyBrush(Qt::lightGray);
499             dirItem->setBackground(0, greyBrush);
500          }
501       }
502    }
503
504    /* process the current (next) item */
505    
506    if ((nextPage) || (nextConsole)) {
507       if (nextConsole != previousConsole) {
508          /* make connections to the current console */
509          m_currentConsole = nextConsole;
510          connectConsoleSignals();
511          setMessageIcon();
512          /* Set director's tree widget background to magenta for ease of identification */
513          QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
514          QBrush magentaBrush(Qt::magenta);
515          dirItem->setBackground(0, magentaBrush);
516       }
517       /* set the value for the currently active console */
518       int stackindex = tabWidget->indexOf(nextPage);
519       if (!nextPage->isOnceDocked()) {
520          nextPage->dockPage();
521       }
522    
523       /* Is this page currently on the stack or is it undocked */
524       if (stackindex >= 0) {
525          /* put this page on the top of the stack */
526          tabWidget->setCurrentIndex(stackindex);
527       } else {
528          /* it is undocked, raise it to the front */
529          nextPage->raise();
530       }
531       /* for the page selectors menu action to dock or undock, set the text */
532       nextPage->setContextMenuDockText();
533
534       treeWidget->addAction(actionToggleDock);
535       /* if this page is closeable, and it has no childern, then add that action */
536       if ((nextPage->isCloseable()) && (currentitem->child(0) == NULL))
537          treeWidget->addAction(actionClosePage);
538
539       /* Add the actions to the Page Selectors tree widget that are part of the
540        * current items list of desired actions regardless of whether on top of stack*/
541       treeWidget->addActions(nextPage->m_contextActions);
542    }
543 }
544
545 void MainWin::labelButtonClicked() 
546 {
547    new labelPage();
548 }
549
550 void MainWin::runButtonClicked() 
551 {
552    new runPage("");
553 }
554
555 void MainWin::estimateButtonClicked() 
556 {
557    new estimatePage();
558 }
559
560 void MainWin::browseButtonClicked() 
561 {
562    new restoreTree();
563 }
564
565 void MainWin::statusPageButtonClicked()
566 {
567    /* if one exists, then just set it current */
568    bool found = false;
569    foreach(Pages *page, m_pagehash) {
570       if (m_currentConsole == page->console()) {
571          if (page->name() == tr("Director Status")) {
572             found = true;
573             page->setCurrent();
574          }
575       }
576    }
577    if (!found) {
578       new DirStat();
579    }
580 }
581
582 void MainWin::restoreButtonClicked() 
583 {
584    new prerestorePage();
585    if (mainWin->m_miscDebug) Pmsg0(000, "in restoreButtonClicked after prerestorePage\n");
586 }
587
588 void MainWin::jobPlotButtonClicked()
589 {
590 #ifdef HAVE_QWT
591    JobPlotPass pass;
592    pass.use = false;
593    new JobPlot(NULL, pass);
594 #endif
595 }
596
597 /*
598  * The user just finished typing a line in the command line edit box
599  */
600 void MainWin::input_line()
601 {
602    int conn;
603    QString cmdStr = lineEdit->text();    /* Get the text */
604    lineEdit->clear();                    /* clear the lineEdit box */
605    if (m_currentConsole->is_connected()) {
606       if (m_currentConsole->findDirComm(conn)) {
607          m_currentConsole->consoleCommand(cmdStr, conn);
608       } else {
609          /* Use consoleCommand to allow typing anything */
610          m_currentConsole->consoleCommand(cmdStr);
611       }
612    } else {
613       set_status(tr("Director not connected. Click on connect button."));
614    }
615    m_cmd_history.append(cmdStr);
616    m_cmd_last = -1;
617    if (treeWidget->currentItem() != getFromHash(m_currentConsole))
618       m_currentConsole->setCurrent();
619 }
620
621
622 void MainWin::about()
623 {
624    QMessageBox::about(this, tr("About bat"),
625       tr("<br><h2>bat %1 (%2), by Dirk H Bartley and Kern Sibbald</h2>"
626          "<p>Copyright &copy; 2007-%3 Free Software Foundation Europe e.V."
627          "<p>The <b>bat</b> is an administrative console"
628          " interface to the Director.").arg(VERSION).arg(BDATE).arg(BYEAR));
629 }
630
631 void MainWin::help()
632 {
633    Help::displayFile("index.html");
634 }
635
636 void MainWin::set_statusf(const char *fmt, ...)
637 {
638    va_list arg_ptr;
639    char buf[1000];
640    int len;
641    va_start(arg_ptr, fmt);
642    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
643    va_end(arg_ptr);
644    set_status(buf);
645 }
646
647 void MainWin::set_status_ready()
648 {
649    set_status(tr(" Ready"));
650 }
651
652 void MainWin::set_status(const QString &str)
653 {
654    statusBar()->showMessage(str);
655 }
656
657 void MainWin::set_status(const char *buf)
658 {
659    statusBar()->showMessage(buf);
660 }
661
662 /*
663  * Function to respond to the button bar button to undock
664  */
665 void MainWin::undockWindowButton()
666 {
667    Pages* page = (Pages*)tabWidget->currentWidget();
668    page->togglePageDocking();
669 }
670
671 /*
672  * Function to respond to action on page selector context menu to toggle the 
673  * dock status of the window associated with the page selectors current
674  * tree widget item.
675  */
676 void MainWin::toggleDockContextWindow()
677 {
678    QTreeWidgetItem *currentitem = treeWidget->currentItem();
679    
680    /* Is this a page that has been inserted into the hash  */
681    if (getFromHash(currentitem)) {
682       Pages* page = getFromHash(currentitem);
683       page->togglePageDocking();
684    }
685 }
686
687 /*
688  * This function is called when the stack item is changed.  Call
689  * the virtual function here.  Avoids a window being undocked leaving
690  * a window at the top of the stack unpopulated.
691  */
692 void MainWin::stackItemChanged(int)
693 {
694    if (m_isClosing) return; /* if closing the application, do nothing here */
695    Pages* page = (Pages*)tabWidget->currentWidget();
696    /* run the virtual function in case this class overrides it */
697    page->currentStackItem();
698    if (!m_waitState) {
699       disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
700       disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
701       treeWidget->setCurrentItem(getFromHash(page));
702       connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
703       connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
704    }
705 }
706
707 /*
708  * Function to simplify insertion of QTreeWidgetItem <-> Page association
709  * into a double direction hash.
710  */
711 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
712 {
713    m_pagehash.insert(item, page);
714    m_widgethash.insert(page, item);
715 }
716
717 /*
718  * Function to simplify removal of QTreeWidgetItem <-> Page association
719  * into a double direction hash.
720  */
721 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
722 {
723    /* I had all sorts of return status checking code here.  Do we have a log
724     * level capability in bat.  I would have left it in but it used printf's
725     * and it should really be some kind of log level facility ???
726     * ******FIXME********/
727    m_pagehash.remove(item);
728    m_widgethash.remove(page);
729 }
730
731 /*
732  * Function to retrieve a Page* when the item in the page selector's tree is
733  * known.
734  */
735 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
736 {
737    return m_pagehash.value(item);
738 }
739
740 /*
741  * Function to retrieve the page selectors tree widget item when the page is
742  * known.
743  */
744 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
745 {
746    return m_widgethash.value(page);
747 }
748
749 /*
750  * Function to respond to action on page selector context menu to close the
751  * current window.
752  */
753 void MainWin::closePage()
754 {
755    QTreeWidgetItem *currentitem = treeWidget->currentItem();
756    
757    /* Is this a page that has been inserted into the hash  */
758    if (getFromHash(currentitem)) {
759       Pages* page = getFromHash(currentitem);
760       if (page->isCloseable()) {
761          page->closeStackPage();
762       }
763    }
764 }
765
766 /* Quick function to return the current console */
767 Console *MainWin::currentConsole()
768 {
769    return m_currentConsole;
770 }
771
772 /* Quick function to return the tree item for the director */
773 QTreeWidgetItem *MainWin::currentTopItem()
774 {
775    return m_currentConsole->directorTreeItem();
776 }
777
778 /* Preferences menu item clicked */
779 void MainWin::setPreferences()
780 {
781    prefsDialog prefs;
782    prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
783    prefs.connDebug->setCheckState(m_connDebug ? Qt::Checked : Qt::Unchecked);
784    prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
785    prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
786    prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
787    prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
788    prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
789    prefs.recordSpinBox->setValue(m_recordLimitVal);
790    prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
791    prefs.daysSpinBox->setValue(m_daysLimitVal);
792    prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
793    prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
794    prefs.executeLongCheckBox->setCheckState(m_longList ? Qt::Checked : Qt::Unchecked);
795    prefs.rtPopDirCheckBox->setCheckState(m_rtPopDirDebug ? Qt::Checked : Qt::Unchecked);
796    prefs.rtDirCurICCheckBox->setCheckState(m_rtDirCurICDebug ? Qt::Checked : Qt::Unchecked);
797    prefs.rtDirICCheckBox->setCheckState(m_rtDirICDebug ? Qt::Checked : Qt::Unchecked);
798    prefs.rtFileTabICCheckBox->setCheckState(m_rtFileTabICDebug ? Qt::Checked : Qt::Unchecked);
799    prefs.rtVerTabICCheckBox->setCheckState(m_rtVerTabICDebug ? Qt::Checked : Qt::Unchecked);
800    prefs.rtUpdateFTCheckBox->setCheckState(m_rtUpdateFTDebug ? Qt::Checked : Qt::Unchecked);
801    prefs.rtUpdateVTCheckBox->setCheckState(m_rtUpdateVTDebug ? Qt::Checked : Qt::Unchecked);
802    prefs.rtChecksCheckBox->setCheckState(m_rtChecksDebug ? Qt::Checked : Qt::Unchecked);
803    prefs.rtIconStateCheckBox->setCheckState(m_rtIconStateDebug ? Qt::Checked : Qt::Unchecked);
804    prefs.rtRestore1CheckBox->setCheckState(m_rtRestore1Debug ? Qt::Checked : Qt::Unchecked);
805    prefs.rtRestore2CheckBox->setCheckState(m_rtRestore2Debug ? Qt::Checked : Qt::Unchecked);
806    prefs.rtRestore3CheckBox->setCheckState(m_rtRestore3Debug ? Qt::Checked : Qt::Unchecked);
807    switch (ItemFormatterBase::getBytesConversion()) {
808    case ItemFormatterBase::BYTES_CONVERSION_NONE:
809       prefs.radioConvertOff->setChecked(Qt::Checked);
810       break;
811    case ItemFormatterBase::BYTES_CONVERSION_IEC:
812       prefs.radioConvertIEC->setChecked(Qt::Checked);
813       break;
814    default:
815       prefs.radioConvertStandard->setChecked(Qt::Checked);
816       break;
817    }
818    prefs.openPlotCheckBox->setCheckState(m_openPlot ? Qt::Checked : Qt::Unchecked);
819 #ifndef HAVE_QWT
820    prefs.openPlotCheckBox->setVisible(false);
821 #endif
822    prefs.openBrowserCheckBox->setCheckState(m_openBrowser ? Qt::Checked : Qt::Unchecked);
823    prefs.openDirStatCheckBox->setCheckState(m_openDirStat ? Qt::Checked : Qt::Unchecked);
824    prefs.exec();
825 }
826
827 /* Preferences dialog */
828 prefsDialog::prefsDialog()
829 {
830    setupUi(this);
831 }
832
833 void prefsDialog::accept()
834 {
835    this->hide();
836    mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
837    mainWin->m_connDebug = this->connDebug->checkState() == Qt::Checked;
838    mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
839    mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
840    mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
841    mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
842    mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
843    mainWin->m_recordLimitVal = this->recordSpinBox->value();
844    mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
845    mainWin->m_daysLimitVal = this->daysSpinBox->value();
846    mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
847    mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
848    mainWin->m_longList = this->executeLongCheckBox->checkState() == Qt::Checked;
849
850    mainWin->m_rtPopDirDebug = this->rtPopDirCheckBox->checkState() == Qt::Checked;
851    mainWin->m_rtDirCurICDebug = this->rtDirCurICCheckBox->checkState() == Qt::Checked;
852    mainWin->m_rtDirICDebug = this->rtDirICCheckBox->checkState() == Qt::Checked;
853    mainWin->m_rtFileTabICDebug = this->rtFileTabICCheckBox->checkState() == Qt::Checked;
854    mainWin->m_rtVerTabICDebug = this->rtVerTabICCheckBox->checkState() == Qt::Checked;
855    mainWin->m_rtUpdateFTDebug = this->rtUpdateFTCheckBox->checkState() == Qt::Checked;
856    mainWin->m_rtUpdateVTDebug = this->rtUpdateVTCheckBox->checkState() == Qt::Checked;
857    mainWin->m_rtChecksDebug = this->rtChecksCheckBox->checkState() == Qt::Checked;
858    mainWin->m_rtIconStateDebug = this->rtIconStateCheckBox->checkState() == Qt::Checked;
859    mainWin->m_rtRestore1Debug = this->rtRestore1CheckBox->checkState() == Qt::Checked;
860    mainWin->m_rtRestore2Debug = this->rtRestore2CheckBox->checkState() == Qt::Checked;
861    mainWin->m_rtRestore3Debug = this->rtRestore3CheckBox->checkState() == Qt::Checked;
862    if (this->radioConvertOff->isChecked()) {
863       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_NONE);
864    } else if (this->radioConvertIEC->isChecked()){
865       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_IEC);
866    } else {
867       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_SI);
868    }
869    mainWin->m_openPlot = this->openPlotCheckBox->checkState() == Qt::Checked;
870    mainWin->m_openBrowser = this->openBrowserCheckBox->checkState() == Qt::Checked;
871    mainWin->m_openDirStat = this->openDirStatCheckBox->checkState() == Qt::Checked;
872
873    QSettings settings("www.bacula.org", "bat");
874    settings.beginGroup("Debug");
875    settings.setValue("commDebug", mainWin->m_commDebug);
876    settings.setValue("connDebug", mainWin->m_connDebug);
877    settings.setValue("displayAll", mainWin->m_displayAll);
878    settings.setValue("sqlDebug", mainWin->m_sqlDebug);
879    settings.setValue("commandDebug", mainWin->m_commandDebug);
880    settings.setValue("miscDebug", mainWin->m_miscDebug);
881    settings.endGroup();
882    settings.beginGroup("JobList");
883    settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
884    settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
885    settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
886    settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
887    settings.endGroup();
888    settings.beginGroup("Timers");
889    settings.setValue("checkMessages", mainWin->m_checkMessages);
890    settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
891    settings.endGroup();
892    settings.beginGroup("Misc");
893    settings.setValue("longList", mainWin->m_longList);
894    settings.setValue("byteConvert", ItemFormatterBase::getBytesConversion());
895    settings.setValue("openplot", mainWin->m_openPlot);
896    settings.setValue("openbrowser", mainWin->m_openBrowser);
897    settings.setValue("opendirstat", mainWin->m_openDirStat);
898    settings.endGroup();
899    settings.beginGroup("RestoreTree");
900    settings.setValue("rtPopDirDebug", mainWin->m_rtPopDirDebug);
901    settings.setValue("rtDirCurICDebug", mainWin->m_rtDirCurICDebug);
902    settings.setValue("rtDirCurICRetDebug", mainWin->m_rtDirICDebug);
903    settings.setValue("rtFileTabICDebug", mainWin->m_rtFileTabICDebug);
904    settings.setValue("rtVerTabICDebug", mainWin->m_rtVerTabICDebug);
905    settings.setValue("rtUpdateFTDebug", mainWin->m_rtUpdateFTDebug);
906    settings.setValue("rtUpdateVTDebug", mainWin->m_rtUpdateVTDebug);
907    settings.setValue("rtChecksDebug", mainWin->m_rtChecksDebug);
908    settings.setValue("rtIconStateDebug", mainWin->m_rtIconStateDebug);
909    settings.setValue("rtRestore1Debug", mainWin->m_rtRestore1Debug);
910    settings.setValue("rtRestore2Debug", mainWin->m_rtRestore2Debug);
911    settings.setValue("rtRestore3Debug", mainWin->m_rtRestore3Debug);
912    settings.endGroup();
913 }
914
915 void prefsDialog::reject()
916 {
917    this->hide();
918    mainWin->set_status(tr("Canceled"));
919 }
920
921 /* read preferences for the prefences dialog box */
922 void MainWin::readPreferences()
923 {
924    QSettings settings("www.bacula.org", "bat");
925    settings.beginGroup("Debug");
926    m_commDebug = settings.value("commDebug", false).toBool();
927    m_connDebug = settings.value("connDebug", false).toBool();
928    m_displayAll = settings.value("displayAll", false).toBool();
929    m_sqlDebug = settings.value("sqlDebug", false).toBool();
930    m_commandDebug = settings.value("commandDebug", false).toBool();
931    m_miscDebug = settings.value("miscDebug", false).toBool();
932    settings.endGroup();
933    settings.beginGroup("JobList");
934    m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
935    m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
936    m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
937    m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
938    settings.endGroup();
939    settings.beginGroup("Timers");
940    m_checkMessages = settings.value("checkMessages", false).toBool();
941    m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();
942    settings.endGroup();
943    settings.beginGroup("Misc");
944    m_longList = settings.value("longList", false).toBool();
945    ItemFormatterBase::setBytesConversion(
946          (ItemFormatterBase::BYTES_CONVERSION) settings.value("byteConvert", 
947          ItemFormatterBase::BYTES_CONVERSION_IEC).toInt());
948    m_openPlot = settings.value("openplot", false).toBool();
949    m_openBrowser = settings.value("openbrowser", false).toBool();
950    m_openDirStat = settings.value("opendirstat", false).toBool();
951    settings.endGroup();
952    settings.beginGroup("RestoreTree");
953    m_rtPopDirDebug = settings.value("rtPopDirDebug", false).toBool();
954    m_rtDirCurICDebug = settings.value("rtDirCurICDebug", false).toBool();
955    m_rtDirICDebug = settings.value("rtDirCurICRetDebug", false).toBool();
956    m_rtFileTabICDebug = settings.value("rtFileTabICDebug", false).toBool();
957    m_rtVerTabICDebug = settings.value("rtVerTabICDebug", false).toBool();
958    m_rtUpdateFTDebug = settings.value("rtUpdateFTDebug", false).toBool();
959    m_rtUpdateVTDebug = settings.value("rtUpdateVTDebug", false).toBool();
960    m_rtChecksDebug = settings.value("rtChecksDebug", false).toBool();
961    m_rtIconStateDebug = settings.value("rtIconStateDebug", false).toBool();
962    m_rtRestore1Debug = settings.value("rtRestore1Debug", false).toBool();
963    m_rtRestore2Debug = settings.value("rtRestore2Debug", false).toBool();
964    m_rtRestore3Debug = settings.value("rtRestore3Debug", false).toBool();
965    settings.endGroup();
966 }
967
968 void MainWin::setMessageIcon()
969 {
970    if (m_currentConsole->is_messagesPending())
971       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-pending.png")));
972    else
973       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-new.png")));
974 }
975
976 void MainWin::goToPreviousPage()
977 {
978    m_treeStackTrap = true;
979    bool done = false;
980    while (!done) {
981       /* If stack list is emtpty, then done */
982       if (m_treeWidgetStack.isEmpty()) {
983          done = true;
984       } else {
985          QTreeWidgetItem* testItem = m_treeWidgetStack.takeLast();
986          QTreeWidgetItemIterator it(treeWidget);
987          /* lets avoid a segfault by setting an item current that no longer exists */
988          while (*it) {
989             if (*it == testItem) {
990                if (testItem != treeWidget->currentItem()) {
991                   treeWidget->setCurrentItem(testItem);
992                   done = true;
993                }
994                break;
995             }
996             ++it;
997          }
998       }
999    }
1000    m_treeStackTrap = false;
1001 }