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