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());
307 void MainWin::readSettings()
309 QSettings settings("bacula.org", "bat");
311 settings.beginGroup("MainWin");
312 resize(settings.value("winSize", QSize(1041, 801)).toSize());
313 move(settings.value("winPos", QPoint(200, 150)).toPoint());
318 * This subroutine is called with an item in the Page Selection window
321 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
323 /* Is this a page that has been inserted into the hash */
324 if (getFromHash(item)) {
325 Pages* page = getFromHash(item);
326 int stackindex=stackedWidget->indexOf(page);
328 if (stackindex >= 0) {
329 stackedWidget->setCurrentWidget(page);
331 /* run the virtual function in case this class overrides it */
332 page->PgSeltreeWidgetClicked();
337 * Called with a change of the highlighed tree widget item in the page selector.
339 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
341 Pages *previousPage, *nextPage;
342 Console *previousConsole, *nextConsole;
344 /* first determine the next item */
346 /* knowing the treeWidgetItem, get the page from the hash */
347 nextPage = getFromHash(currentitem);
348 nextConsole = m_consoleHash.value(currentitem);
349 /* Is this a page that has been inserted into the hash */
351 nextConsole = nextPage->console();
352 /* then is it a treeWidgetItem representing a director */
353 } else if (nextConsole) {
354 /* let the next page BE the console */
355 nextPage = nextConsole;
357 /* Should never get here */
362 /* The Previous item */
364 /* this condition prevents a segfault. The first time there is no previousitem*/
366 /* knowing the treeWidgetItem, get the page from the hash */
367 previousPage = getFromHash(previousitem);
368 previousConsole = m_consoleHash.value(previousitem);
370 previousConsole = previousPage->console();
371 } else if (previousConsole) {
372 previousPage = previousConsole;
374 if ((previousPage) || (previousConsole)) {
375 if (nextConsole != previousConsole) {
376 /* remove connections to the current console */
377 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
378 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
379 disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
380 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
381 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
382 QBrush greyBrush(Qt::lightGray);
383 dirItem->setBackground(0, greyBrush);
385 /* make sure the close window and toggle dock options are removed */
386 treeWidget->removeAction(actionClosePage);
387 treeWidget->removeAction(actionToggleDock);
388 /* Is this a page that has been inserted into the hash */
390 foreach(QAction* pageaction, previousPage->m_contextActions) {
391 treeWidget->removeAction(pageaction);
397 /* process the current (next) item */
399 if ((nextPage) || (nextConsole)) {
400 if (nextConsole != previousConsole) {
401 /* make connections to the current console */
402 m_currentConsole = nextConsole;
403 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
404 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
405 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
406 connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
407 /* Set director's tree widget background to magenta for ease of identification */
408 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
409 QBrush magentaBrush(Qt::magenta);
410 dirItem->setBackground(0, magentaBrush);
412 /* set the value for the currently active console */
413 int stackindex = stackedWidget->indexOf(nextPage);
415 /* Is this page currently on the stack or is it undocked */
416 if (stackindex >= 0) {
417 /* put this page on the top of the stack */
418 stackedWidget->setCurrentIndex(stackindex);
420 /* it is undocked, raise it to the front */
423 /* for the page selectors menu action to dock or undock, set the text */
424 nextPage->setContextMenuDockText();
426 treeWidget->addAction(actionToggleDock);
427 /* if this page is closeable, then add that action */
428 if (nextPage->isCloseable()) {
429 treeWidget->addAction(actionClosePage);
432 /* Add the actions to the Page Selectors tree widget that are part of the
433 * current items list of desired actions regardless of whether on top of stack*/
434 treeWidget->addActions(nextPage->m_contextActions);
438 void MainWin::labelButtonClicked()
443 void MainWin::runButtonClicked()
448 void MainWin::restoreButtonClicked()
450 new prerestorePage();
454 * The user just finished typing a line in the command line edit box
456 void MainWin::input_line()
458 QString cmdStr = lineEdit->text(); /* Get the text */
459 lineEdit->clear(); /* clear the lineEdit box */
460 if (m_currentConsole->is_connected()) {
461 m_currentConsole->display_text(cmdStr + "\n");
462 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
464 set_status("Director not connected. Click on connect button.");
466 m_cmd_history.append(cmdStr);
468 if (treeWidget->currentItem() != getFromHash(m_currentConsole))
469 m_currentConsole->setCurrent();
473 void MainWin::about()
475 QMessageBox::about(this, tr("About bat"),
476 tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
477 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
478 "<p>The <b>bat</b> is an administrative console"
479 " interface to the Director."));
482 void MainWin::set_statusf(const char *fmt, ...)
487 va_start(arg_ptr, fmt);
488 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
493 void MainWin::set_status_ready()
495 set_status(" Ready");
498 void MainWin::set_status(const char *buf)
500 statusBar()->showMessage(buf);
504 * Function to respond to the button bar button to undock
506 void MainWin::undockWindowButton()
508 Pages* page = (Pages*)stackedWidget->currentWidget();
509 page->togglePageDocking();
513 * Function to respond to action on page selector context menu to toggle the
514 * dock status of the window associated with the page selectors current
517 void MainWin::toggleDockContextWindow()
519 QTreeWidgetItem *currentitem = treeWidget->currentItem();
521 /* Is this a page that has been inserted into the hash */
522 if (getFromHash(currentitem)) {
523 Pages* page = getFromHash(currentitem);
524 page->togglePageDocking();
529 * This function is called when the stack item is changed. Call
530 * the virtual function here. Avoids a window being undocked leaving
531 * a window at the top of the stack unpopulated.
533 void MainWin::stackItemChanged(int)
535 Pages* page = (Pages*)stackedWidget->currentWidget();
536 /* run the virtual function in case this class overrides it */
537 page->currentStackItem();
541 * Function to simplify insertion of QTreeWidgetItem <-> Page association
542 * into a double direction hash.
544 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
546 m_pagehash.insert(item, page);
547 m_widgethash.insert(page, item);
551 * Function to simplify removal of QTreeWidgetItem <-> Page association
552 * into a double direction hash.
554 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
556 /* I had all sorts of return status checking code here. Do we have a log
557 * level capability in bat. I would have left it in but it used printf's
558 * and it should really be some kind of log level facility ???
559 * ******FIXME********/
560 m_pagehash.remove(item);
561 m_widgethash.remove(page);
565 * Function to retrieve a Page* when the item in the page selector's tree is
568 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
570 return m_pagehash.value(item);
574 * Function to retrieve the page selectors tree widget item when the page is
577 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
579 return m_widgethash.value(page);
583 * Function to respond to action on page selector context menu to close the
586 void MainWin::closePage()
588 QTreeWidgetItem *currentitem = treeWidget->currentItem();
590 /* Is this a page that has been inserted into the hash */
591 if (getFromHash(currentitem)) {
592 Pages* page = getFromHash(currentitem);
593 if (page->isCloseable()) {
594 page->closeStackPage();
599 /* Quick function to return the current console */
600 Console *MainWin::currentConsole()
602 return m_currentConsole;
604 /* Quick function to return the tree item for the director */
605 QTreeWidgetItem *MainWin::currentTopItem()
607 return m_currentConsole->directorTreeItem();
610 /* Preferences menu item clicked */
611 void MainWin::setPreferences()
614 prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
615 prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
616 prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
617 prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
618 prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
619 prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
620 prefs.recordSpinBox->setValue(m_recordLimitVal);
621 prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
622 prefs.daysSpinBox->setValue(m_daysLimitVal);
623 prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
624 prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
628 /* Preferences dialog */
629 prefsDialog::prefsDialog()
634 void prefsDialog::accept()
637 mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
638 mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
639 mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
640 mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
641 mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
642 mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
643 mainWin->m_recordLimitVal = this->recordSpinBox->value();
644 mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
645 mainWin->m_daysLimitVal = this->daysSpinBox->value();
646 mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
647 mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
648 QSettings settings("www.bacula.org", "bat");
649 settings.beginGroup("Debug");
650 settings.setValue("commDebug", mainWin->m_commDebug);
651 settings.setValue("displayAll", mainWin->m_displayAll);
652 settings.setValue("sqlDebug", mainWin->m_sqlDebug);
653 settings.setValue("commandDebug", mainWin->m_commandDebug);
654 settings.setValue("miscDebug", mainWin->m_miscDebug);
656 settings.beginGroup("JobList");
657 settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
658 settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
659 settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
660 settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
662 settings.beginGroup("Messages");
663 settings.setValue("checkMessages", mainWin->m_checkMessages);
664 settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
666 foreach(Console *console, mainWin->m_consoleHash) {
667 console->startTimer();
671 void prefsDialog::reject()
674 mainWin->set_status("Canceled");
677 /* read preferences for the prefences dialog box */
678 void MainWin::readPreferences()
680 QSettings settings("www.bacula.org", "bat");
681 settings.beginGroup("Debug");
682 m_commDebug = settings.value("commDebug", false).toBool();
683 m_displayAll = settings.value("displayAll", false).toBool();
684 m_sqlDebug = settings.value("sqlDebug", false).toBool();
685 m_commandDebug = settings.value("commandDebug", false).toBool();
686 m_miscDebug = settings.value("miscDebug", false).toBool();
688 settings.beginGroup("JobList");
689 m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
690 m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
691 m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
692 m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
694 settings.beginGroup("Messages");
695 m_checkMessages = settings.value("checkMessages", false).toBool();
696 m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();