]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
Require Qt version 4.8.4
[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(int)));
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(closeCurrentPage()));
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(int)));
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(closeCurrentPage()));
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    Pages* page = getFromHash(item);
446    if (page) {
447       int stackindex = tabWidget->indexOf(page);
448
449       if (stackindex >= 0) {
450          tabWidget->setCurrentWidget(page);
451       }
452       page->dockPage();
453       /* run the virtual function in case this class overrides it */
454       page->PgSeltreeWidgetClicked();
455    } else {
456       Dmsg0(000, "Page not in hash");
457    }
458 }
459
460 /*
461  * Called with a change of the highlighed tree widget item in the page selector.
462  */
463 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
464 {
465    if (m_isClosing) return; /* if closing the application, do nothing here */
466
467    Pages *previousPage, *nextPage;
468    Console *previousConsole = NULL;
469    Console *nextConsole;
470
471    /* remove all actions before adding actions appropriate for new page */
472    foreach(QAction* pageAction, treeWidget->actions()) {
473       treeWidget->removeAction(pageAction);
474    }
475
476    /* first determine the next item */
477
478    /* knowing the treeWidgetItem, get the page from the hash */
479    nextPage = getFromHash(currentitem);
480    nextConsole = m_consoleHash.value(currentitem);
481    /* Is this a page that has been inserted into the hash  */
482    if (nextPage) {
483       nextConsole = nextPage->console();
484       /* then is it a treeWidgetItem representing a director */
485    } else if (nextConsole) {
486       /* let the next page BE the console */
487       nextPage = nextConsole;
488    } else {
489       /* Should never get here */
490       nextPage = NULL;
491       nextConsole = NULL;
492    }
493           
494    /* The Previous item */
495
496    /* this condition prevents a segfault.  The first time there is no previousitem*/
497    if (previousitem) {
498       if (m_treeStackTrap == false) { /* keep track of previous items for going Back */
499          m_treeWidgetStack.append(previousitem);
500       }
501       /* knowing the treeWidgetItem, get the page from the hash */
502       previousPage = getFromHash(previousitem);
503       previousConsole = m_consoleHash.value(previousitem);
504       if (previousPage) {
505          previousConsole = previousPage->console();
506       } else if (previousConsole) {
507          previousPage = previousConsole;
508       }
509       if ((previousPage) || (previousConsole)) {
510          if (nextConsole != previousConsole) {
511             /* remove connections to the current console */
512             disconnectConsoleSignals(previousConsole);
513             QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
514             QBrush greyBrush(Qt::lightGray);
515             dirItem->setBackground(0, greyBrush);
516          }
517       }
518    }
519
520    /* process the current (next) item */
521    
522    if ((nextPage) || (nextConsole)) {
523       if (nextConsole != previousConsole) {
524          /* make connections to the current console */
525          m_currentConsole = nextConsole;
526          connectConsoleSignals();
527          setMessageIcon();
528          /* Set director's tree widget background to magenta for ease of identification */
529          QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
530          QBrush magentaBrush(Qt::magenta);
531          dirItem->setBackground(0, magentaBrush);
532       }
533       /* set the value for the currently active console */
534       int stackindex = tabWidget->indexOf(nextPage);
535       nextPage->firstUseDock();
536    
537       /* Is this page currently on the stack or is it undocked */
538       if (stackindex >= 0) {
539          /* put this page on the top of the stack */
540          tabWidget->setCurrentIndex(stackindex);
541       } else {
542          /* it is undocked, raise it to the front */
543          nextPage->raise();
544       }
545       /* for the page selectors menu action to dock or undock, set the text */
546       nextPage->setContextMenuDockText();
547
548       treeWidget->addAction(actionToggleDock);
549       /* if this page is closeable, and it has no childern, then add that action */
550       if ((nextPage->isCloseable()) && (currentitem->child(0) == NULL))
551          treeWidget->addAction(actionClosePage);
552
553       /* Add the actions to the Page Selectors tree widget that are part of the
554        * current items list of desired actions regardless of whether on top of stack*/
555       treeWidget->addActions(nextPage->m_contextActions);
556    }
557 }
558
559 void MainWin::labelButtonClicked() 
560 {
561    new labelPage();
562 }
563
564 void MainWin::runButtonClicked() 
565 {
566    new runPage("");
567 }
568
569 void MainWin::estimateButtonClicked() 
570 {
571    new estimatePage();
572 }
573
574 void MainWin::browseButtonClicked() 
575 {
576 //   new restoreTree();
577 }
578
579 void MainWin::statusPageButtonClicked()
580 {
581    /* if one exists, then just set it current */
582    bool found = false;
583    foreach(Pages *page, m_pagehash) {
584       if (m_currentConsole == page->console()) {
585          if (page->name() == tr("Director Status")) {
586             found = true;
587             page->setCurrent();
588          }
589       }
590    }
591    if (!found) {
592       new DirStat();
593    }
594 }
595
596 void MainWin::restoreButtonClicked() 
597 {
598    new prerestorePage();
599    if (mainWin->m_miscDebug) Pmsg0(000, "in restoreButtonClicked after prerestorePage\n");
600 }
601
602 void MainWin::jobPlotButtonClicked()
603 {
604 #ifdef HAVE_QWT
605    JobPlotPass pass;
606    pass.use = false;
607    new JobPlot(NULL, pass);
608 #endif
609 }
610
611 /*
612  * The user just finished typing a line in the command line edit box
613  */
614 void MainWin::input_line()
615 {
616    int conn;
617    QString cmdStr = lineEdit->text();    /* Get the text */
618    lineEdit->clear();                    /* clear the lineEdit box */
619    if (m_currentConsole->is_connected()) {
620       if (m_currentConsole->findDirComm(conn)) {
621          m_currentConsole->consoleCommand(cmdStr, conn);
622       } else {
623          /* Use consoleCommand to allow typing anything */
624          m_currentConsole->consoleCommand(cmdStr);
625       }
626    } else {
627       set_status(tr("Director not connected. Click on connect button."));
628    }
629    m_cmd_history.append(cmdStr);
630    m_cmd_last = -1;
631    if (treeWidget->currentItem() != getFromHash(m_currentConsole))
632       m_currentConsole->setCurrent();
633 }
634
635
636 void MainWin::about()
637 {
638    QMessageBox::about(this, tr("About bat"),
639       tr("<br><h2>bat %1 (%2), by Dirk H Bartley and Kern Sibbald</h2>"
640          "<p>Copyright &copy; 2007-%3 Free Software Foundation Europe e.V."
641          "<p>The <b>bat</b> is an administrative console"
642          " interface to the Director.").arg(VERSION).arg(BDATE).arg(BYEAR));
643 }
644
645 void MainWin::help()
646 {
647    Help::displayFile("index.html");
648 }
649
650 void MainWin::set_statusf(const char *fmt, ...)
651 {
652    va_list arg_ptr;
653    char buf[1000];
654    va_start(arg_ptr, fmt);
655    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
656    va_end(arg_ptr);
657    set_status(buf);
658 }
659
660 void MainWin::set_status_ready()
661 {
662    set_status(tr(" Ready"));
663 }
664
665 void MainWin::set_status(const QString &str)
666 {
667    statusBar()->showMessage(str);
668 }
669
670 void MainWin::set_status(const char *buf)
671 {
672    statusBar()->showMessage(buf);
673 }
674
675 /*
676  * Function to respond to the button bar button to undock
677  */
678 void MainWin::undockWindowButton()
679 {
680    Pages* page = (Pages*)tabWidget->currentWidget();
681    if (page) {
682       page->togglePageDocking();
683    }
684 }
685
686 /*
687  * Function to respond to action on page selector context menu to toggle the 
688  * dock status of the window associated with the page selectors current
689  * tree widget item.
690  */
691 void MainWin::toggleDockContextWindow()
692 {
693    QTreeWidgetItem *currentitem = treeWidget->currentItem();
694    
695    /* Is this a page that has been inserted into the hash  */
696    if (getFromHash(currentitem)) {
697       Pages* page = getFromHash(currentitem);
698       if (page) {
699          page->togglePageDocking();
700       }
701    }
702 }
703
704 /*
705  * This function is called when the stack item is changed.  Call
706  * the virtual function here.  Avoids a window being undocked leaving
707  * a window at the top of the stack unpopulated.
708  */
709 void MainWin::stackItemChanged(int)
710 {
711    if (m_isClosing) return; /* if closing the application, do nothing here */
712    Pages* page = (Pages*)tabWidget->currentWidget();
713    /* run the virtual function in case this class overrides it */
714    if (page) {
715       page->currentStackItem();
716    }
717    if (!m_waitState) {
718       disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
719       disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
720       treeWidget->setCurrentItem(getFromHash(page));
721       connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
722       connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
723    }
724 }
725
726 /*
727  * Function to simplify insertion of QTreeWidgetItem <-> Page association
728  * into a double direction hash.
729  */
730 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
731 {
732    m_pagehash.insert(item, page);
733    m_widgethash.insert(page, item);
734 }
735
736 /*
737  * Function to simplify removal of QTreeWidgetItem <-> Page association
738  * into a double direction hash.
739  */
740 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
741 {
742    /* I had all sorts of return status checking code here.  Do we have a log
743     * level capability in bat.  I would have left it in but it used printf's
744     * and it should really be some kind of log level facility ???
745     * ******FIXME********/
746    m_pagehash.remove(item);
747    m_widgethash.remove(page);
748 }
749
750 /*
751  * Function to retrieve a Page* when the item in the page selector's tree is
752  * known.
753  */
754 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
755 {
756    return m_pagehash.value(item);
757 }
758
759 /*
760  * Function to retrieve the page selectors tree widget item when the page is
761  * known.
762  */
763 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
764 {
765    return m_widgethash.value(page);
766 }
767
768 void MainWin::closeCurrentPage()
769 {
770    closePage(-1);
771 }
772
773 /*
774  * Function to respond to action on page selector context menu to close the
775  * current window.
776  */
777 void MainWin::closePage(int item)
778 {
779    QTreeWidgetItem *currentitem;
780    Pages *page = NULL;
781
782    if (item >= 0) {
783      page = (Pages *)tabWidget->widget(item);
784    } else {
785       currentitem = treeWidget->currentItem();
786       /* Is this a page that has been inserted into the hash  */
787       if (getFromHash(currentitem)) {
788          page = getFromHash(currentitem);
789       }
790    }   
791    
792    if (page) {
793       if (page->isCloseable()) {
794          page->closeStackPage();
795       } else {
796          page->hidePage();
797       }
798    }
799 }
800
801 /* Quick function to return the current console */
802 Console *MainWin::currentConsole()
803 {
804    return m_currentConsole;
805 }
806
807 /* Quick function to return the tree item for the director */
808 QTreeWidgetItem *MainWin::currentTopItem()
809 {
810    return m_currentConsole->directorTreeItem();
811 }
812
813 /* Preferences menu item clicked */
814 void MainWin::setPreferences()
815 {
816    prefsDialog prefs;
817    prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
818    prefs.connDebug->setCheckState(m_connDebug ? Qt::Checked : Qt::Unchecked);
819    prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
820    prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
821    prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
822    prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
823    prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
824    prefs.recordSpinBox->setValue(m_recordLimitVal);
825    prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
826    prefs.daysSpinBox->setValue(m_daysLimitVal);
827    prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
828    prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
829    prefs.executeLongCheckBox->setCheckState(m_longList ? Qt::Checked : Qt::Unchecked);
830    prefs.rtPopDirCheckBox->setCheckState(m_rtPopDirDebug ? Qt::Checked : Qt::Unchecked);
831    prefs.rtDirCurICCheckBox->setCheckState(m_rtDirCurICDebug ? Qt::Checked : Qt::Unchecked);
832    prefs.rtDirICCheckBox->setCheckState(m_rtDirICDebug ? Qt::Checked : Qt::Unchecked);
833    prefs.rtFileTabICCheckBox->setCheckState(m_rtFileTabICDebug ? Qt::Checked : Qt::Unchecked);
834    prefs.rtVerTabICCheckBox->setCheckState(m_rtVerTabICDebug ? Qt::Checked : Qt::Unchecked);
835    prefs.rtUpdateFTCheckBox->setCheckState(m_rtUpdateFTDebug ? Qt::Checked : Qt::Unchecked);
836    prefs.rtUpdateVTCheckBox->setCheckState(m_rtUpdateVTDebug ? Qt::Checked : Qt::Unchecked);
837    prefs.rtChecksCheckBox->setCheckState(m_rtChecksDebug ? Qt::Checked : Qt::Unchecked);
838    prefs.rtIconStateCheckBox->setCheckState(m_rtIconStateDebug ? Qt::Checked : Qt::Unchecked);
839    prefs.rtRestore1CheckBox->setCheckState(m_rtRestore1Debug ? Qt::Checked : Qt::Unchecked);
840    prefs.rtRestore2CheckBox->setCheckState(m_rtRestore2Debug ? Qt::Checked : Qt::Unchecked);
841    prefs.rtRestore3CheckBox->setCheckState(m_rtRestore3Debug ? Qt::Checked : Qt::Unchecked);
842    switch (ItemFormatterBase::getBytesConversion()) {
843    case ItemFormatterBase::BYTES_CONVERSION_NONE:
844       prefs.radioConvertOff->setChecked(Qt::Checked);
845       break;
846    case ItemFormatterBase::BYTES_CONVERSION_IEC:
847       prefs.radioConvertIEC->setChecked(Qt::Checked);
848       break;
849    default:
850       prefs.radioConvertStandard->setChecked(Qt::Checked);
851       break;
852    }
853    prefs.openPlotCheckBox->setCheckState(m_openPlot ? Qt::Checked : Qt::Unchecked);
854 #ifndef HAVE_QWT
855    prefs.openPlotCheckBox->setVisible(false);
856 #endif
857    prefs.openBrowserCheckBox->setCheckState(m_openBrowser ? Qt::Checked : Qt::Unchecked);
858    prefs.openDirStatCheckBox->setCheckState(m_openDirStat ? Qt::Checked : Qt::Unchecked);
859    prefs.exec();
860 }
861
862 /* Preferences dialog */
863 prefsDialog::prefsDialog() : QDialog()
864 {
865    setupUi(this);
866 }
867
868 void prefsDialog::accept()
869 {
870    this->hide();
871    mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
872    mainWin->m_connDebug = this->connDebug->checkState() == Qt::Checked;
873    mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
874    mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
875    mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
876    mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
877    mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
878    mainWin->m_recordLimitVal = this->recordSpinBox->value();
879    mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
880    mainWin->m_daysLimitVal = this->daysSpinBox->value();
881    mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
882    mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
883    mainWin->m_longList = this->executeLongCheckBox->checkState() == Qt::Checked;
884
885    mainWin->m_rtPopDirDebug = this->rtPopDirCheckBox->checkState() == Qt::Checked;
886    mainWin->m_rtDirCurICDebug = this->rtDirCurICCheckBox->checkState() == Qt::Checked;
887    mainWin->m_rtDirICDebug = this->rtDirICCheckBox->checkState() == Qt::Checked;
888    mainWin->m_rtFileTabICDebug = this->rtFileTabICCheckBox->checkState() == Qt::Checked;
889    mainWin->m_rtVerTabICDebug = this->rtVerTabICCheckBox->checkState() == Qt::Checked;
890    mainWin->m_rtUpdateFTDebug = this->rtUpdateFTCheckBox->checkState() == Qt::Checked;
891    mainWin->m_rtUpdateVTDebug = this->rtUpdateVTCheckBox->checkState() == Qt::Checked;
892    mainWin->m_rtChecksDebug = this->rtChecksCheckBox->checkState() == Qt::Checked;
893    mainWin->m_rtIconStateDebug = this->rtIconStateCheckBox->checkState() == Qt::Checked;
894    mainWin->m_rtRestore1Debug = this->rtRestore1CheckBox->checkState() == Qt::Checked;
895    mainWin->m_rtRestore2Debug = this->rtRestore2CheckBox->checkState() == Qt::Checked;
896    mainWin->m_rtRestore3Debug = this->rtRestore3CheckBox->checkState() == Qt::Checked;
897    if (this->radioConvertOff->isChecked()) {
898       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_NONE);
899    } else if (this->radioConvertIEC->isChecked()){
900       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_IEC);
901    } else {
902       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_SI);
903    }
904    mainWin->m_openPlot = this->openPlotCheckBox->checkState() == Qt::Checked;
905    mainWin->m_openBrowser = this->openBrowserCheckBox->checkState() == Qt::Checked;
906    mainWin->m_openDirStat = this->openDirStatCheckBox->checkState() == Qt::Checked;
907
908    QSettings settings("www.bacula.org", "bat");
909    settings.beginGroup("Debug");
910    settings.setValue("commDebug", mainWin->m_commDebug);
911    settings.setValue("connDebug", mainWin->m_connDebug);
912    settings.setValue("displayAll", mainWin->m_displayAll);
913    settings.setValue("sqlDebug", mainWin->m_sqlDebug);
914    settings.setValue("commandDebug", mainWin->m_commandDebug);
915    settings.setValue("miscDebug", mainWin->m_miscDebug);
916    settings.endGroup();
917    settings.beginGroup("JobList");
918    settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
919    settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
920    settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
921    settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
922    settings.endGroup();
923    settings.beginGroup("Timers");
924    settings.setValue("checkMessages", mainWin->m_checkMessages);
925    settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
926    settings.endGroup();
927    settings.beginGroup("Misc");
928    settings.setValue("longList", mainWin->m_longList);
929    settings.setValue("byteConvert", ItemFormatterBase::getBytesConversion());
930    settings.setValue("openplot", mainWin->m_openPlot);
931    settings.setValue("openbrowser", mainWin->m_openBrowser);
932    settings.setValue("opendirstat", mainWin->m_openDirStat);
933    settings.endGroup();
934    settings.beginGroup("RestoreTree");
935    settings.setValue("rtPopDirDebug", mainWin->m_rtPopDirDebug);
936    settings.setValue("rtDirCurICDebug", mainWin->m_rtDirCurICDebug);
937    settings.setValue("rtDirCurICRetDebug", mainWin->m_rtDirICDebug);
938    settings.setValue("rtFileTabICDebug", mainWin->m_rtFileTabICDebug);
939    settings.setValue("rtVerTabICDebug", mainWin->m_rtVerTabICDebug);
940    settings.setValue("rtUpdateFTDebug", mainWin->m_rtUpdateFTDebug);
941    settings.setValue("rtUpdateVTDebug", mainWin->m_rtUpdateVTDebug);
942    settings.setValue("rtChecksDebug", mainWin->m_rtChecksDebug);
943    settings.setValue("rtIconStateDebug", mainWin->m_rtIconStateDebug);
944    settings.setValue("rtRestore1Debug", mainWin->m_rtRestore1Debug);
945    settings.setValue("rtRestore2Debug", mainWin->m_rtRestore2Debug);
946    settings.setValue("rtRestore3Debug", mainWin->m_rtRestore3Debug);
947    settings.endGroup();
948 }
949
950 void prefsDialog::reject()
951 {
952    this->hide();
953    mainWin->set_status(tr("Canceled"));
954 }
955
956 /* read preferences for the prefences dialog box */
957 void MainWin::readPreferences()
958 {
959    QSettings settings("www.bacula.org", "bat");
960    settings.beginGroup("Debug");
961    m_commDebug = settings.value("commDebug", false).toBool();
962    m_connDebug = settings.value("connDebug", false).toBool();
963    m_displayAll = settings.value("displayAll", false).toBool();
964    m_sqlDebug = settings.value("sqlDebug", false).toBool();
965    m_commandDebug = settings.value("commandDebug", false).toBool();
966    m_miscDebug = settings.value("miscDebug", false).toBool();
967    settings.endGroup();
968    settings.beginGroup("JobList");
969    m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
970    m_recordLimitVal = settings.value("recordLimitVal", 50).toInt();
971    m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
972    m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
973    settings.endGroup();
974    settings.beginGroup("Timers");
975    m_checkMessages = settings.value("checkMessages", false).toBool();
976    m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();
977    settings.endGroup();
978    settings.beginGroup("Misc");
979    m_longList = settings.value("longList", false).toBool();
980    ItemFormatterBase::setBytesConversion(
981          (ItemFormatterBase::BYTES_CONVERSION) settings.value("byteConvert", 
982          ItemFormatterBase::BYTES_CONVERSION_IEC).toInt());
983    m_openPlot = settings.value("openplot", false).toBool();
984    m_openBrowser = settings.value("openbrowser", false).toBool();
985    m_openDirStat = settings.value("opendirstat", false).toBool();
986    settings.endGroup();
987    settings.beginGroup("RestoreTree");
988    m_rtPopDirDebug = settings.value("rtPopDirDebug", false).toBool();
989    m_rtDirCurICDebug = settings.value("rtDirCurICDebug", false).toBool();
990    m_rtDirICDebug = settings.value("rtDirCurICRetDebug", false).toBool();
991    m_rtFileTabICDebug = settings.value("rtFileTabICDebug", false).toBool();
992    m_rtVerTabICDebug = settings.value("rtVerTabICDebug", false).toBool();
993    m_rtUpdateFTDebug = settings.value("rtUpdateFTDebug", false).toBool();
994    m_rtUpdateVTDebug = settings.value("rtUpdateVTDebug", false).toBool();
995    m_rtChecksDebug = settings.value("rtChecksDebug", false).toBool();
996    m_rtIconStateDebug = settings.value("rtIconStateDebug", false).toBool();
997    m_rtRestore1Debug = settings.value("rtRestore1Debug", false).toBool();
998    m_rtRestore2Debug = settings.value("rtRestore2Debug", false).toBool();
999    m_rtRestore3Debug = settings.value("rtRestore3Debug", false).toBool();
1000    settings.endGroup();
1001 }
1002
1003 void MainWin::setMessageIcon()
1004 {
1005    if (m_currentConsole->is_messagesPending())
1006       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-pending.png")));
1007    else
1008       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-new.png")));
1009 }
1010
1011 void MainWin::goToPreviousPage()
1012 {
1013    m_treeStackTrap = true;
1014    bool done = false;
1015    while (!done) {
1016       /* If stack list is emtpty, then done */
1017       if (m_treeWidgetStack.isEmpty()) {
1018          done = true;
1019       } else {
1020          QTreeWidgetItem* testItem = m_treeWidgetStack.takeLast();
1021          QTreeWidgetItemIterator it(treeWidget);
1022          /* lets avoid a segfault by setting an item current that no longer exists */
1023          while (*it) {
1024             if (*it == testItem) {
1025                if (testItem != treeWidget->currentItem()) {
1026                   treeWidget->setCurrentItem(testItem);
1027                   done = true;
1028                }
1029                break;
1030             }
1031             ++it;
1032          }
1033       }
1034    }
1035    m_treeStackTrap = false;
1036 }