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