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)
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 dirfector */
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();
120 /* create instances of the rest of the classes that will by default exist
121 * under each director */
122 // createPagebRestore();
123 createPageMediaList();
124 QString emptymedia(""), emptyclient("");
125 createPageJobList(emptymedia, emptyclient, NULL);
130 treeWidget->expandItem(topItem);
131 stackedWidget->setCurrentWidget(m_currentConsole);
137 * create an instance of the the brestore class on the stack
139 void MainWin::createPagebRestore()
141 bRestore* brestore = new bRestore();
142 brestore->dockPage();
146 * create an instance of the the medialist class on the stack
148 void MainWin::createPageMediaList()
150 MediaList* medialist = new MediaList();
151 medialist->dockPage();
155 * create an instance of the the joblist class on the stack
157 void MainWin::createPageJobList(QString &media, QString &client,
158 QTreeWidgetItem *parentTreeWidgetItem)
160 QTreeWidgetItem *holdItem;
162 /* save current tree widget item in case query produces no results */
163 holdItem = treeWidget->currentItem();
164 JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
166 /* If this is a query of jobs on a specific media */
167 if ((media != "") || (client != "")) {
168 joblist->setCurrent();
169 /* did query produce results, if not close window and set back to hold */
170 if (joblist->m_resultCount == 0) {
171 joblist->closeStackPage();
172 treeWidget->setCurrentItem(holdItem);
178 * create an instance of the the Clients class on the stack
180 void MainWin::createPageClients()
182 Clients* clients = new Clients();
187 * create an instance of the the storage class on the stack
189 void MainWin::createPageStorage()
191 Storage* storage = new Storage();
196 * create an instance of the the fileset class on the stack
198 void MainWin::createPageFileSet()
200 FileSet* fileset = new FileSet();
204 /* Create a root Tree Widget */
205 QTreeWidgetItem *MainWin::createTopPage(char *name)
207 QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
208 item->setText(0, name);
212 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
213 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
215 QTreeWidgetItem *item = new QTreeWidgetItem(parent);
216 item->setText(0, name);
221 * Handle up and down arrow keys for the command line
224 void MainWin::keyPressEvent(QKeyEvent *event)
226 if (m_cmd_history.size() == 0) {
230 switch (event->key()) {
232 if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
239 if (m_cmd_last == 0) {
243 if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
244 m_cmd_last = m_cmd_history.size() - 1;
253 lineEdit->setText(m_cmd_history[m_cmd_last]);
256 void MainWin::createConnections()
258 /* Connect signals to slots */
259 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
260 connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
261 connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
262 SLOT(treeItemClicked(QTreeWidgetItem *, int)));
263 connect(treeWidget, SIGNAL(
264 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
265 this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
266 connect(stackedWidget, SIGNAL(currentChanged(int)),
267 this, SLOT(stackItemChanged(int)));
268 connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
269 connect(actionLabel, SIGNAL(triggered()), this, SLOT(labelButtonClicked()));
270 connect(actionRun, SIGNAL(triggered()), this, SLOT(runButtonClicked()));
271 connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreButtonClicked()));
272 connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
273 connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
274 connect(actionClosePage, SIGNAL(triggered()), this, SLOT(closePage()));
275 connect(actionPreferences, SIGNAL(triggered()), this, SLOT(setPreferences()));
279 * Reimplementation of QWidget closeEvent virtual function
281 void MainWin::closeEvent(QCloseEvent *event)
284 foreach(Console *console, m_consoleHash){
285 console->writeSettings();
286 console->terminate();
289 foreach(Pages *page, m_pagehash) {
290 if (!page->isDocked())
295 void MainWin::writeSettings()
297 QSettings settings("bacula.org", "bat");
299 settings.beginGroup("MainWin");
300 settings.setValue("winSize", size());
301 settings.setValue("winPos", pos());
305 void MainWin::readSettings()
307 QSettings settings("bacula.org", "bat");
309 settings.beginGroup("MainWin");
310 resize(settings.value("winSize", QSize(1041, 801)).toSize());
311 move(settings.value("winPos", QPoint(200, 150)).toPoint());
316 * This subroutine is called with an item in the Page Selection window
319 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
321 /* Is this a page that has been inserted into the hash */
322 if (getFromHash(item)) {
323 Pages* page = getFromHash(item);
324 int stackindex=stackedWidget->indexOf(page);
326 if (stackindex >= 0) {
327 stackedWidget->setCurrentWidget(page);
329 /* run the virtual function in case this class overrides it */
330 page->PgSeltreeWidgetClicked();
335 * Called with a change of the highlighed tree widget item in the page selector.
337 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
339 Pages *previousPage, *nextPage;
340 Console *previousConsole, *nextConsole;
342 /* first determine the next item */
344 /* knowing the treeWidgetItem, get the page from the hash */
345 nextPage = getFromHash(currentitem);
346 nextConsole = m_consoleHash.value(currentitem);
347 /* Is this a page that has been inserted into the hash */
349 nextConsole = nextPage->console();
350 /* then is it a treeWidgetItem representing a director */
351 } else if (nextConsole) {
352 /* let the next page BE the console */
353 nextPage = nextConsole;
355 /* Should never get here */
360 /* The Previous item */
362 /* this condition prevents a segfault. The first time there is no previousitem*/
364 /* knowing the treeWidgetItem, get the page from the hash */
365 previousPage = getFromHash(previousitem);
366 previousConsole = m_consoleHash.value(previousitem);
368 previousConsole = previousPage->console();
369 } else if (previousConsole) {
370 previousPage = previousConsole;
372 if ((previousPage) || (previousConsole)) {
373 if (nextConsole != previousConsole) {
374 /* remove connections to the current console */
375 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
376 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
377 disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
378 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
379 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
380 QBrush greyBrush(Qt::lightGray);
381 dirItem->setBackground(0, greyBrush);
383 /* make sure the close window and toggle dock options are removed */
384 treeWidget->removeAction(actionClosePage);
385 treeWidget->removeAction(actionToggleDock);
386 /* Is this a page that has been inserted into the hash */
388 foreach(QAction* pageaction, previousPage->m_contextActions) {
389 treeWidget->removeAction(pageaction);
395 /* process the current (next) item */
397 if ((nextPage) || (nextConsole)) {
398 if (nextConsole != previousConsole) {
399 /* make connections to the current console */
400 m_currentConsole = nextConsole;
401 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
402 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
403 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
404 connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
405 /* Set director's tree widget background to magenta for ease of identification */
406 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
407 QBrush magentaBrush(Qt::magenta);
408 dirItem->setBackground(0, magentaBrush);
410 /* set the value for the currently active console */
411 int stackindex = stackedWidget->indexOf(nextPage);
413 /* Is this page currently on the stack or is it undocked */
414 if (stackindex >= 0) {
415 /* put this page on the top of the stack */
416 stackedWidget->setCurrentIndex(stackindex);
418 /* it is undocked, raise it to the front */
421 /* for the page selectors menu action to dock or undock, set the text */
422 nextPage->setContextMenuDockText();
424 treeWidget->addAction(actionToggleDock);
425 /* if this page is closeable, then add that action */
426 if (nextPage->isCloseable()) {
427 treeWidget->addAction(actionClosePage);
430 /* Add the actions to the Page Selectors tree widget that are part of the
431 * current items list of desired actions regardless of whether on top of stack*/
432 treeWidget->addActions(nextPage->m_contextActions);
436 void MainWin::labelButtonClicked()
441 void MainWin::runButtonClicked()
446 void MainWin::restoreButtonClicked()
448 new prerestorePage();
452 * The user just finished typing a line in the command line edit box
454 void MainWin::input_line()
456 QString cmdStr = lineEdit->text(); /* Get the text */
457 lineEdit->clear(); /* clear the lineEdit box */
458 if (m_currentConsole->is_connected()) {
459 m_currentConsole->display_text(cmdStr + "\n");
460 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
462 set_status("Director not connected. Click on connect button.");
464 m_cmd_history.append(cmdStr);
466 if (treeWidget->currentItem() != getFromHash(m_currentConsole))
467 m_currentConsole->setCurrent();
471 void MainWin::about()
473 QMessageBox::about(this, tr("About bat"),
474 tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
475 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
476 "<p>The <b>bat</b> is an administrative console"
477 " interface to the Director."));
480 void MainWin::set_statusf(const char *fmt, ...)
485 va_start(arg_ptr, fmt);
486 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
491 void MainWin::set_status_ready()
493 set_status(" Ready");
496 void MainWin::set_status(const char *buf)
498 statusBar()->showMessage(buf);
502 * Function to respond to the button bar button to undock
504 void MainWin::undockWindowButton()
506 Pages* page = (Pages*)stackedWidget->currentWidget();
507 page->togglePageDocking();
511 * Function to respond to action on page selector context menu to toggle the
512 * dock status of the window associated with the page selectors current
515 void MainWin::toggleDockContextWindow()
517 QTreeWidgetItem *currentitem = treeWidget->currentItem();
519 /* Is this a page that has been inserted into the hash */
520 if (getFromHash(currentitem)) {
521 Pages* page = getFromHash(currentitem);
522 page->togglePageDocking();
527 * This function is called when the stack item is changed. Call
528 * the virtual function here. Avoids a window being undocked leaving
529 * a window at the top of the stack unpopulated.
531 void MainWin::stackItemChanged(int)
533 Pages* page = (Pages*)stackedWidget->currentWidget();
534 /* run the virtual function in case this class overrides it */
535 page->currentStackItem();
539 * Function to simplify insertion of QTreeWidgetItem <-> Page association
540 * into a double direction hash.
542 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
544 m_pagehash.insert(item, page);
545 m_widgethash.insert(page, item);
549 * Function to simplify removal of QTreeWidgetItem <-> Page association
550 * into a double direction hash.
552 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
554 /* I had all sorts of return status checking code here. Do we have a log
555 * level capability in bat. I would have left it in but it used printf's
556 * and it should really be some kind of log level facility ???
557 * ******FIXME********/
558 m_pagehash.remove(item);
559 m_widgethash.remove(page);
563 * Function to retrieve a Page* when the item in the page selector's tree is
566 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
568 return m_pagehash.value(item);
572 * Function to retrieve the page selectors tree widget item when the page is
575 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
577 return m_widgethash.value(page);
581 * Function to respond to action on page selector context menu to close the
584 void MainWin::closePage()
586 QTreeWidgetItem *currentitem = treeWidget->currentItem();
588 /* Is this a page that has been inserted into the hash */
589 if (getFromHash(currentitem)) {
590 Pages* page = getFromHash(currentitem);
591 if (page->isCloseable()) {
592 page->closeStackPage();
597 /* Quick function to return the current console */
598 Console *MainWin::currentConsole()
600 return m_currentConsole;
602 /* Quick function to return the tree item for the director */
603 QTreeWidgetItem *MainWin::currentTopItem()
605 return m_currentConsole->directorTreeItem();
608 /* Preferences menu item clicked */
609 void MainWin::setPreferences()
612 prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
613 prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
614 prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
615 prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
616 prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
617 prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
618 prefs.recordSpinBox->setValue(m_recordLimitVal);
619 prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
620 prefs.daysSpinBox->setValue(m_daysLimitVal);
624 /* Preferences dialog */
625 prefsDialog::prefsDialog()
630 void prefsDialog::accept()
633 mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
634 mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
635 mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
636 mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
637 mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
638 mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
639 mainWin->m_recordLimitVal = this->recordSpinBox->value();
640 mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
641 mainWin->m_daysLimitVal = this->daysSpinBox->value();
642 QSettings settings("www.bacula.org", "bat");
643 settings.beginGroup("Messages");
644 settings.setValue("commDebug", mainWin->m_commDebug);
645 settings.setValue("displayAll", mainWin->m_displayAll);
646 settings.setValue("sqlDebug", mainWin->m_sqlDebug);
647 settings.setValue("commandDebug", mainWin->m_commandDebug);
648 settings.setValue("miscDebug", mainWin->m_miscDebug);
649 settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
650 settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
651 settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
652 settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
656 void prefsDialog::reject()
659 mainWin->set_status("Canceled");
662 /* read preferences for the prefences dialog box */
663 void MainWin::readPreferences()
665 QSettings settings("www.bacula.org", "bat");
666 settings.beginGroup("Messages");
667 m_commDebug = settings.value("commDebug", false).toBool();
668 m_displayAll = settings.value("displayAll", false).toBool();
669 m_sqlDebug = settings.value("sqlDebug", false).toBool();
670 m_commandDebug = settings.value("commandDebug", false).toBool();
671 m_miscDebug = settings.value("miscDebug", false).toBool();
672 m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
673 m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
674 m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
675 m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();