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"
51 * Daemon message callback
53 void message_callback(int /* type */, char *msg)
55 QMessageBox::warning(mainWin, "Bat", msg, QMessageBox::Ok);
58 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
60 m_dtformat = "yyyy-MM-dd HH:mm:ss";
62 setupUi(this); /* Setup UI defined by main.ui (designer) */
63 register_message_callback(message_callback);
66 treeWidget->setColumnCount(1);
67 treeWidget->setHeaderLabel("Select Page");
68 treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
80 foreach(Console *console, m_consoleHash) {
83 m_currentConsole = (Console*)getFromHash(m_firstItem);
84 m_currentConsole->setCurrent();
86 QString directoryResourceName;
87 m_currentConsole->getDirResName(directoryResourceName);
88 Pmsg1(000, "Setting initial window to %s\n", directoryResourceName.toUtf8().data());
92 void MainWin::createPages()
95 QTreeWidgetItem *item, *topItem;
99 foreach_res(dir, R_DIRECTOR) {
101 /* Create console tree stacked widget item */
102 m_currentConsole = new Console(stackedWidget);
103 m_currentConsole->setDirRes(dir);
104 m_currentConsole->readSettings();
106 /* The top tree item representing the director */
107 topItem = createTopPage(dir->name());
108 topItem->setIcon(0, QIcon(":images/server.png"));
109 /* Set background to grey for ease of identification of inactive Director */
110 QBrush greyBrush(Qt::lightGray);
111 topItem->setBackground(0, greyBrush);
112 m_currentConsole->setDirectorTreeItem(topItem);
113 m_consoleHash.insert(topItem, m_currentConsole);
115 /* Create Tree Widget Item */
116 item = createPage("Console", topItem);
117 if (!m_firstItem){ m_firstItem = item; }
119 /* insert the cosole and tree widget item into the hashes */
120 hashInsert(item, m_currentConsole);
122 /* Set Color of treeWidgetItem for the console
123 * It will be set to green in the console class if the connection is made.
125 QBrush redBrush(Qt::red);
126 item->setForeground(0, redBrush);
127 m_currentConsole->dockPage();
130 * Create instances in alphabetic order of the rest
131 * of the classes that will by default exist under each Director.
133 // createPagebRestore();
136 QString emptymedia(""), emptyclient("");
137 createPageJobList(emptymedia, emptyclient, NULL);
138 createPageMediaList();
141 treeWidget->expandItem(topItem);
142 stackedWidget->setCurrentWidget(m_currentConsole);
148 * create an instance of the the brestore class on the stack
150 void MainWin::createPagebRestore()
152 bRestore* brestore = new bRestore();
153 brestore->dockPage();
157 * create an instance of the the medialist class on the stack
159 void MainWin::createPageMediaList()
161 MediaList* medialist = new MediaList();
162 medialist->dockPage();
166 * create an instance of the the joblist class on the stack
168 void MainWin::createPageJobList(QString &media, QString &client,
169 QTreeWidgetItem *parentTreeWidgetItem)
171 QTreeWidgetItem *holdItem;
173 /* save current tree widget item in case query produces no results */
174 holdItem = treeWidget->currentItem();
175 JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
177 /* If this is a query of jobs on a specific media */
178 if ((media != "") || (client != "")) {
179 joblist->setCurrent();
180 /* did query produce results, if not close window and set back to hold */
181 if (joblist->m_resultCount == 0) {
182 joblist->closeStackPage();
183 treeWidget->setCurrentItem(holdItem);
189 * create an instance of the the Clients class on the stack
191 void MainWin::createPageClients()
193 Clients* clients = new Clients();
198 * create an instance of the the storage class on the stack
200 void MainWin::createPageStorage()
202 Storage* storage = new Storage();
207 * create an instance of the the fileset class on the stack
209 void MainWin::createPageFileSet()
211 FileSet* fileset = new FileSet();
215 /* Create a root Tree Widget */
216 QTreeWidgetItem *MainWin::createTopPage(char *name)
218 QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
219 item->setText(0, name);
223 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
224 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
226 QTreeWidgetItem *item = new QTreeWidgetItem(parent);
227 item->setText(0, name);
232 * Handle up and down arrow keys for the command line
235 void MainWin::keyPressEvent(QKeyEvent *event)
237 if (m_cmd_history.size() == 0) {
241 switch (event->key()) {
243 if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
250 if (m_cmd_last == 0) {
254 if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
255 m_cmd_last = m_cmd_history.size() - 1;
264 lineEdit->setText(m_cmd_history[m_cmd_last]);
267 void MainWin::createConnections()
269 /* Connect signals to slots */
270 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
271 connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
272 connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
273 SLOT(treeItemClicked(QTreeWidgetItem *, int)));
274 connect(treeWidget, SIGNAL(
275 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
276 this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
277 connect(stackedWidget, SIGNAL(currentChanged(int)),
278 this, SLOT(stackItemChanged(int)));
279 connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
280 connect(actionLabel, SIGNAL(triggered()), this, SLOT(labelButtonClicked()));
281 connect(actionRun, SIGNAL(triggered()), this, SLOT(runButtonClicked()));
282 connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreButtonClicked()));
283 connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
284 connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
285 connect(actionClosePage, SIGNAL(triggered()), this, SLOT(closePage()));
286 connect(actionPreferences, SIGNAL(triggered()), this, SLOT(setPreferences()));
290 * Reimplementation of QWidget closeEvent virtual function
292 void MainWin::closeEvent(QCloseEvent *event)
295 foreach(Console *console, m_consoleHash){
296 console->writeSettings();
297 console->terminate();
300 foreach(Pages *page, m_pagehash) {
301 if (!page->isDocked())
306 void MainWin::writeSettings()
308 QSettings settings("bacula.org", "bat");
310 settings.beginGroup("MainWin");
311 settings.setValue("winSize", size());
312 settings.setValue("winPos", pos());
313 settings.setValue("state", saveState());
317 void MainWin::readSettings()
319 QSettings settings("bacula.org", "bat");
321 settings.beginGroup("MainWin");
322 resize(settings.value("winSize", QSize(1041, 801)).toSize());
323 move(settings.value("winPos", QPoint(200, 150)).toPoint());
324 restoreState(settings.value("state").toByteArray());
329 * This subroutine is called with an item in the Page Selection window
332 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
334 /* Is this a page that has been inserted into the hash */
335 if (getFromHash(item)) {
336 Pages* page = getFromHash(item);
337 int stackindex=stackedWidget->indexOf(page);
339 if (stackindex >= 0) {
340 stackedWidget->setCurrentWidget(page);
342 /* run the virtual function in case this class overrides it */
343 page->PgSeltreeWidgetClicked();
348 * Called with a change of the highlighed tree widget item in the page selector.
350 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
352 Pages *previousPage, *nextPage;
353 Console *previousConsole, *nextConsole;
355 /* first determine the next item */
357 /* knowing the treeWidgetItem, get the page from the hash */
358 nextPage = getFromHash(currentitem);
359 nextConsole = m_consoleHash.value(currentitem);
360 /* Is this a page that has been inserted into the hash */
362 nextConsole = nextPage->console();
363 /* then is it a treeWidgetItem representing a director */
364 } else if (nextConsole) {
365 /* let the next page BE the console */
366 nextPage = nextConsole;
368 /* Should never get here */
373 /* The Previous item */
375 /* this condition prevents a segfault. The first time there is no previousitem*/
377 /* knowing the treeWidgetItem, get the page from the hash */
378 previousPage = getFromHash(previousitem);
379 previousConsole = m_consoleHash.value(previousitem);
381 previousConsole = previousPage->console();
382 } else if (previousConsole) {
383 previousPage = previousConsole;
385 if ((previousPage) || (previousConsole)) {
386 if (nextConsole != previousConsole) {
387 /* remove connections to the current console */
388 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
389 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
390 disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
391 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
392 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
393 QBrush greyBrush(Qt::lightGray);
394 dirItem->setBackground(0, greyBrush);
396 /* make sure the close window and toggle dock options are removed */
397 treeWidget->removeAction(actionClosePage);
398 treeWidget->removeAction(actionToggleDock);
399 /* Is this a page that has been inserted into the hash */
401 foreach(QAction* pageaction, previousPage->m_contextActions) {
402 treeWidget->removeAction(pageaction);
408 /* process the current (next) item */
410 if ((nextPage) || (nextConsole)) {
411 if (nextConsole != previousConsole) {
412 /* make connections to the current console */
413 m_currentConsole = nextConsole;
414 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
415 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
416 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
417 connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
418 /* Set director's tree widget background to magenta for ease of identification */
419 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
420 QBrush magentaBrush(Qt::magenta);
421 dirItem->setBackground(0, magentaBrush);
423 /* set the value for the currently active console */
424 int stackindex = stackedWidget->indexOf(nextPage);
426 /* Is this page currently on the stack or is it undocked */
427 if (stackindex >= 0) {
428 /* put this page on the top of the stack */
429 stackedWidget->setCurrentIndex(stackindex);
431 /* it is undocked, raise it to the front */
434 /* for the page selectors menu action to dock or undock, set the text */
435 nextPage->setContextMenuDockText();
437 treeWidget->addAction(actionToggleDock);
438 /* if this page is closeable, then add that action */
439 if (nextPage->isCloseable()) {
440 treeWidget->addAction(actionClosePage);
443 /* Add the actions to the Page Selectors tree widget that are part of the
444 * current items list of desired actions regardless of whether on top of stack*/
445 treeWidget->addActions(nextPage->m_contextActions);
449 void MainWin::labelButtonClicked()
454 void MainWin::runButtonClicked()
459 void MainWin::restoreButtonClicked()
461 new prerestorePage();
465 * The user just finished typing a line in the command line edit box
467 void MainWin::input_line()
469 QString cmdStr = lineEdit->text(); /* Get the text */
470 lineEdit->clear(); /* clear the lineEdit box */
471 if (m_currentConsole->is_connected()) {
472 m_currentConsole->display_text(cmdStr + "\n");
473 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
475 set_status("Director not connected. Click on connect button.");
477 m_cmd_history.append(cmdStr);
479 if (treeWidget->currentItem() != getFromHash(m_currentConsole))
480 m_currentConsole->setCurrent();
484 void MainWin::about()
486 QMessageBox::about(this, tr("About bat"),
487 tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
488 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
489 "<p>The <b>bat</b> is an administrative console"
490 " interface to the Director."));
493 void MainWin::set_statusf(const char *fmt, ...)
498 va_start(arg_ptr, fmt);
499 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
504 void MainWin::set_status_ready()
506 set_status(" Ready");
509 void MainWin::set_status(const char *buf)
511 statusBar()->showMessage(buf);
515 * Function to respond to the button bar button to undock
517 void MainWin::undockWindowButton()
519 Pages* page = (Pages*)stackedWidget->currentWidget();
520 page->togglePageDocking();
524 * Function to respond to action on page selector context menu to toggle the
525 * dock status of the window associated with the page selectors current
528 void MainWin::toggleDockContextWindow()
530 QTreeWidgetItem *currentitem = treeWidget->currentItem();
532 /* Is this a page that has been inserted into the hash */
533 if (getFromHash(currentitem)) {
534 Pages* page = getFromHash(currentitem);
535 page->togglePageDocking();
540 * This function is called when the stack item is changed. Call
541 * the virtual function here. Avoids a window being undocked leaving
542 * a window at the top of the stack unpopulated.
544 void MainWin::stackItemChanged(int)
546 Pages* page = (Pages*)stackedWidget->currentWidget();
547 /* run the virtual function in case this class overrides it */
548 page->currentStackItem();
552 * Function to simplify insertion of QTreeWidgetItem <-> Page association
553 * into a double direction hash.
555 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
557 m_pagehash.insert(item, page);
558 m_widgethash.insert(page, item);
562 * Function to simplify removal of QTreeWidgetItem <-> Page association
563 * into a double direction hash.
565 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
567 /* I had all sorts of return status checking code here. Do we have a log
568 * level capability in bat. I would have left it in but it used printf's
569 * and it should really be some kind of log level facility ???
570 * ******FIXME********/
571 m_pagehash.remove(item);
572 m_widgethash.remove(page);
576 * Function to retrieve a Page* when the item in the page selector's tree is
579 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
581 return m_pagehash.value(item);
585 * Function to retrieve the page selectors tree widget item when the page is
588 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
590 return m_widgethash.value(page);
594 * Function to respond to action on page selector context menu to close the
597 void MainWin::closePage()
599 QTreeWidgetItem *currentitem = treeWidget->currentItem();
601 /* Is this a page that has been inserted into the hash */
602 if (getFromHash(currentitem)) {
603 Pages* page = getFromHash(currentitem);
604 if (page->isCloseable()) {
605 page->closeStackPage();
610 /* Quick function to return the current console */
611 Console *MainWin::currentConsole()
613 return m_currentConsole;
615 /* Quick function to return the tree item for the director */
616 QTreeWidgetItem *MainWin::currentTopItem()
618 return m_currentConsole->directorTreeItem();
621 /* Preferences menu item clicked */
622 void MainWin::setPreferences()
625 prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
626 prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
627 prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
628 prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
629 prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
630 prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
631 prefs.recordSpinBox->setValue(m_recordLimitVal);
632 prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
633 prefs.daysSpinBox->setValue(m_daysLimitVal);
634 prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
635 prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
639 /* Preferences dialog */
640 prefsDialog::prefsDialog()
645 void prefsDialog::accept()
648 mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
649 mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
650 mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
651 mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
652 mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
653 mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
654 mainWin->m_recordLimitVal = this->recordSpinBox->value();
655 mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
656 mainWin->m_daysLimitVal = this->daysSpinBox->value();
657 mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
658 mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
659 QSettings settings("www.bacula.org", "bat");
660 settings.beginGroup("Debug");
661 settings.setValue("commDebug", mainWin->m_commDebug);
662 settings.setValue("displayAll", mainWin->m_displayAll);
663 settings.setValue("sqlDebug", mainWin->m_sqlDebug);
664 settings.setValue("commandDebug", mainWin->m_commandDebug);
665 settings.setValue("miscDebug", mainWin->m_miscDebug);
667 settings.beginGroup("JobList");
668 settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
669 settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
670 settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
671 settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
673 settings.beginGroup("Messages");
674 settings.setValue("checkMessages", mainWin->m_checkMessages);
675 settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
677 foreach(Console *console, mainWin->m_consoleHash) {
678 console->startTimer();
682 void prefsDialog::reject()
685 mainWin->set_status("Canceled");
688 /* read preferences for the prefences dialog box */
689 void MainWin::readPreferences()
691 QSettings settings("www.bacula.org", "bat");
692 settings.beginGroup("Debug");
693 m_commDebug = settings.value("commDebug", false).toBool();
694 m_displayAll = settings.value("displayAll", false).toBool();
695 m_sqlDebug = settings.value("sqlDebug", false).toBool();
696 m_commandDebug = settings.value("commandDebug", false).toBool();
697 m_miscDebug = settings.value("miscDebug", false).toBool();
699 settings.beginGroup("JobList");
700 m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
701 m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
702 m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
703 m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
705 settings.beginGroup("Messages");
706 m_checkMessages = settings.value("checkMessages", false).toBool();
707 m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();