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