]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
This commit puts prefences for debuggin output and prefences for the joblist
[bacula/bacula] / bacula / src / qt-console / mainwin.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 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 plus additions
11    that are listed 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 John Walker.
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 "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
50 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
51 {
52
53    mainWin = this;
54    setupUi(this);                     /* Setup UI defined by main.ui (designer) */
55    readPreferences();
56    treeWidget->clear();
57    treeWidget->setColumnCount(1);
58    treeWidget->setHeaderLabel("Select Page");
59    treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
60
61    createPages();
62
63    resetFocus();
64
65    createConnections();
66
67    this->show();
68
69    readSettings();
70
71    foreach(Console *console, m_consoleHash) {
72       console->connect();
73    }
74    m_currentConsole = (Console*)getFromHash(m_firstItem);
75    m_currentConsole->setCurrent();
76    if (m_miscDebug) {
77       QString directoryResourceName;
78       m_currentConsole->getDirResName(directoryResourceName);
79       Pmsg1(000, "Setting initial window to %s\n", directoryResourceName.toUtf8().data());
80    }
81 }
82
83 void MainWin::createPages()
84 {
85    DIRRES *dir;
86    QTreeWidgetItem *item, *topItem;
87    m_firstItem = NULL;
88
89    LockRes();
90    foreach_res(dir, R_DIRECTOR) {
91
92       /* Create console tree stacked widget item */
93       m_currentConsole = new Console(stackedWidget);
94       m_currentConsole->setDirRes(dir);
95       m_currentConsole->readSettings();
96
97       /* The top tree item representing the director */
98       topItem = createTopPage(dir->name());
99       topItem->setIcon(0, QIcon(":images/server.png"));
100       /* Set background to grey for ease of identification of inactive dirfector */
101       QBrush greyBrush(Qt::lightGray);
102       topItem->setBackground(0, greyBrush);
103       m_currentConsole->setDirectorTreeItem(topItem);
104       m_consoleHash.insert(topItem, m_currentConsole);
105
106       /* Create Tree Widget Item */
107       item = createPage("Console", topItem);
108       if (!m_firstItem){ m_firstItem = item; }
109
110       /* insert the cosole and tree widget item into the hashes */
111       hashInsert(item, m_currentConsole);
112
113       /* Set Color of treeWidgetItem for the console
114       * It will be set to green in the console class if the connection is made.
115       */
116       QBrush redBrush(Qt::red);
117       item->setForeground(0, redBrush);
118       m_currentConsole->dockPage();
119
120       /* create instances of the rest of the classes that will by default exist
121       * under each director */
122 //    createPagebRestore();
123       createPageMediaList();
124       QString emptymedia(""), emptyclient("");
125       createPageJobList(emptymedia, emptyclient, NULL);
126       createPageClients();
127       createPageStorage();
128       createPageFileSet();
129
130       treeWidget->expandItem(topItem);
131       stackedWidget->setCurrentWidget(m_currentConsole);
132    }
133    UnlockRes();
134 }
135
136 /*
137  * create an instance of the the brestore class on the stack
138  */
139 void MainWin::createPagebRestore()
140 {
141    bRestore* brestore = new bRestore();
142    brestore->dockPage();
143 }
144
145 /*
146  * create an instance of the the medialist class on the stack
147  */
148 void MainWin::createPageMediaList()
149 {
150    MediaList* medialist = new MediaList();
151    medialist->dockPage();
152 }
153
154 /*
155  * create an instance of the the joblist class on the stack
156  */
157 void MainWin::createPageJobList(QString &media, QString &client,
158               QTreeWidgetItem *parentTreeWidgetItem)
159 {
160    QTreeWidgetItem *holdItem;
161
162    /* save current tree widget item in case query produces no results */
163    holdItem = treeWidget->currentItem();
164    JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
165    joblist->dockPage();
166    /* If this is a query of jobs on a specific media */
167    if ((media != "") || (client != "")) {
168       joblist->setCurrent();
169       /* did query produce results, if not close window and set back to hold */
170       if (joblist->m_resultCount == 0) {
171          joblist->closeStackPage();
172          treeWidget->setCurrentItem(holdItem);
173       }
174    }
175 }
176
177 /*
178  * create an instance of the the Clients class on the stack
179  */
180 void MainWin::createPageClients()
181 {
182    Clients* clients = new Clients();
183    clients->dockPage();
184 }
185
186 /*
187  * create an instance of the the storage class on the stack
188  */
189 void MainWin::createPageStorage()
190 {
191    Storage* storage = new Storage();
192    storage->dockPage();
193 }
194
195 /*
196  * create an instance of the the fileset class on the stack
197  */
198 void MainWin::createPageFileSet()
199 {
200    FileSet* fileset = new FileSet();
201    fileset->dockPage();
202 }
203
204 /* Create a root Tree Widget */
205 QTreeWidgetItem *MainWin::createTopPage(char *name)
206 {
207    QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
208    item->setText(0, name);
209    return item;
210 }
211
212 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
213 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
214 {
215    QTreeWidgetItem *item = new QTreeWidgetItem(parent);
216    item->setText(0, name);
217    return item;
218 }
219
220 /*
221  * Handle up and down arrow keys for the command line
222  *  history.
223  */
224 void MainWin::keyPressEvent(QKeyEvent *event)
225 {
226    if (m_cmd_history.size() == 0) {
227       event->ignore();
228       return;
229    }
230    switch (event->key()) {
231    case Qt::Key_Down:
232       if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
233          event->ignore();
234          return;
235       }
236       m_cmd_last++;
237       break;
238    case Qt::Key_Up:
239       if (m_cmd_last == 0) {
240          event->ignore();
241          return;
242       }
243       if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
244          m_cmd_last = m_cmd_history.size() - 1;
245       } else {
246          m_cmd_last--;
247       }
248       break;
249    default:
250       event->ignore();
251       return;
252    }
253    lineEdit->setText(m_cmd_history[m_cmd_last]);
254 }
255
256 void MainWin::createConnections()
257 {
258    /* Connect signals to slots */
259    connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
260    connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
261    connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, 
262            SLOT(treeItemClicked(QTreeWidgetItem *, int)));
263    connect(treeWidget, SIGNAL(
264            currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
265            this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
266    connect(stackedWidget, SIGNAL(currentChanged(int)),
267            this, SLOT(stackItemChanged(int)));
268    connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
269    connect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
270    connect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
271    connect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
272    connect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
273    connect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
274    connect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closePage()));
275    connect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
276 }
277
278 /* 
279  * Reimplementation of QWidget closeEvent virtual function   
280  */
281 void MainWin::closeEvent(QCloseEvent *event)
282 {
283    writeSettings();
284    foreach(Console *console, m_consoleHash){
285       console->writeSettings();
286       console->terminate();
287    }
288    event->accept();
289    foreach(Pages *page, m_pagehash) {
290       if (!page->isDocked())
291          page->close();
292    }
293 }
294
295 void MainWin::writeSettings()
296 {
297    QSettings settings("bacula.org", "bat");
298
299    settings.beginGroup("MainWin");
300    settings.setValue("winSize", size());
301    settings.setValue("winPos", pos());
302    settings.endGroup();
303 }
304
305 void MainWin::readSettings()
306
307    QSettings settings("bacula.org", "bat");
308
309    settings.beginGroup("MainWin");
310    resize(settings.value("winSize", QSize(1041, 801)).toSize());
311    move(settings.value("winPos", QPoint(200, 150)).toPoint());
312    settings.endGroup();
313 }
314
315 /*
316  * This subroutine is called with an item in the Page Selection window
317  *   is clicked 
318  */
319 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
320 {
321    /* Is this a page that has been inserted into the hash  */
322    if (getFromHash(item)) {
323       Pages* page = getFromHash(item);
324       int stackindex=stackedWidget->indexOf(page);
325
326       if (stackindex >= 0) {
327          stackedWidget->setCurrentWidget(page);
328       }
329       /* run the virtual function in case this class overrides it */
330       page->PgSeltreeWidgetClicked();
331    }
332 }
333
334 /*
335  * Called with a change of the highlighed tree widget item in the page selector.
336  */
337 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
338 {
339    Pages *previousPage, *nextPage;
340    Console *previousConsole, *nextConsole;
341
342    /* first determine the next item */
343
344    /* knowing the treeWidgetItem, get the page from the hash */
345    nextPage = getFromHash(currentitem);
346    nextConsole = m_consoleHash.value(currentitem);
347    /* Is this a page that has been inserted into the hash  */
348    if (nextPage) {
349       nextConsole = nextPage->console();
350       /* then is it a treeWidgetItem representing a director */
351    } else if (nextConsole) {
352       /* let the next page BE the console */
353       nextPage = nextConsole;
354    } else {
355       /* Should never get here */
356       nextPage = NULL;
357       nextConsole = NULL;
358    }
359           
360    /* The Previous item */
361
362    /* this condition prevents a segfault.  The first time there is no previousitem*/
363    if (previousitem) {
364       /* knowing the treeWidgetItem, get the page from the hash */
365       previousPage = getFromHash(previousitem);
366       previousConsole = m_consoleHash.value(previousitem);
367       if (previousPage) {
368          previousConsole = previousPage->console();
369       } else if (previousConsole) {
370          previousPage = previousConsole;
371       }
372       if ((previousPage) || (previousConsole)) {
373          if (nextConsole != previousConsole) {
374             /* remove connections to the current console */
375             disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
376             disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
377             disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
378             disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
379             QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
380             QBrush greyBrush(Qt::lightGray);
381             dirItem->setBackground(0, greyBrush);
382          }
383          /* make sure the close window and toggle dock options are removed */
384          treeWidget->removeAction(actionClosePage);
385          treeWidget->removeAction(actionToggleDock);
386          /* Is this a page that has been inserted into the hash  */
387          if (previousPage) {
388             foreach(QAction* pageaction, previousPage->m_contextActions) {
389                treeWidget->removeAction(pageaction);
390             }
391          } 
392       }
393    }
394
395    /* process the current (next) item */
396    
397    if ((nextPage) || (nextConsole)) {
398       if (nextConsole != previousConsole) {
399          /* make connections to the current console */
400          m_currentConsole = nextConsole;
401          connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
402          connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
403          connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
404          connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
405          /* Set director's tree widget background to magenta for ease of identification */
406          QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
407          QBrush magentaBrush(Qt::magenta);
408          dirItem->setBackground(0, magentaBrush);
409       }
410       /* set the value for the currently active console */
411       int stackindex = stackedWidget->indexOf(nextPage);
412    
413       /* Is this page currently on the stack or is it undocked */
414       if (stackindex >= 0) {
415          /* put this page on the top of the stack */
416          stackedWidget->setCurrentIndex(stackindex);
417       } else {
418          /* it is undocked, raise it to the front */
419          nextPage->raise();
420       }
421       /* for the page selectors menu action to dock or undock, set the text */
422       nextPage->setContextMenuDockText();
423
424       treeWidget->addAction(actionToggleDock);
425       /* if this page is closeable, then add that action */
426       if (nextPage->isCloseable()) {
427          treeWidget->addAction(actionClosePage);
428       }
429
430       /* Add the actions to the Page Selectors tree widget that are part of the
431        * current items list of desired actions regardless of whether on top of stack*/
432       treeWidget->addActions(nextPage->m_contextActions);
433    }
434 }
435
436 void MainWin::labelButtonClicked() 
437 {
438    new labelPage();
439 }
440
441 void MainWin::runButtonClicked() 
442 {
443    new runPage();
444 }
445
446 void MainWin::restoreButtonClicked() 
447 {
448    new prerestorePage();
449 }
450
451 /*
452  * The user just finished typing a line in the command line edit box
453  */
454 void MainWin::input_line()
455 {
456    QString cmdStr = lineEdit->text();    /* Get the text */
457    lineEdit->clear();                    /* clear the lineEdit box */
458    if (m_currentConsole->is_connected()) {
459       m_currentConsole->display_text(cmdStr + "\n");
460       m_currentConsole->write_dir(cmdStr.toUtf8().data());         /* send to dir */
461    } else {
462       set_status("Director not connected. Click on connect button.");
463    }
464    m_cmd_history.append(cmdStr);
465    m_cmd_last = -1;
466    if (treeWidget->currentItem() != getFromHash(m_currentConsole))
467       m_currentConsole->setCurrent();
468 }
469
470
471 void MainWin::about()
472 {
473    QMessageBox::about(this, tr("About bat"),
474       tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
475          "<p>Copyright &copy; " BYEAR " Free Software Foundation Europe e.V."
476          "<p>The <b>bat</b> is an administrative console"
477          " interface to the Director."));
478 }
479
480 void MainWin::set_statusf(const char *fmt, ...)
481 {
482    va_list arg_ptr;
483    char buf[1000];
484    int len;
485    va_start(arg_ptr, fmt);
486    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
487    va_end(arg_ptr);
488    set_status(buf);
489 }
490
491 void MainWin::set_status_ready()
492 {
493    set_status(" Ready");
494 }
495
496 void MainWin::set_status(const char *buf)
497 {
498    statusBar()->showMessage(buf);
499 }
500
501 /*
502  * Function to respond to the button bar button to undock
503  */
504 void MainWin::undockWindowButton()
505 {
506    Pages* page = (Pages*)stackedWidget->currentWidget();
507    page->togglePageDocking();
508 }
509
510 /*
511  * Function to respond to action on page selector context menu to toggle the 
512  * dock status of the window associated with the page selectors current
513  * tree widget item.
514  */
515 void MainWin::toggleDockContextWindow()
516 {
517    QTreeWidgetItem *currentitem = treeWidget->currentItem();
518    
519    /* Is this a page that has been inserted into the hash  */
520    if (getFromHash(currentitem)) {
521       Pages* page = getFromHash(currentitem);
522       page->togglePageDocking();
523    }
524 }
525
526 /*
527  * This function is called when the stack item is changed.  Call
528  * the virtual function here.  Avoids a window being undocked leaving
529  * a window at the top of the stack unpopulated.
530  */
531 void MainWin::stackItemChanged(int)
532 {
533    Pages* page = (Pages*)stackedWidget->currentWidget();
534    /* run the virtual function in case this class overrides it */
535    page->currentStackItem();
536 }
537
538 /*
539  * Function to simplify insertion of QTreeWidgetItem <-> Page association
540  * into a double direction hash.
541  */
542 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
543 {
544    m_pagehash.insert(item, page);
545    m_widgethash.insert(page, item);
546 }
547
548 /*
549  * Function to simplify removal of QTreeWidgetItem <-> Page association
550  * into a double direction hash.
551  */
552 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
553 {
554    /* I had all sorts of return status checking code here.  Do we have a log
555     * level capability in bat.  I would have left it in but it used printf's
556     * and it should really be some kind of log level facility ???
557     * ******FIXME********/
558    m_pagehash.remove(item);
559    m_widgethash.remove(page);
560 }
561
562 /*
563  * Function to retrieve a Page* when the item in the page selector's tree is
564  * known.
565  */
566 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
567 {
568    return m_pagehash.value(item);
569 }
570
571 /*
572  * Function to retrieve the page selectors tree widget item when the page is
573  * known.
574  */
575 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
576 {
577    return m_widgethash.value(page);
578 }
579
580 /*
581  * Function to respond to action on page selector context menu to close the
582  * current window.
583  */
584 void MainWin::closePage()
585 {
586    QTreeWidgetItem *currentitem = treeWidget->currentItem();
587    
588    /* Is this a page that has been inserted into the hash  */
589    if (getFromHash(currentitem)) {
590       Pages* page = getFromHash(currentitem);
591       if (page->isCloseable()) {
592          page->closeStackPage();
593       }
594    }
595 }
596
597 /* Quick function to return the current console */
598 Console *MainWin::currentConsole()
599 {
600    return m_currentConsole;
601 }
602 /* Quick function to return the tree item for the director */
603 QTreeWidgetItem *MainWin::currentTopItem()
604 {
605    return m_currentConsole->directorTreeItem();
606 }
607
608 /* Preferences menu item clicked */
609 void MainWin::setPreferences()
610 {
611    prefsDialog prefs;
612    prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
613    prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
614    prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
615    prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
616    prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
617    prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
618    prefs.recordSpinBox->setValue(m_recordLimitVal);
619    prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
620    prefs.daysSpinBox->setValue(m_daysLimitVal);
621    prefs.exec();
622 }
623
624 /* Preferences dialog */
625 prefsDialog::prefsDialog()
626 {
627    setupUi(this);
628 }
629
630 void prefsDialog::accept()
631 {
632    this->hide();
633    mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
634    mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
635    mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
636    mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
637    mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
638    mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
639    mainWin->m_recordLimitVal = this->recordSpinBox->value();
640    mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
641    mainWin->m_daysLimitVal = this->daysSpinBox->value();
642    QSettings settings("www.bacula.org", "bat");
643    settings.beginGroup("Messages");
644    settings.setValue("commDebug", mainWin->m_commDebug);
645    settings.setValue("displayAll", mainWin->m_displayAll);
646    settings.setValue("sqlDebug", mainWin->m_sqlDebug);
647    settings.setValue("commandDebug", mainWin->m_commandDebug);
648    settings.setValue("miscDebug", mainWin->m_miscDebug);
649    settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
650    settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
651    settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
652    settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
653    settings.endGroup();
654 }
655
656 void prefsDialog::reject()
657 {
658    this->hide();
659    mainWin->set_status("Canceled");
660 }
661
662 /* read preferences for the prefences dialog box */
663 void MainWin::readPreferences()
664 {
665    QSettings settings("www.bacula.org", "bat");
666    settings.beginGroup("Messages");
667    m_commDebug = settings.value("commDebug", false).toBool();
668    m_displayAll = settings.value("displayAll", false).toBool();
669    m_sqlDebug = settings.value("sqlDebug", false).toBool();
670    m_commandDebug = settings.value("commandDebug", false).toBool();
671    m_miscDebug = settings.value("miscDebug", false).toBool();
672    m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
673    m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
674    m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
675    m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
676    settings.endGroup();
677 }