]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
Improve bat stability by checking if page valid
[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    int len;
655    va_start(arg_ptr, fmt);
656    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
657    va_end(arg_ptr);
658    set_status(buf);
659 }
660
661 void MainWin::set_status_ready()
662 {
663    set_status(tr(" Ready"));
664 }
665
666 void MainWin::set_status(const QString &str)
667 {
668    statusBar()->showMessage(str);
669 }
670
671 void MainWin::set_status(const char *buf)
672 {
673    statusBar()->showMessage(buf);
674 }
675
676 /*
677  * Function to respond to the button bar button to undock
678  */
679 void MainWin::undockWindowButton()
680 {
681    Pages* page = (Pages*)tabWidget->currentWidget();
682    if (page) {
683       page->togglePageDocking();
684    }
685 }
686
687 /*
688  * Function to respond to action on page selector context menu to toggle the 
689  * dock status of the window associated with the page selectors current
690  * tree widget item.
691  */
692 void MainWin::toggleDockContextWindow()
693 {
694    QTreeWidgetItem *currentitem = treeWidget->currentItem();
695    
696    /* Is this a page that has been inserted into the hash  */
697    if (getFromHash(currentitem)) {
698       Pages* page = getFromHash(currentitem);
699       if (page) {
700          page->togglePageDocking();
701       }
702    }
703 }
704
705 /*
706  * This function is called when the stack item is changed.  Call
707  * the virtual function here.  Avoids a window being undocked leaving
708  * a window at the top of the stack unpopulated.
709  */
710 void MainWin::stackItemChanged(int)
711 {
712    if (m_isClosing) return; /* if closing the application, do nothing here */
713    Pages* page = (Pages*)tabWidget->currentWidget();
714    /* run the virtual function in case this class overrides it */
715    if (page) {
716       page->currentStackItem();
717    }
718    if (!m_waitState) {
719       disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
720       disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
721       treeWidget->setCurrentItem(getFromHash(page));
722       connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
723       connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
724    }
725 }
726
727 /*
728  * Function to simplify insertion of QTreeWidgetItem <-> Page association
729  * into a double direction hash.
730  */
731 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
732 {
733    m_pagehash.insert(item, page);
734    m_widgethash.insert(page, item);
735 }
736
737 /*
738  * Function to simplify removal of QTreeWidgetItem <-> Page association
739  * into a double direction hash.
740  */
741 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
742 {
743    /* I had all sorts of return status checking code here.  Do we have a log
744     * level capability in bat.  I would have left it in but it used printf's
745     * and it should really be some kind of log level facility ???
746     * ******FIXME********/
747    m_pagehash.remove(item);
748    m_widgethash.remove(page);
749 }
750
751 /*
752  * Function to retrieve a Page* when the item in the page selector's tree is
753  * known.
754  */
755 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
756 {
757    return m_pagehash.value(item);
758 }
759
760 /*
761  * Function to retrieve the page selectors tree widget item when the page is
762  * known.
763  */
764 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
765 {
766    return m_widgethash.value(page);
767 }
768
769 void MainWin::closeCurrentPage()
770 {
771    closePage(-1);
772 }
773
774 /*
775  * Function to respond to action on page selector context menu to close the
776  * current window.
777  */
778 void MainWin::closePage(int item)
779 {
780    QTreeWidgetItem *currentitem;
781    Pages *page;
782
783    if (item >= 0) {
784      page = (Pages *)tabWidget->widget(item);
785    } else {
786       currentitem = treeWidget->currentItem();
787       /* Is this a page that has been inserted into the hash  */
788       if (getFromHash(currentitem)) {
789          page = getFromHash(currentitem);
790       }
791    }   
792    
793    if (page) {
794       if (page->isCloseable()) {
795          page->closeStackPage();
796       } else {
797          page->hidePage();
798       }
799    }
800 }
801
802 /* Quick function to return the current console */
803 Console *MainWin::currentConsole()
804 {
805    return m_currentConsole;
806 }
807
808 /* Quick function to return the tree item for the director */
809 QTreeWidgetItem *MainWin::currentTopItem()
810 {
811    return m_currentConsole->directorTreeItem();
812 }
813
814 /* Preferences menu item clicked */
815 void MainWin::setPreferences()
816 {
817    prefsDialog prefs;
818    prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
819    prefs.connDebug->setCheckState(m_connDebug ? Qt::Checked : Qt::Unchecked);
820    prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
821    prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
822    prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
823    prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
824    prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
825    prefs.recordSpinBox->setValue(m_recordLimitVal);
826    prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
827    prefs.daysSpinBox->setValue(m_daysLimitVal);
828    prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
829    prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
830    prefs.executeLongCheckBox->setCheckState(m_longList ? Qt::Checked : Qt::Unchecked);
831    prefs.rtPopDirCheckBox->setCheckState(m_rtPopDirDebug ? Qt::Checked : Qt::Unchecked);
832    prefs.rtDirCurICCheckBox->setCheckState(m_rtDirCurICDebug ? Qt::Checked : Qt::Unchecked);
833    prefs.rtDirICCheckBox->setCheckState(m_rtDirICDebug ? Qt::Checked : Qt::Unchecked);
834    prefs.rtFileTabICCheckBox->setCheckState(m_rtFileTabICDebug ? Qt::Checked : Qt::Unchecked);
835    prefs.rtVerTabICCheckBox->setCheckState(m_rtVerTabICDebug ? Qt::Checked : Qt::Unchecked);
836    prefs.rtUpdateFTCheckBox->setCheckState(m_rtUpdateFTDebug ? Qt::Checked : Qt::Unchecked);
837    prefs.rtUpdateVTCheckBox->setCheckState(m_rtUpdateVTDebug ? Qt::Checked : Qt::Unchecked);
838    prefs.rtChecksCheckBox->setCheckState(m_rtChecksDebug ? Qt::Checked : Qt::Unchecked);
839    prefs.rtIconStateCheckBox->setCheckState(m_rtIconStateDebug ? Qt::Checked : Qt::Unchecked);
840    prefs.rtRestore1CheckBox->setCheckState(m_rtRestore1Debug ? Qt::Checked : Qt::Unchecked);
841    prefs.rtRestore2CheckBox->setCheckState(m_rtRestore2Debug ? Qt::Checked : Qt::Unchecked);
842    prefs.rtRestore3CheckBox->setCheckState(m_rtRestore3Debug ? Qt::Checked : Qt::Unchecked);
843    switch (ItemFormatterBase::getBytesConversion()) {
844    case ItemFormatterBase::BYTES_CONVERSION_NONE:
845       prefs.radioConvertOff->setChecked(Qt::Checked);
846       break;
847    case ItemFormatterBase::BYTES_CONVERSION_IEC:
848       prefs.radioConvertIEC->setChecked(Qt::Checked);
849       break;
850    default:
851       prefs.radioConvertStandard->setChecked(Qt::Checked);
852       break;
853    }
854    prefs.openPlotCheckBox->setCheckState(m_openPlot ? Qt::Checked : Qt::Unchecked);
855 #ifndef HAVE_QWT
856    prefs.openPlotCheckBox->setVisible(false);
857 #endif
858    prefs.openBrowserCheckBox->setCheckState(m_openBrowser ? Qt::Checked : Qt::Unchecked);
859    prefs.openDirStatCheckBox->setCheckState(m_openDirStat ? Qt::Checked : Qt::Unchecked);
860    prefs.exec();
861 }
862
863 /* Preferences dialog */
864 prefsDialog::prefsDialog()
865 {
866    setupUi(this);
867 }
868
869 void prefsDialog::accept()
870 {
871    this->hide();
872    mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
873    mainWin->m_connDebug = this->connDebug->checkState() == Qt::Checked;
874    mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
875    mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
876    mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
877    mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
878    mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
879    mainWin->m_recordLimitVal = this->recordSpinBox->value();
880    mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
881    mainWin->m_daysLimitVal = this->daysSpinBox->value();
882    mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
883    mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
884    mainWin->m_longList = this->executeLongCheckBox->checkState() == Qt::Checked;
885
886    mainWin->m_rtPopDirDebug = this->rtPopDirCheckBox->checkState() == Qt::Checked;
887    mainWin->m_rtDirCurICDebug = this->rtDirCurICCheckBox->checkState() == Qt::Checked;
888    mainWin->m_rtDirICDebug = this->rtDirICCheckBox->checkState() == Qt::Checked;
889    mainWin->m_rtFileTabICDebug = this->rtFileTabICCheckBox->checkState() == Qt::Checked;
890    mainWin->m_rtVerTabICDebug = this->rtVerTabICCheckBox->checkState() == Qt::Checked;
891    mainWin->m_rtUpdateFTDebug = this->rtUpdateFTCheckBox->checkState() == Qt::Checked;
892    mainWin->m_rtUpdateVTDebug = this->rtUpdateVTCheckBox->checkState() == Qt::Checked;
893    mainWin->m_rtChecksDebug = this->rtChecksCheckBox->checkState() == Qt::Checked;
894    mainWin->m_rtIconStateDebug = this->rtIconStateCheckBox->checkState() == Qt::Checked;
895    mainWin->m_rtRestore1Debug = this->rtRestore1CheckBox->checkState() == Qt::Checked;
896    mainWin->m_rtRestore2Debug = this->rtRestore2CheckBox->checkState() == Qt::Checked;
897    mainWin->m_rtRestore3Debug = this->rtRestore3CheckBox->checkState() == Qt::Checked;
898    if (this->radioConvertOff->isChecked()) {
899       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_NONE);
900    } else if (this->radioConvertIEC->isChecked()){
901       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_IEC);
902    } else {
903       ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_SI);
904    }
905    mainWin->m_openPlot = this->openPlotCheckBox->checkState() == Qt::Checked;
906    mainWin->m_openBrowser = this->openBrowserCheckBox->checkState() == Qt::Checked;
907    mainWin->m_openDirStat = this->openDirStatCheckBox->checkState() == Qt::Checked;
908
909    QSettings settings("www.bacula.org", "bat");
910    settings.beginGroup("Debug");
911    settings.setValue("commDebug", mainWin->m_commDebug);
912    settings.setValue("connDebug", mainWin->m_connDebug);
913    settings.setValue("displayAll", mainWin->m_displayAll);
914    settings.setValue("sqlDebug", mainWin->m_sqlDebug);
915    settings.setValue("commandDebug", mainWin->m_commandDebug);
916    settings.setValue("miscDebug", mainWin->m_miscDebug);
917    settings.endGroup();
918    settings.beginGroup("JobList");
919    settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
920    settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
921    settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
922    settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
923    settings.endGroup();
924    settings.beginGroup("Timers");
925    settings.setValue("checkMessages", mainWin->m_checkMessages);
926    settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
927    settings.endGroup();
928    settings.beginGroup("Misc");
929    settings.setValue("longList", mainWin->m_longList);
930    settings.setValue("byteConvert", ItemFormatterBase::getBytesConversion());
931    settings.setValue("openplot", mainWin->m_openPlot);
932    settings.setValue("openbrowser", mainWin->m_openBrowser);
933    settings.setValue("opendirstat", mainWin->m_openDirStat);
934    settings.endGroup();
935    settings.beginGroup("RestoreTree");
936    settings.setValue("rtPopDirDebug", mainWin->m_rtPopDirDebug);
937    settings.setValue("rtDirCurICDebug", mainWin->m_rtDirCurICDebug);
938    settings.setValue("rtDirCurICRetDebug", mainWin->m_rtDirICDebug);
939    settings.setValue("rtFileTabICDebug", mainWin->m_rtFileTabICDebug);
940    settings.setValue("rtVerTabICDebug", mainWin->m_rtVerTabICDebug);
941    settings.setValue("rtUpdateFTDebug", mainWin->m_rtUpdateFTDebug);
942    settings.setValue("rtUpdateVTDebug", mainWin->m_rtUpdateVTDebug);
943    settings.setValue("rtChecksDebug", mainWin->m_rtChecksDebug);
944    settings.setValue("rtIconStateDebug", mainWin->m_rtIconStateDebug);
945    settings.setValue("rtRestore1Debug", mainWin->m_rtRestore1Debug);
946    settings.setValue("rtRestore2Debug", mainWin->m_rtRestore2Debug);
947    settings.setValue("rtRestore3Debug", mainWin->m_rtRestore3Debug);
948    settings.endGroup();
949 }
950
951 void prefsDialog::reject()
952 {
953    this->hide();
954    mainWin->set_status(tr("Canceled"));
955 }
956
957 /* read preferences for the prefences dialog box */
958 void MainWin::readPreferences()
959 {
960    QSettings settings("www.bacula.org", "bat");
961    settings.beginGroup("Debug");
962    m_commDebug = settings.value("commDebug", false).toBool();
963    m_connDebug = settings.value("connDebug", false).toBool();
964    m_displayAll = settings.value("displayAll", false).toBool();
965    m_sqlDebug = settings.value("sqlDebug", false).toBool();
966    m_commandDebug = settings.value("commandDebug", false).toBool();
967    m_miscDebug = settings.value("miscDebug", false).toBool();
968    settings.endGroup();
969    settings.beginGroup("JobList");
970    m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
971    m_recordLimitVal = settings.value("recordLimitVal", 50).toInt();
972    m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
973    m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
974    settings.endGroup();
975    settings.beginGroup("Timers");
976    m_checkMessages = settings.value("checkMessages", false).toBool();
977    m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();
978    settings.endGroup();
979    settings.beginGroup("Misc");
980    m_longList = settings.value("longList", false).toBool();
981    ItemFormatterBase::setBytesConversion(
982          (ItemFormatterBase::BYTES_CONVERSION) settings.value("byteConvert", 
983          ItemFormatterBase::BYTES_CONVERSION_IEC).toInt());
984    m_openPlot = settings.value("openplot", false).toBool();
985    m_openBrowser = settings.value("openbrowser", false).toBool();
986    m_openDirStat = settings.value("opendirstat", false).toBool();
987    settings.endGroup();
988    settings.beginGroup("RestoreTree");
989    m_rtPopDirDebug = settings.value("rtPopDirDebug", false).toBool();
990    m_rtDirCurICDebug = settings.value("rtDirCurICDebug", false).toBool();
991    m_rtDirICDebug = settings.value("rtDirCurICRetDebug", false).toBool();
992    m_rtFileTabICDebug = settings.value("rtFileTabICDebug", false).toBool();
993    m_rtVerTabICDebug = settings.value("rtVerTabICDebug", false).toBool();
994    m_rtUpdateFTDebug = settings.value("rtUpdateFTDebug", false).toBool();
995    m_rtUpdateVTDebug = settings.value("rtUpdateVTDebug", false).toBool();
996    m_rtChecksDebug = settings.value("rtChecksDebug", false).toBool();
997    m_rtIconStateDebug = settings.value("rtIconStateDebug", false).toBool();
998    m_rtRestore1Debug = settings.value("rtRestore1Debug", false).toBool();
999    m_rtRestore2Debug = settings.value("rtRestore2Debug", false).toBool();
1000    m_rtRestore3Debug = settings.value("rtRestore3Debug", false).toBool();
1001    settings.endGroup();
1002 }
1003
1004 void MainWin::setMessageIcon()
1005 {
1006    if (m_currentConsole->is_messagesPending())
1007       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-pending.png")));
1008    else
1009       actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-new.png")));
1010 }
1011
1012 void MainWin::goToPreviousPage()
1013 {
1014    m_treeStackTrap = true;
1015    bool done = false;
1016    while (!done) {
1017       /* If stack list is emtpty, then done */
1018       if (m_treeWidgetStack.isEmpty()) {
1019          done = true;
1020       } else {
1021          QTreeWidgetItem* testItem = m_treeWidgetStack.takeLast();
1022          QTreeWidgetItemIterator it(treeWidget);
1023          /* lets avoid a segfault by setting an item current that no longer exists */
1024          while (*it) {
1025             if (*it == testItem) {
1026                if (testItem != treeWidget->currentItem()) {
1027                   treeWidget->setCurrentItem(testItem);
1028                   done = true;
1029                }
1030                break;
1031             }
1032             ++it;
1033          }
1034       }
1035    }
1036    m_treeStackTrap = false;
1037 }