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