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) */
56 treeWidget->setColumnCount(1);
57 treeWidget->setHeaderLabel("Select Page");
58 treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
70 foreach(Console *console, m_consoleHash){
73 m_currentConsole = (Console*)getFromHash(m_firstItem);
74 m_currentConsole->setCurrent();
76 * I'd like to turn this into a debug item
77 * DIRRES* dirres = m_currentConsole->getDirRes();
78 * printf("Setting initial window to %s\n", dirres->name());
82 void MainWin::createPages()
85 QTreeWidgetItem *item, *topItem;
89 foreach_res(dir, R_DIRECTOR) {
91 /* Create console tree stacked widget item */
92 m_currentConsole = new Console(stackedWidget);
93 m_currentConsole->setDirRes(dir);
94 m_currentConsole->readSettings();
96 /* The top tree item representing the director */
97 topItem = createTopPage(dir->name());
98 topItem->setIcon(0, QIcon(":images/server.png"));
99 /* Set background to grey for ease of identification of inactive dirfector */
100 QBrush greyBrush(Qt::lightGray);
101 topItem->setBackground(0, greyBrush);
102 m_currentConsole->setDirectorTreeItem(topItem);
103 m_consoleHash.insert(topItem, m_currentConsole);
105 /* Create Tree Widget Item */
106 item = createPage("Console", topItem);
107 if (!m_firstItem){ m_firstItem = item; }
109 /* insert the cosole and tree widget item into the hashes */
110 hashInsert(item, m_currentConsole);
112 /* Set Color of treeWidgetItem for the console
113 * It will be set to green in the console class if the connection is made.
115 QBrush redBrush(Qt::red);
116 item->setForeground(0, redBrush);
117 m_currentConsole->dockPage();
119 /* create instances of the rest of the classes that will by default exist
120 * under each director */
121 // createPagebRestore();
122 createPageMediaList();
123 QString emptymedia(""), emptyclient("");
124 createPageJobList(emptymedia, emptyclient, NULL);
129 treeWidget->expandItem(topItem);
130 stackedWidget->setCurrentWidget(m_currentConsole);
136 * create an instance of the the brestore class on the stack
138 void MainWin::createPagebRestore()
140 bRestore* brestore = new bRestore();
141 brestore->dockPage();
145 * create an instance of the the medialist class on the stack
147 void MainWin::createPageMediaList()
149 MediaList* medialist = new MediaList();
150 medialist->dockPage();
154 * create an instance of the the joblist class on the stack
156 void MainWin::createPageJobList(QString &media, QString &client,
157 QTreeWidgetItem *parentTreeWidgetItem)
159 QTreeWidgetItem *holdItem;
161 /* save current tree widget item in case query produces no results */
162 holdItem = treeWidget->currentItem();
163 JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
165 /* If this is a query of jobs on a specific media */
166 if ((media != "") || (client != "")) {
167 joblist->setCurrent();
168 /* did query produce results, if not close window and set back to hold */
169 if (joblist->m_resultCount == 0) {
170 joblist->closeStackPage();
171 treeWidget->setCurrentItem(holdItem);
177 * create an instance of the the Clients class on the stack
179 void MainWin::createPageClients()
181 Clients* clients = new Clients();
186 * create an instance of the the storage class on the stack
188 void MainWin::createPageStorage()
190 Storage* storage = new Storage();
195 * create an instance of the the fileset class on the stack
197 void MainWin::createPageFileSet()
199 FileSet* fileset = new FileSet();
203 /* Create a root Tree Widget */
204 QTreeWidgetItem *MainWin::createTopPage(char *name)
206 QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
207 item->setText(0, name);
211 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
212 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
214 QTreeWidgetItem *item = new QTreeWidgetItem(parent);
215 item->setText(0, name);
220 * Handle up and down arrow keys for the command line
223 void MainWin::keyPressEvent(QKeyEvent *event)
225 if (m_cmd_history.size() == 0) {
229 switch (event->key()) {
231 if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
238 if (m_cmd_last == 0) {
242 if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
243 m_cmd_last = m_cmd_history.size() - 1;
252 lineEdit->setText(m_cmd_history[m_cmd_last]);
255 void MainWin::createConnections()
257 /* Connect signals to slots */
258 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
259 connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
260 connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
261 SLOT(treeItemClicked(QTreeWidgetItem *, int)));
262 connect(treeWidget, SIGNAL(
263 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
264 this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
265 connect(stackedWidget, SIGNAL(currentChanged(int)),
266 this, SLOT(stackItemChanged(int)));
267 connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
268 connect(actionLabel, SIGNAL(triggered()), this, SLOT(labelButtonClicked()));
269 connect(actionRun, SIGNAL(triggered()), this, SLOT(runButtonClicked()));
270 connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreButtonClicked()));
271 connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
272 connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
273 connect(actionClosePage, SIGNAL(triggered()), this, SLOT(closePage()));
277 * Reimplementation of QWidget closeEvent virtual function
279 void MainWin::closeEvent(QCloseEvent *event)
282 foreach(Console *console, m_consoleHash){
283 console->writeSettings();
284 console->terminate();
287 foreach(Pages *page, m_pagehash) {
288 if (!page->isDocked())
293 void MainWin::writeSettings()
295 QSettings settings("bacula.org", "bat");
297 settings.beginGroup("MainWin");
298 settings.setValue("winSize", size());
299 settings.setValue("winPos", pos());
303 void MainWin::readSettings()
305 QSettings settings("bacula.org", "bat");
307 settings.beginGroup("MainWin");
308 resize(settings.value("winSize", QSize(1041, 801)).toSize());
309 move(settings.value("winPos", QPoint(200, 150)).toPoint());
314 * This subroutine is called with an item in the Page Selection window
317 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
319 /* Is this a page that has been inserted into the hash */
320 if (getFromHash(item)) {
321 Pages* page = getFromHash(item);
322 int stackindex=stackedWidget->indexOf(page);
324 if (stackindex >= 0) {
325 stackedWidget->setCurrentWidget(page);
327 /* run the virtual function in case this class overrides it */
328 page->PgSeltreeWidgetClicked();
333 * Called with a change of the highlighed tree widget item in the page selector.
335 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
337 Pages *previousPage, *nextPage;
338 Console *previousConsole, *nextConsole;
340 /* first determine the next item */
342 /* knowing the treeWidgetItem, get the page from the hash */
343 nextPage = getFromHash(currentitem);
344 nextConsole = m_consoleHash.value(currentitem);
345 /* Is this a page that has been inserted into the hash */
347 nextConsole = nextPage->console();
348 /* then is it a treeWidgetItem representing a director */
349 } else if (nextConsole) {
350 /* let the next page BE the console */
351 nextPage = nextConsole;
353 /* Should never get here */
358 /* The Previous item */
360 /* this condition prevents a segfault. The first time there is no previousitem*/
362 /* knowing the treeWidgetItem, get the page from the hash */
363 previousPage = getFromHash(previousitem);
364 previousConsole = m_consoleHash.value(previousitem);
366 previousConsole = previousPage->console();
367 } else if (previousConsole) {
368 previousPage = previousConsole;
370 if ((previousPage) || (previousConsole)) {
371 if (nextConsole != previousConsole) {
372 /* remove connections to the current console */
373 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
374 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
375 disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
376 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
377 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
378 QBrush greyBrush(Qt::lightGray);
379 dirItem->setBackground(0, greyBrush);
381 /* make sure the close window and toggle dock options are removed */
382 treeWidget->removeAction(actionClosePage);
383 treeWidget->removeAction(actionToggleDock);
384 /* Is this a page that has been inserted into the hash */
386 foreach(QAction* pageaction, previousPage->m_contextActions) {
387 treeWidget->removeAction(pageaction);
393 /* process the current (next) item */
395 if ((nextPage) || (nextConsole)) {
396 if (nextConsole != previousConsole) {
397 /* make connections to the current console */
398 m_currentConsole = nextConsole;
399 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
400 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
401 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
402 connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
403 /* Set director's tree widget background to magenta for ease of identification */
404 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
405 QBrush magentaBrush(Qt::magenta);
406 dirItem->setBackground(0, magentaBrush);
408 /* set the value for the currently active console */
409 int stackindex = stackedWidget->indexOf(nextPage);
411 /* Is this page currently on the stack or is it undocked */
412 if (stackindex >= 0) {
413 /* put this page on the top of the stack */
414 stackedWidget->setCurrentIndex(stackindex);
416 /* it is undocked, raise it to the front */
419 /* for the page selectors menu action to dock or undock, set the text */
420 setContextMenuDockText(nextPage, currentitem);
422 treeWidget->addAction(actionToggleDock);
423 /* if this page is closeable, then add that action */
424 if (nextPage->isCloseable()) {
425 treeWidget->addAction(actionClosePage);
428 /* Add the actions to the Page Selectors tree widget that are part of the
429 * current items list of desired actions regardless of whether on top of stack*/
430 treeWidget->addActions(nextPage->m_contextActions);
434 void MainWin::labelButtonClicked()
439 void MainWin::runButtonClicked()
444 void MainWin::restoreButtonClicked()
446 new prerestorePage();
450 * The user just finished typing a line in the command line edit box
452 void MainWin::input_line()
454 QString cmdStr = lineEdit->text(); /* Get the text */
455 lineEdit->clear(); /* clear the lineEdit box */
456 if (m_currentConsole->is_connected()) {
457 m_currentConsole->display_text(cmdStr + "\n");
458 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
460 set_status("Director not connected. Click on connect button.");
462 m_cmd_history.append(cmdStr);
464 if (treeWidget->currentItem() != getFromHash(m_currentConsole))
465 m_currentConsole->setCurrent();
469 void MainWin::about()
471 QMessageBox::about(this, tr("About bat"),
472 tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
473 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
474 "<p>The <b>bat</b> is an administrative console"
475 " interface to the Director."));
478 void MainWin::set_statusf(const char *fmt, ...)
483 va_start(arg_ptr, fmt);
484 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
489 void MainWin::set_status_ready()
491 set_status(" Ready");
494 void MainWin::set_status(const char *buf)
496 statusBar()->showMessage(buf);
500 * Function to respond to the button bar button to undock
502 void MainWin::undockWindowButton()
504 Pages* page = (Pages*)stackedWidget->currentWidget();
505 page->togglePageDocking();
506 /* The window has been undocked, lets change the context menu */
507 setContextMenuDockText();
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();
523 if (page->isDocked()) {
524 stackedWidget->setCurrentWidget(page);
526 /* Toggle the menu item. The window's dock status has been toggled */
527 setContextMenuDockText(page, currentitem);
532 * Function to set the text of the toggle dock context menu when page and
533 * widget item are NOT known. This is an overoaded funciton.
534 * It is called from MainWin::undockWindowButton, it is not intended to change
535 * for the top pages tree widget, it is for the currently active tree widget
536 * item. Which is why the page is not passed.
538 void MainWin::setContextMenuDockText()
540 QTreeWidgetItem *currentitem = treeWidget->currentItem();
542 /* Is this a page that has been inserted into the hash */
543 if (getFromHash(currentitem)) {
544 Pages* page = getFromHash(currentitem);
545 setContextMenuDockText(page, currentitem);
550 * Function to set the text of the toggle dock context menu when page and
551 * widget item are known. This is the more commonly used.
553 void MainWin::setContextMenuDockText(Pages* page, QTreeWidgetItem* item)
555 QString docktext("");
556 if (page->isDocked()) {
557 docktext += "UnDock ";
559 docktext += "ReDock ";
561 docktext += item->text(0) += " Window";
563 actionToggleDock->setText(docktext);
564 setTreeWidgetItemDockColor(page, item);
568 * Function to set the color of the tree widget item based on whether it is
571 void MainWin::setTreeWidgetItemDockColor(Pages* page, QTreeWidgetItem* item)
573 if (item->text(0) != "Console") {
574 if (page->isDocked()) {
575 /* Set the brush to blue if undocked */
576 QBrush blackBrush(Qt::black);
577 item->setForeground(0, blackBrush);
579 /* Set the brush back to black if docked */
580 QBrush blueBrush(Qt::blue);
581 item->setForeground(0, blueBrush);
587 * Overload of previous function, use treeindex to get item from page
588 * This is called when an undocked window is closed.
590 void MainWin::setTreeWidgetItemDockColor(Pages* page)
592 QTreeWidgetItem* item = getFromHash(page);
594 setTreeWidgetItemDockColor(page, item);
599 * This function is called when the stack item is changed. Call
600 * the virtual function here. Avoids a window being undocked leaving
601 * a window at the top of the stack unpopulated.
603 void MainWin::stackItemChanged(int)
605 Pages* page = (Pages*)stackedWidget->currentWidget();
606 /* run the virtual function in case this class overrides it */
607 page->currentStackItem();
611 * Function to simplify insertion of QTreeWidgetItem <-> Page association
612 * into a double direction hash.
614 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
616 m_pagehash.insert(item, page);
617 m_widgethash.insert(page, item);
621 * Function to simplify removal of QTreeWidgetItem <-> Page association
622 * into a double direction hash.
624 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
626 /* I had all sorts of return status checking code here. Do we have a log
627 * level capability in bat. I would have left it in but it used printf's
628 * and it should really be some kind of log level facility ???
629 * ******FIXME********/
630 m_pagehash.remove(item);
631 m_widgethash.remove(page);
635 * Function to retrieve a Page* when the item in the page selector's tree is
638 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
640 return m_pagehash.value(item);
644 * Function to retrieve the page selectors tree widget item when the page is
647 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
649 return m_widgethash.value(page);
653 * Function to respond to action on page selector context menu to close the
656 void MainWin::closePage()
658 QTreeWidgetItem *currentitem = treeWidget->currentItem();
660 /* Is this a page that has been inserted into the hash */
661 if (getFromHash(currentitem)) {
662 Pages* page = getFromHash(currentitem);
663 if (page->isCloseable()) {
664 page->closeStackPage();
669 /* Quick function to return the current console */
670 Console *MainWin::currentConsole()
672 return m_currentConsole;
674 /* Quick function to return the tree item for the director */
675 QTreeWidgetItem *MainWin::currentTopItem()
677 return m_currentConsole->directorTreeItem();