2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
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.
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.
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
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.
32 * Main Window control for bat (qt-console)
34 * Kern Sibbald, January MMVII
39 #include "joblist/joblist.h"
40 #include "storage/storage.h"
41 #include "fileset/fileset.h"
42 #include "label/label.h"
45 #include "restore/restore.h"
46 #include "medialist/medialist.h"
47 #include "joblist/joblist.h"
48 #include "clients/clients.h"
49 #include "help/help.h"
52 * Daemon message callback
54 void message_callback(int /* type */, char *msg)
56 QMessageBox::warning(mainWin, "Bat", msg, QMessageBox::Ok);
59 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
61 m_dtformat = "yyyy-MM-dd HH:mm:ss";
63 setupUi(this); /* Setup UI defined by main.ui (designer) */
64 register_message_callback(message_callback);
67 treeWidget->setColumnCount(1);
68 treeWidget->setHeaderLabel("Select Page");
69 treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
81 foreach(Console *console, m_consoleHash) {
82 console->connect_dir();
84 m_currentConsole = (Console*)getFromHash(m_firstItem);
85 m_currentConsole->setCurrent();
87 QString directoryResourceName;
88 m_currentConsole->getDirResName(directoryResourceName);
89 Pmsg1(000, "Setting initial window to %s\n", directoryResourceName.toUtf8().data());
93 void MainWin::createPages()
96 QTreeWidgetItem *item, *topItem;
100 foreach_res(dir, R_DIRECTOR) {
102 /* Create console tree stacked widget item */
103 m_currentConsole = new Console(stackedWidget);
104 m_currentConsole->setDirRes(dir);
105 m_currentConsole->readSettings();
107 /* The top tree item representing the director */
108 topItem = createTopPage(dir->name());
109 topItem->setIcon(0, QIcon(":images/server.png"));
110 /* Set background to grey for ease of identification of inactive Director */
111 QBrush greyBrush(Qt::lightGray);
112 topItem->setBackground(0, greyBrush);
113 m_currentConsole->setDirectorTreeItem(topItem);
114 m_consoleHash.insert(topItem, m_currentConsole);
116 /* Create Tree Widget Item */
117 item = createPage("Console", topItem);
118 if (!m_firstItem){ m_firstItem = item; }
120 /* insert the cosole and tree widget item into the hashes */
121 hashInsert(item, m_currentConsole);
123 /* Set Color of treeWidgetItem for the console
124 * It will be set to green in the console class if the connection is made.
126 QBrush redBrush(Qt::red);
127 item->setForeground(0, redBrush);
128 m_currentConsole->dockPage();
131 * Create instances in alphabetic order of the rest
132 * of the classes that will by default exist under each Director.
134 // createPagebRestore();
137 QString emptymedia(""), emptyclient("");
138 createPageJobList(emptymedia, emptyclient, NULL);
139 createPageMediaList();
142 treeWidget->expandItem(topItem);
143 stackedWidget->setCurrentWidget(m_currentConsole);
149 * create an instance of the the brestore class on the stack
151 void MainWin::createPagebRestore()
153 bRestore* brestore = new bRestore();
154 brestore->dockPage();
158 * create an instance of the the medialist class on the stack
160 void MainWin::createPageMediaList()
162 MediaList* medialist = new MediaList();
163 medialist->dockPage();
167 * create an instance of the the joblist class on the stack
169 void MainWin::createPageJobList(QString &media, QString &client,
170 QTreeWidgetItem *parentTreeWidgetItem)
172 QTreeWidgetItem *holdItem;
174 /* save current tree widget item in case query produces no results */
175 holdItem = treeWidget->currentItem();
176 JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
178 /* If this is a query of jobs on a specific media */
179 if ((media != "") || (client != "")) {
180 joblist->setCurrent();
181 /* did query produce results, if not close window and set back to hold */
182 if (joblist->m_resultCount == 0) {
183 joblist->closeStackPage();
184 treeWidget->setCurrentItem(holdItem);
190 * create an instance of the the Clients class on the stack
192 void MainWin::createPageClients()
194 Clients* clients = new Clients();
199 * create an instance of the the storage class on the stack
201 void MainWin::createPageStorage()
203 Storage* storage = new Storage();
208 * create an instance of the the fileset class on the stack
210 void MainWin::createPageFileSet()
212 FileSet* fileset = new FileSet();
216 /* Create a root Tree Widget */
217 QTreeWidgetItem *MainWin::createTopPage(char *name)
219 QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
220 item->setText(0, name);
224 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
225 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
227 QTreeWidgetItem *item = new QTreeWidgetItem(parent);
228 item->setText(0, name);
233 * Handle up and down arrow keys for the command line
236 void MainWin::keyPressEvent(QKeyEvent *event)
238 if (m_cmd_history.size() == 0) {
242 switch (event->key()) {
244 if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
251 if (m_cmd_last == 0) {
255 if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
256 m_cmd_last = m_cmd_history.size() - 1;
265 lineEdit->setText(m_cmd_history[m_cmd_last]);
268 void MainWin::createConnections()
270 /* Connect signals to slots */
271 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
272 connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
273 connect(actionBat_Help, SIGNAL(triggered()), this, SLOT(help()));
274 connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
275 SLOT(treeItemClicked(QTreeWidgetItem *, int)));
276 connect(treeWidget, SIGNAL(
277 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
278 this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
279 connect(stackedWidget, SIGNAL(currentChanged(int)),
280 this, SLOT(stackItemChanged(int)));
281 connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
282 connect(actionLabel, SIGNAL(triggered()), this, SLOT(labelButtonClicked()));
283 connect(actionRun, SIGNAL(triggered()), this, SLOT(runButtonClicked()));
284 connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreButtonClicked()));
285 connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
286 connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
287 connect(actionClosePage, SIGNAL(triggered()), this, SLOT(closePage()));
288 connect(actionPreferences, SIGNAL(triggered()), this, SLOT(setPreferences()));
292 * Reimplementation of QWidget closeEvent virtual function
294 void MainWin::closeEvent(QCloseEvent *event)
297 foreach(Console *console, m_consoleHash){
298 console->writeSettings();
299 console->terminate();
302 foreach(Pages *page, m_pagehash) {
303 if (!page->isDocked())
308 void MainWin::writeSettings()
310 QSettings settings("bacula.org", "bat");
312 settings.beginGroup("MainWin");
313 settings.setValue("winSize", size());
314 settings.setValue("winPos", pos());
315 settings.setValue("state", saveState());
319 void MainWin::readSettings()
321 QSettings settings("bacula.org", "bat");
323 settings.beginGroup("MainWin");
324 resize(settings.value("winSize", QSize(1041, 801)).toSize());
325 move(settings.value("winPos", QPoint(200, 150)).toPoint());
326 restoreState(settings.value("state").toByteArray());
331 * This subroutine is called with an item in the Page Selection window
334 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
336 /* Is this a page that has been inserted into the hash */
337 if (getFromHash(item)) {
338 Pages* page = getFromHash(item);
339 int stackindex=stackedWidget->indexOf(page);
341 if (stackindex >= 0) {
342 stackedWidget->setCurrentWidget(page);
344 /* run the virtual function in case this class overrides it */
345 page->PgSeltreeWidgetClicked();
350 * Called with a change of the highlighed tree widget item in the page selector.
352 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
354 Pages *previousPage, *nextPage;
355 Console *previousConsole, *nextConsole;
357 /* first determine the next item */
359 /* knowing the treeWidgetItem, get the page from the hash */
360 nextPage = getFromHash(currentitem);
361 nextConsole = m_consoleHash.value(currentitem);
362 /* Is this a page that has been inserted into the hash */
364 nextConsole = nextPage->console();
365 /* then is it a treeWidgetItem representing a director */
366 } else if (nextConsole) {
367 /* let the next page BE the console */
368 nextPage = nextConsole;
370 /* Should never get here */
375 /* The Previous item */
377 /* this condition prevents a segfault. The first time there is no previousitem*/
379 /* knowing the treeWidgetItem, get the page from the hash */
380 previousPage = getFromHash(previousitem);
381 previousConsole = m_consoleHash.value(previousitem);
383 previousConsole = previousPage->console();
384 } else if (previousConsole) {
385 previousPage = previousConsole;
387 if ((previousPage) || (previousConsole)) {
388 if (nextConsole != previousConsole) {
389 /* remove connections to the current console */
390 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
391 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
392 disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
393 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
394 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
395 QBrush greyBrush(Qt::lightGray);
396 dirItem->setBackground(0, greyBrush);
398 /* make sure the close window and toggle dock options are removed */
399 treeWidget->removeAction(actionClosePage);
400 treeWidget->removeAction(actionToggleDock);
401 /* Is this a page that has been inserted into the hash */
403 foreach(QAction* pageaction, previousPage->m_contextActions) {
404 treeWidget->removeAction(pageaction);
410 /* process the current (next) item */
412 if ((nextPage) || (nextConsole)) {
413 if (nextConsole != previousConsole) {
414 /* make connections to the current console */
415 m_currentConsole = nextConsole;
416 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
417 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
418 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
419 connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
420 /* Set director's tree widget background to magenta for ease of identification */
421 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
422 QBrush magentaBrush(Qt::magenta);
423 dirItem->setBackground(0, magentaBrush);
425 /* set the value for the currently active console */
426 int stackindex = stackedWidget->indexOf(nextPage);
428 /* Is this page currently on the stack or is it undocked */
429 if (stackindex >= 0) {
430 /* put this page on the top of the stack */
431 stackedWidget->setCurrentIndex(stackindex);
433 /* it is undocked, raise it to the front */
436 /* for the page selectors menu action to dock or undock, set the text */
437 nextPage->setContextMenuDockText();
439 treeWidget->addAction(actionToggleDock);
440 /* if this page is closeable, then add that action */
441 if (nextPage->isCloseable()) {
442 treeWidget->addAction(actionClosePage);
445 /* Add the actions to the Page Selectors tree widget that are part of the
446 * current items list of desired actions regardless of whether on top of stack*/
447 treeWidget->addActions(nextPage->m_contextActions);
451 void MainWin::labelButtonClicked()
456 void MainWin::runButtonClicked()
461 void MainWin::restoreButtonClicked()
463 new prerestorePage();
467 * The user just finished typing a line in the command line edit box
469 void MainWin::input_line()
471 QString cmdStr = lineEdit->text(); /* Get the text */
472 lineEdit->clear(); /* clear the lineEdit box */
473 if (m_currentConsole->is_connected()) {
474 m_currentConsole->display_text(cmdStr + "\n");
475 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
477 set_status("Director not connected. Click on connect button.");
479 m_cmd_history.append(cmdStr);
481 if (treeWidget->currentItem() != getFromHash(m_currentConsole))
482 m_currentConsole->setCurrent();
486 void MainWin::about()
488 QMessageBox::about(this, tr("About bat"),
489 tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
490 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
491 "<p>The <b>bat</b> is an administrative console"
492 " interface to the Director."));
497 Help::displayFile("index.html");
500 void MainWin::set_statusf(const char *fmt, ...)
505 va_start(arg_ptr, fmt);
506 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
511 void MainWin::set_status_ready()
513 set_status(" Ready");
516 void MainWin::set_status(const char *buf)
518 statusBar()->showMessage(buf);
522 * Function to respond to the button bar button to undock
524 void MainWin::undockWindowButton()
526 Pages* page = (Pages*)stackedWidget->currentWidget();
527 page->togglePageDocking();
531 * Function to respond to action on page selector context menu to toggle the
532 * dock status of the window associated with the page selectors current
535 void MainWin::toggleDockContextWindow()
537 QTreeWidgetItem *currentitem = treeWidget->currentItem();
539 /* Is this a page that has been inserted into the hash */
540 if (getFromHash(currentitem)) {
541 Pages* page = getFromHash(currentitem);
542 page->togglePageDocking();
547 * This function is called when the stack item is changed. Call
548 * the virtual function here. Avoids a window being undocked leaving
549 * a window at the top of the stack unpopulated.
551 void MainWin::stackItemChanged(int)
553 Pages* page = (Pages*)stackedWidget->currentWidget();
554 /* run the virtual function in case this class overrides it */
555 page->currentStackItem();
559 * Function to simplify insertion of QTreeWidgetItem <-> Page association
560 * into a double direction hash.
562 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
564 m_pagehash.insert(item, page);
565 m_widgethash.insert(page, item);
569 * Function to simplify removal of QTreeWidgetItem <-> Page association
570 * into a double direction hash.
572 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
574 /* I had all sorts of return status checking code here. Do we have a log
575 * level capability in bat. I would have left it in but it used printf's
576 * and it should really be some kind of log level facility ???
577 * ******FIXME********/
578 m_pagehash.remove(item);
579 m_widgethash.remove(page);
583 * Function to retrieve a Page* when the item in the page selector's tree is
586 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
588 return m_pagehash.value(item);
592 * Function to retrieve the page selectors tree widget item when the page is
595 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
597 return m_widgethash.value(page);
601 * Function to respond to action on page selector context menu to close the
604 void MainWin::closePage()
606 QTreeWidgetItem *currentitem = treeWidget->currentItem();
608 /* Is this a page that has been inserted into the hash */
609 if (getFromHash(currentitem)) {
610 Pages* page = getFromHash(currentitem);
611 if (page->isCloseable()) {
612 page->closeStackPage();
617 /* Quick function to return the current console */
618 Console *MainWin::currentConsole()
620 return m_currentConsole;
622 /* Quick function to return the tree item for the director */
623 QTreeWidgetItem *MainWin::currentTopItem()
625 return m_currentConsole->directorTreeItem();
628 /* Preferences menu item clicked */
629 void MainWin::setPreferences()
632 prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
633 prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
634 prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
635 prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
636 prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
637 prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
638 prefs.recordSpinBox->setValue(m_recordLimitVal);
639 prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
640 prefs.daysSpinBox->setValue(m_daysLimitVal);
641 prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
642 prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
646 /* Preferences dialog */
647 prefsDialog::prefsDialog()
652 void prefsDialog::accept()
655 mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
656 mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
657 mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
658 mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
659 mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
660 mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
661 mainWin->m_recordLimitVal = this->recordSpinBox->value();
662 mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
663 mainWin->m_daysLimitVal = this->daysSpinBox->value();
664 mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
665 mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
666 QSettings settings("www.bacula.org", "bat");
667 settings.beginGroup("Debug");
668 settings.setValue("commDebug", mainWin->m_commDebug);
669 settings.setValue("displayAll", mainWin->m_displayAll);
670 settings.setValue("sqlDebug", mainWin->m_sqlDebug);
671 settings.setValue("commandDebug", mainWin->m_commandDebug);
672 settings.setValue("miscDebug", mainWin->m_miscDebug);
674 settings.beginGroup("JobList");
675 settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
676 settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
677 settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
678 settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
680 settings.beginGroup("Messages");
681 settings.setValue("checkMessages", mainWin->m_checkMessages);
682 settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
684 foreach(Console *console, mainWin->m_consoleHash) {
685 console->startTimer();
689 void prefsDialog::reject()
692 mainWin->set_status("Canceled");
695 /* read preferences for the prefences dialog box */
696 void MainWin::readPreferences()
698 QSettings settings("www.bacula.org", "bat");
699 settings.beginGroup("Debug");
700 m_commDebug = settings.value("commDebug", false).toBool();
701 m_displayAll = settings.value("displayAll", false).toBool();
702 m_sqlDebug = settings.value("sqlDebug", false).toBool();
703 m_commandDebug = settings.value("commandDebug", false).toBool();
704 m_miscDebug = settings.value("miscDebug", false).toBool();
706 settings.beginGroup("JobList");
707 m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
708 m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
709 m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
710 m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
712 settings.beginGroup("Messages");
713 m_checkMessages = settings.value("checkMessages", false).toBool();
714 m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();