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