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; }
119 item->setIcon(0,QIcon(QString::fromUtf8(":images/utilities-terminal.png")));
121 /* insert the cosole and tree widget item into the hashes */
122 hashInsert(item, m_currentConsole);
124 /* Set Color of treeWidgetItem for the console
125 * It will be set to green in the console class if the connection is made.
127 QBrush redBrush(Qt::red);
128 item->setForeground(0, redBrush);
129 m_currentConsole->dockPage();
132 * Create instances in alphabetic order of the rest
133 * of the classes that will by default exist under each Director.
135 // createPagebRestore();
138 QString emptymedia(""), emptyclient("");
139 createPageJobList(emptymedia, emptyclient, NULL);
140 createPageMediaList();
143 treeWidget->expandItem(topItem);
144 stackedWidget->setCurrentWidget(m_currentConsole);
150 * create an instance of the the brestore class on the stack
152 void MainWin::createPagebRestore()
154 bRestore* brestore = new bRestore();
155 brestore->dockPage();
159 * create an instance of the the medialist class on the stack
161 void MainWin::createPageMediaList()
163 MediaList* medialist = new MediaList();
164 medialist->dockPage();
168 * create an instance of the the joblist class on the stack
170 void MainWin::createPageJobList(QString &media, QString &client,
171 QTreeWidgetItem *parentTreeWidgetItem)
173 QTreeWidgetItem *holdItem;
175 /* save current tree widget item in case query produces no results */
176 holdItem = treeWidget->currentItem();
177 JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
179 /* If this is a query of jobs on a specific media */
180 if ((media != "") || (client != "")) {
181 joblist->setCurrent();
182 /* did query produce results, if not close window and set back to hold */
183 if (joblist->m_resultCount == 0) {
184 joblist->closeStackPage();
185 treeWidget->setCurrentItem(holdItem);
191 * create an instance of the the Clients class on the stack
193 void MainWin::createPageClients()
195 Clients* clients = new Clients();
200 * create an instance of the the storage class on the stack
202 void MainWin::createPageStorage()
204 Storage* storage = new Storage();
209 * create an instance of the the fileset class on the stack
211 void MainWin::createPageFileSet()
213 FileSet* fileset = new FileSet();
217 /* Create a root Tree Widget */
218 QTreeWidgetItem *MainWin::createTopPage(char *name)
220 QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
221 item->setText(0, name);
225 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
226 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
228 QTreeWidgetItem *item = new QTreeWidgetItem(parent);
229 item->setText(0, name);
234 * Handle up and down arrow keys for the command line
237 void MainWin::keyPressEvent(QKeyEvent *event)
239 if (m_cmd_history.size() == 0) {
243 switch (event->key()) {
245 if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
252 if (m_cmd_last == 0) {
256 if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
257 m_cmd_last = m_cmd_history.size() - 1;
266 lineEdit->setText(m_cmd_history[m_cmd_last]);
269 void MainWin::createConnections()
271 /* Connect signals to slots */
272 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
273 connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
274 connect(actionBat_Help, SIGNAL(triggered()), this, SLOT(help()));
275 connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
276 SLOT(treeItemClicked(QTreeWidgetItem *, int)));
277 connect(treeWidget, SIGNAL(
278 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
279 this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
280 connect(stackedWidget, SIGNAL(currentChanged(int)),
281 this, SLOT(stackItemChanged(int)));
282 connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
283 connect(actionLabel, SIGNAL(triggered()), this, SLOT(labelButtonClicked()));
284 connect(actionRun, SIGNAL(triggered()), this, SLOT(runButtonClicked()));
285 connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreButtonClicked()));
286 connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
287 connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
288 connect(actionClosePage, SIGNAL(triggered()), this, SLOT(closePage()));
289 connect(actionPreferences, SIGNAL(triggered()), this, SLOT(setPreferences()));
293 * Reimplementation of QWidget closeEvent virtual function
295 void MainWin::closeEvent(QCloseEvent *event)
298 foreach(Console *console, m_consoleHash){
299 console->writeSettings();
300 console->terminate();
303 foreach(Pages *page, m_pagehash) {
304 if (!page->isDocked())
309 void MainWin::writeSettings()
311 QSettings settings("bacula.org", "bat");
313 settings.beginGroup("MainWin");
314 settings.setValue("winSize", size());
315 settings.setValue("winPos", pos());
316 settings.setValue("state", saveState());
320 void MainWin::readSettings()
322 QSettings settings("bacula.org", "bat");
324 settings.beginGroup("MainWin");
325 resize(settings.value("winSize", QSize(1041, 801)).toSize());
326 move(settings.value("winPos", QPoint(200, 150)).toPoint());
327 restoreState(settings.value("state").toByteArray());
332 * This subroutine is called with an item in the Page Selection window
335 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
337 /* Is this a page that has been inserted into the hash */
338 if (getFromHash(item)) {
339 Pages* page = getFromHash(item);
340 int stackindex=stackedWidget->indexOf(page);
342 if (stackindex >= 0) {
343 stackedWidget->setCurrentWidget(page);
345 /* run the virtual function in case this class overrides it */
346 page->PgSeltreeWidgetClicked();
351 * Called with a change of the highlighed tree widget item in the page selector.
353 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
355 Pages *previousPage, *nextPage;
356 Console *previousConsole, *nextConsole;
358 /* first determine the next item */
360 /* knowing the treeWidgetItem, get the page from the hash */
361 nextPage = getFromHash(currentitem);
362 nextConsole = m_consoleHash.value(currentitem);
363 /* Is this a page that has been inserted into the hash */
365 nextConsole = nextPage->console();
366 /* then is it a treeWidgetItem representing a director */
367 } else if (nextConsole) {
368 /* let the next page BE the console */
369 nextPage = nextConsole;
371 /* Should never get here */
376 /* The Previous item */
378 /* this condition prevents a segfault. The first time there is no previousitem*/
380 /* knowing the treeWidgetItem, get the page from the hash */
381 previousPage = getFromHash(previousitem);
382 previousConsole = m_consoleHash.value(previousitem);
384 previousConsole = previousPage->console();
385 } else if (previousConsole) {
386 previousPage = previousConsole;
388 if ((previousPage) || (previousConsole)) {
389 if (nextConsole != previousConsole) {
390 /* remove connections to the current console */
391 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect_dir()));
392 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
393 disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
394 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
395 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
396 QBrush greyBrush(Qt::lightGray);
397 dirItem->setBackground(0, greyBrush);
399 /* make sure the close window and toggle dock options are removed */
400 treeWidget->removeAction(actionClosePage);
401 treeWidget->removeAction(actionToggleDock);
402 /* Is this a page that has been inserted into the hash */
404 foreach(QAction* pageaction, previousPage->m_contextActions) {
405 treeWidget->removeAction(pageaction);
411 /* process the current (next) item */
413 if ((nextPage) || (nextConsole)) {
414 if (nextConsole != previousConsole) {
415 /* make connections to the current console */
416 m_currentConsole = nextConsole;
417 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect_dir()));
418 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
419 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
420 connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
421 /* Set director's tree widget background to magenta for ease of identification */
422 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
423 QBrush magentaBrush(Qt::magenta);
424 dirItem->setBackground(0, magentaBrush);
426 /* set the value for the currently active console */
427 int stackindex = stackedWidget->indexOf(nextPage);
429 /* Is this page currently on the stack or is it undocked */
430 if (stackindex >= 0) {
431 /* put this page on the top of the stack */
432 stackedWidget->setCurrentIndex(stackindex);
434 /* it is undocked, raise it to the front */
437 /* for the page selectors menu action to dock or undock, set the text */
438 nextPage->setContextMenuDockText();
440 treeWidget->addAction(actionToggleDock);
441 /* if this page is closeable, then add that action */
442 if (nextPage->isCloseable()) {
443 treeWidget->addAction(actionClosePage);
446 /* Add the actions to the Page Selectors tree widget that are part of the
447 * current items list of desired actions regardless of whether on top of stack*/
448 treeWidget->addActions(nextPage->m_contextActions);
452 void MainWin::labelButtonClicked()
457 void MainWin::runButtonClicked()
462 void MainWin::restoreButtonClicked()
464 new prerestorePage();
468 * The user just finished typing a line in the command line edit box
470 void MainWin::input_line()
472 QString cmdStr = lineEdit->text(); /* Get the text */
473 lineEdit->clear(); /* clear the lineEdit box */
474 if (m_currentConsole->is_connected()) {
475 m_currentConsole->display_text(cmdStr + "\n");
476 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
478 set_status("Director not connected. Click on connect button.");
480 m_cmd_history.append(cmdStr);
482 if (treeWidget->currentItem() != getFromHash(m_currentConsole))
483 m_currentConsole->setCurrent();
487 void MainWin::about()
489 QMessageBox::about(this, tr("About bat"),
490 tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
491 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
492 "<p>The <b>bat</b> is an administrative console"
493 " interface to the Director."));
498 Help::displayFile("index.html");
501 void MainWin::set_statusf(const char *fmt, ...)
506 va_start(arg_ptr, fmt);
507 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
512 void MainWin::set_status_ready()
514 set_status(" Ready");
517 void MainWin::set_status(const char *buf)
519 statusBar()->showMessage(buf);
523 * Function to respond to the button bar button to undock
525 void MainWin::undockWindowButton()
527 Pages* page = (Pages*)stackedWidget->currentWidget();
528 page->togglePageDocking();
532 * Function to respond to action on page selector context menu to toggle the
533 * dock status of the window associated with the page selectors current
536 void MainWin::toggleDockContextWindow()
538 QTreeWidgetItem *currentitem = treeWidget->currentItem();
540 /* Is this a page that has been inserted into the hash */
541 if (getFromHash(currentitem)) {
542 Pages* page = getFromHash(currentitem);
543 page->togglePageDocking();
548 * This function is called when the stack item is changed. Call
549 * the virtual function here. Avoids a window being undocked leaving
550 * a window at the top of the stack unpopulated.
552 void MainWin::stackItemChanged(int)
554 Pages* page = (Pages*)stackedWidget->currentWidget();
555 /* run the virtual function in case this class overrides it */
556 page->currentStackItem();
560 * Function to simplify insertion of QTreeWidgetItem <-> Page association
561 * into a double direction hash.
563 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
565 m_pagehash.insert(item, page);
566 m_widgethash.insert(page, item);
570 * Function to simplify removal of QTreeWidgetItem <-> Page association
571 * into a double direction hash.
573 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
575 /* I had all sorts of return status checking code here. Do we have a log
576 * level capability in bat. I would have left it in but it used printf's
577 * and it should really be some kind of log level facility ???
578 * ******FIXME********/
579 m_pagehash.remove(item);
580 m_widgethash.remove(page);
584 * Function to retrieve a Page* when the item in the page selector's tree is
587 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
589 return m_pagehash.value(item);
593 * Function to retrieve the page selectors tree widget item when the page is
596 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
598 return m_widgethash.value(page);
602 * Function to respond to action on page selector context menu to close the
605 void MainWin::closePage()
607 QTreeWidgetItem *currentitem = treeWidget->currentItem();
609 /* Is this a page that has been inserted into the hash */
610 if (getFromHash(currentitem)) {
611 Pages* page = getFromHash(currentitem);
612 if (page->isCloseable()) {
613 page->closeStackPage();
618 /* Quick function to return the current console */
619 Console *MainWin::currentConsole()
621 return m_currentConsole;
623 /* Quick function to return the tree item for the director */
624 QTreeWidgetItem *MainWin::currentTopItem()
626 return m_currentConsole->directorTreeItem();
629 /* Preferences menu item clicked */
630 void MainWin::setPreferences()
633 prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
634 prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
635 prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
636 prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
637 prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
638 prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
639 prefs.recordSpinBox->setValue(m_recordLimitVal);
640 prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
641 prefs.daysSpinBox->setValue(m_daysLimitVal);
642 prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
643 prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
647 /* Preferences dialog */
648 prefsDialog::prefsDialog()
653 void prefsDialog::accept()
656 mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
657 mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
658 mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
659 mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
660 mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
661 mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
662 mainWin->m_recordLimitVal = this->recordSpinBox->value();
663 mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
664 mainWin->m_daysLimitVal = this->daysSpinBox->value();
665 mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
666 mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
667 QSettings settings("www.bacula.org", "bat");
668 settings.beginGroup("Debug");
669 settings.setValue("commDebug", mainWin->m_commDebug);
670 settings.setValue("displayAll", mainWin->m_displayAll);
671 settings.setValue("sqlDebug", mainWin->m_sqlDebug);
672 settings.setValue("commandDebug", mainWin->m_commandDebug);
673 settings.setValue("miscDebug", mainWin->m_miscDebug);
675 settings.beginGroup("JobList");
676 settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
677 settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
678 settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
679 settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
681 settings.beginGroup("Messages");
682 settings.setValue("checkMessages", mainWin->m_checkMessages);
683 settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
685 foreach(Console *console, mainWin->m_consoleHash) {
686 console->startTimer();
690 void prefsDialog::reject()
693 mainWin->set_status("Canceled");
696 /* read preferences for the prefences dialog box */
697 void MainWin::readPreferences()
699 QSettings settings("www.bacula.org", "bat");
700 settings.beginGroup("Debug");
701 m_commDebug = settings.value("commDebug", false).toBool();
702 m_displayAll = settings.value("displayAll", false).toBool();
703 m_sqlDebug = settings.value("sqlDebug", false).toBool();
704 m_commandDebug = settings.value("commandDebug", false).toBool();
705 m_miscDebug = settings.value("miscDebug", false).toBool();
707 settings.beginGroup("JobList");
708 m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
709 m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
710 m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
711 m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
713 settings.beginGroup("Messages");
714 m_checkMessages = settings.value("checkMessages", false).toBool();
715 m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();