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