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"
50 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
52 m_dtformat = "yyyy-MM-dd HH:mm:ss";
54 setupUi(this); /* Setup UI defined by main.ui (designer) */
57 treeWidget->setColumnCount(1);
58 treeWidget->setHeaderLabel("Select Page");
59 treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
71 foreach(Console *console, m_consoleHash) {
74 m_currentConsole = (Console*)getFromHash(m_firstItem);
75 m_currentConsole->setCurrent();
77 QString directoryResourceName;
78 m_currentConsole->getDirResName(directoryResourceName);
79 Pmsg1(000, "Setting initial window to %s\n", directoryResourceName.toUtf8().data());
83 void MainWin::createPages()
86 QTreeWidgetItem *item, *topItem;
90 foreach_res(dir, R_DIRECTOR) {
92 /* Create console tree stacked widget item */
93 m_currentConsole = new Console(stackedWidget);
94 m_currentConsole->setDirRes(dir);
95 m_currentConsole->readSettings();
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 Director */
101 QBrush greyBrush(Qt::lightGray);
102 topItem->setBackground(0, greyBrush);
103 m_currentConsole->setDirectorTreeItem(topItem);
104 m_consoleHash.insert(topItem, m_currentConsole);
106 /* Create Tree Widget Item */
107 item = createPage("Console", topItem);
108 if (!m_firstItem){ m_firstItem = item; }
110 /* insert the cosole and tree widget item into the hashes */
111 hashInsert(item, m_currentConsole);
113 /* Set Color of treeWidgetItem for the console
114 * It will be set to green in the console class if the connection is made.
116 QBrush redBrush(Qt::red);
117 item->setForeground(0, redBrush);
118 m_currentConsole->dockPage();
121 * Create instances in alphabetic order of the rest
122 * of the classes that will by default exist under each Director.
124 // createPagebRestore();
127 QString emptymedia(""), emptyclient("");
128 createPageJobList(emptymedia, emptyclient, NULL);
129 createPageMediaList();
132 treeWidget->expandItem(topItem);
133 stackedWidget->setCurrentWidget(m_currentConsole);
139 * create an instance of the the brestore class on the stack
141 void MainWin::createPagebRestore()
143 bRestore* brestore = new bRestore();
144 brestore->dockPage();
148 * create an instance of the the medialist class on the stack
150 void MainWin::createPageMediaList()
152 MediaList* medialist = new MediaList();
153 medialist->dockPage();
157 * create an instance of the the joblist class on the stack
159 void MainWin::createPageJobList(QString &media, QString &client,
160 QTreeWidgetItem *parentTreeWidgetItem)
162 QTreeWidgetItem *holdItem;
164 /* save current tree widget item in case query produces no results */
165 holdItem = treeWidget->currentItem();
166 JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
168 /* If this is a query of jobs on a specific media */
169 if ((media != "") || (client != "")) {
170 joblist->setCurrent();
171 /* did query produce results, if not close window and set back to hold */
172 if (joblist->m_resultCount == 0) {
173 joblist->closeStackPage();
174 treeWidget->setCurrentItem(holdItem);
180 * create an instance of the the Clients class on the stack
182 void MainWin::createPageClients()
184 Clients* clients = new Clients();
189 * create an instance of the the storage class on the stack
191 void MainWin::createPageStorage()
193 Storage* storage = new Storage();
198 * create an instance of the the fileset class on the stack
200 void MainWin::createPageFileSet()
202 FileSet* fileset = new FileSet();
206 /* Create a root Tree Widget */
207 QTreeWidgetItem *MainWin::createTopPage(char *name)
209 QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
210 item->setText(0, name);
214 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
215 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
217 QTreeWidgetItem *item = new QTreeWidgetItem(parent);
218 item->setText(0, name);
223 * Handle up and down arrow keys for the command line
226 void MainWin::keyPressEvent(QKeyEvent *event)
228 if (m_cmd_history.size() == 0) {
232 switch (event->key()) {
234 if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
241 if (m_cmd_last == 0) {
245 if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
246 m_cmd_last = m_cmd_history.size() - 1;
255 lineEdit->setText(m_cmd_history[m_cmd_last]);
258 void MainWin::createConnections()
260 /* Connect signals to slots */
261 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
262 connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
263 connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
264 SLOT(treeItemClicked(QTreeWidgetItem *, int)));
265 connect(treeWidget, SIGNAL(
266 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
267 this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
268 connect(stackedWidget, SIGNAL(currentChanged(int)),
269 this, SLOT(stackItemChanged(int)));
270 connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
271 connect(actionLabel, SIGNAL(triggered()), this, SLOT(labelButtonClicked()));
272 connect(actionRun, SIGNAL(triggered()), this, SLOT(runButtonClicked()));
273 connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreButtonClicked()));
274 connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
275 connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
276 connect(actionClosePage, SIGNAL(triggered()), this, SLOT(closePage()));
277 connect(actionPreferences, SIGNAL(triggered()), this, SLOT(setPreferences()));
281 * Reimplementation of QWidget closeEvent virtual function
283 void MainWin::closeEvent(QCloseEvent *event)
286 foreach(Console *console, m_consoleHash){
287 console->writeSettings();
288 console->terminate();
291 foreach(Pages *page, m_pagehash) {
292 if (!page->isDocked())
297 void MainWin::writeSettings()
299 QSettings settings("bacula.org", "bat");
301 settings.beginGroup("MainWin");
302 settings.setValue("winSize", size());
303 settings.setValue("winPos", pos());
304 settings.setValue("state", saveState());
308 void MainWin::readSettings()
310 QSettings settings("bacula.org", "bat");
312 settings.beginGroup("MainWin");
313 resize(settings.value("winSize", QSize(1041, 801)).toSize());
314 move(settings.value("winPos", QPoint(200, 150)).toPoint());
315 restoreState(settings.value("state").toByteArray());
320 * This subroutine is called with an item in the Page Selection window
323 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
325 /* Is this a page that has been inserted into the hash */
326 if (getFromHash(item)) {
327 Pages* page = getFromHash(item);
328 int stackindex=stackedWidget->indexOf(page);
330 if (stackindex >= 0) {
331 stackedWidget->setCurrentWidget(page);
333 /* run the virtual function in case this class overrides it */
334 page->PgSeltreeWidgetClicked();
339 * Called with a change of the highlighed tree widget item in the page selector.
341 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
343 Pages *previousPage, *nextPage;
344 Console *previousConsole, *nextConsole;
346 /* first determine the next item */
348 /* knowing the treeWidgetItem, get the page from the hash */
349 nextPage = getFromHash(currentitem);
350 nextConsole = m_consoleHash.value(currentitem);
351 /* Is this a page that has been inserted into the hash */
353 nextConsole = nextPage->console();
354 /* then is it a treeWidgetItem representing a director */
355 } else if (nextConsole) {
356 /* let the next page BE the console */
357 nextPage = nextConsole;
359 /* Should never get here */
364 /* The Previous item */
366 /* this condition prevents a segfault. The first time there is no previousitem*/
368 /* knowing the treeWidgetItem, get the page from the hash */
369 previousPage = getFromHash(previousitem);
370 previousConsole = m_consoleHash.value(previousitem);
372 previousConsole = previousPage->console();
373 } else if (previousConsole) {
374 previousPage = previousConsole;
376 if ((previousPage) || (previousConsole)) {
377 if (nextConsole != previousConsole) {
378 /* remove connections to the current console */
379 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
380 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
381 disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
382 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
383 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
384 QBrush greyBrush(Qt::lightGray);
385 dirItem->setBackground(0, greyBrush);
387 /* make sure the close window and toggle dock options are removed */
388 treeWidget->removeAction(actionClosePage);
389 treeWidget->removeAction(actionToggleDock);
390 /* Is this a page that has been inserted into the hash */
392 foreach(QAction* pageaction, previousPage->m_contextActions) {
393 treeWidget->removeAction(pageaction);
399 /* process the current (next) item */
401 if ((nextPage) || (nextConsole)) {
402 if (nextConsole != previousConsole) {
403 /* make connections to the current console */
404 m_currentConsole = nextConsole;
405 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
406 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
407 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
408 connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
409 /* Set director's tree widget background to magenta for ease of identification */
410 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
411 QBrush magentaBrush(Qt::magenta);
412 dirItem->setBackground(0, magentaBrush);
414 /* set the value for the currently active console */
415 int stackindex = stackedWidget->indexOf(nextPage);
417 /* Is this page currently on the stack or is it undocked */
418 if (stackindex >= 0) {
419 /* put this page on the top of the stack */
420 stackedWidget->setCurrentIndex(stackindex);
422 /* it is undocked, raise it to the front */
425 /* for the page selectors menu action to dock or undock, set the text */
426 nextPage->setContextMenuDockText();
428 treeWidget->addAction(actionToggleDock);
429 /* if this page is closeable, then add that action */
430 if (nextPage->isCloseable()) {
431 treeWidget->addAction(actionClosePage);
434 /* Add the actions to the Page Selectors tree widget that are part of the
435 * current items list of desired actions regardless of whether on top of stack*/
436 treeWidget->addActions(nextPage->m_contextActions);
440 void MainWin::labelButtonClicked()
445 void MainWin::runButtonClicked()
450 void MainWin::restoreButtonClicked()
452 new prerestorePage();
456 * The user just finished typing a line in the command line edit box
458 void MainWin::input_line()
460 QString cmdStr = lineEdit->text(); /* Get the text */
461 lineEdit->clear(); /* clear the lineEdit box */
462 if (m_currentConsole->is_connected()) {
463 m_currentConsole->display_text(cmdStr + "\n");
464 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
466 set_status("Director not connected. Click on connect button.");
468 m_cmd_history.append(cmdStr);
470 if (treeWidget->currentItem() != getFromHash(m_currentConsole))
471 m_currentConsole->setCurrent();
475 void MainWin::about()
477 QMessageBox::about(this, tr("About bat"),
478 tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
479 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
480 "<p>The <b>bat</b> is an administrative console"
481 " interface to the Director."));
484 void MainWin::set_statusf(const char *fmt, ...)
489 va_start(arg_ptr, fmt);
490 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
495 void MainWin::set_status_ready()
497 set_status(" Ready");
500 void MainWin::set_status(const char *buf)
502 statusBar()->showMessage(buf);
506 * Function to respond to the button bar button to undock
508 void MainWin::undockWindowButton()
510 Pages* page = (Pages*)stackedWidget->currentWidget();
511 page->togglePageDocking();
515 * Function to respond to action on page selector context menu to toggle the
516 * dock status of the window associated with the page selectors current
519 void MainWin::toggleDockContextWindow()
521 QTreeWidgetItem *currentitem = treeWidget->currentItem();
523 /* Is this a page that has been inserted into the hash */
524 if (getFromHash(currentitem)) {
525 Pages* page = getFromHash(currentitem);
526 page->togglePageDocking();
531 * This function is called when the stack item is changed. Call
532 * the virtual function here. Avoids a window being undocked leaving
533 * a window at the top of the stack unpopulated.
535 void MainWin::stackItemChanged(int)
537 Pages* page = (Pages*)stackedWidget->currentWidget();
538 /* run the virtual function in case this class overrides it */
539 page->currentStackItem();
543 * Function to simplify insertion of QTreeWidgetItem <-> Page association
544 * into a double direction hash.
546 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
548 m_pagehash.insert(item, page);
549 m_widgethash.insert(page, item);
553 * Function to simplify removal of QTreeWidgetItem <-> Page association
554 * into a double direction hash.
556 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
558 /* I had all sorts of return status checking code here. Do we have a log
559 * level capability in bat. I would have left it in but it used printf's
560 * and it should really be some kind of log level facility ???
561 * ******FIXME********/
562 m_pagehash.remove(item);
563 m_widgethash.remove(page);
567 * Function to retrieve a Page* when the item in the page selector's tree is
570 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
572 return m_pagehash.value(item);
576 * Function to retrieve the page selectors tree widget item when the page is
579 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
581 return m_widgethash.value(page);
585 * Function to respond to action on page selector context menu to close the
588 void MainWin::closePage()
590 QTreeWidgetItem *currentitem = treeWidget->currentItem();
592 /* Is this a page that has been inserted into the hash */
593 if (getFromHash(currentitem)) {
594 Pages* page = getFromHash(currentitem);
595 if (page->isCloseable()) {
596 page->closeStackPage();
601 /* Quick function to return the current console */
602 Console *MainWin::currentConsole()
604 return m_currentConsole;
606 /* Quick function to return the tree item for the director */
607 QTreeWidgetItem *MainWin::currentTopItem()
609 return m_currentConsole->directorTreeItem();
612 /* Preferences menu item clicked */
613 void MainWin::setPreferences()
616 prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
617 prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
618 prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
619 prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
620 prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
621 prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
622 prefs.recordSpinBox->setValue(m_recordLimitVal);
623 prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
624 prefs.daysSpinBox->setValue(m_daysLimitVal);
625 prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
626 prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
630 /* Preferences dialog */
631 prefsDialog::prefsDialog()
636 void prefsDialog::accept()
639 mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
640 mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
641 mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
642 mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
643 mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
644 mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
645 mainWin->m_recordLimitVal = this->recordSpinBox->value();
646 mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
647 mainWin->m_daysLimitVal = this->daysSpinBox->value();
648 mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
649 mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
650 QSettings settings("www.bacula.org", "bat");
651 settings.beginGroup("Debug");
652 settings.setValue("commDebug", mainWin->m_commDebug);
653 settings.setValue("displayAll", mainWin->m_displayAll);
654 settings.setValue("sqlDebug", mainWin->m_sqlDebug);
655 settings.setValue("commandDebug", mainWin->m_commandDebug);
656 settings.setValue("miscDebug", mainWin->m_miscDebug);
658 settings.beginGroup("JobList");
659 settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
660 settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
661 settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
662 settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
664 settings.beginGroup("Messages");
665 settings.setValue("checkMessages", mainWin->m_checkMessages);
666 settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
668 foreach(Console *console, mainWin->m_consoleHash) {
669 console->startTimer();
673 void prefsDialog::reject()
676 mainWin->set_status("Canceled");
679 /* read preferences for the prefences dialog box */
680 void MainWin::readPreferences()
682 QSettings settings("www.bacula.org", "bat");
683 settings.beginGroup("Debug");
684 m_commDebug = settings.value("commDebug", false).toBool();
685 m_displayAll = settings.value("displayAll", false).toBool();
686 m_sqlDebug = settings.value("sqlDebug", false).toBool();
687 m_commandDebug = settings.value("commandDebug", false).toBool();
688 m_miscDebug = settings.value("miscDebug", false).toBool();
690 settings.beginGroup("JobList");
691 m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
692 m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
693 m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
694 m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
696 settings.beginGroup("Messages");
697 m_checkMessages = settings.value("checkMessages", false).toBool();
698 m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();