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