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"
43 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
47 setupUi(this); /* Setup UI defined by main.ui (designer) */
49 treeWidget->setColumnCount(1);
50 treeWidget->setHeaderLabel("Select Page");
51 treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
63 foreach(Console *console, m_consoleHash){
66 m_currentConsole = (Console*)getFromHash(m_firstItem);
67 treeWidget->setCurrentItem(getFromHash(m_currentConsole));
69 * I'd like to turn this into a debug item
70 * DIRRES* dirres = m_currentConsole->getDirRes();
71 * printf("Setting initial window to %s\n", dirres->name());
75 void MainWin::createPages()
78 QTreeWidgetItem *item, *topItem;
82 foreach_res(dir, R_DIRECTOR) {
84 /* Create console tree stacked widget item */
85 m_currentConsole = new Console(stackedWidget);
86 m_currentConsole->setDirRes(dir);
87 m_currentConsole->readSettings();
89 /* The top tree item representing the director */
90 topItem = createTopPage(dir->name());
91 topItem->setIcon(0, QIcon(":images/server.png"));
92 /* Set background to grey for ease of identification of inactive dirfector */
93 QBrush greyBrush(Qt::lightGray);
94 topItem->setBackground(0, greyBrush);
95 m_currentConsole->setDirectorTreeItem(topItem);
96 m_consoleHash.insert(topItem, m_currentConsole);
98 /* Create Tree Widget Item */
99 item = createPage("Console", topItem);
100 if (!m_firstItem){ m_firstItem = item; }
102 /* insert the cosole and tree widget item into the hashes */
103 hashInsert(item, m_currentConsole);
105 /* Set Color of treeWidgetItem for the console
106 * It will be set to green in the console class if the connection is made.
108 QBrush redBrush(Qt::red);
109 item->setForeground(0, redBrush);
110 m_currentConsole->dockPage();
112 /* create instances of the rest of the classes that will by default exist
113 * under each director */
114 // createPagebRestore();
115 createPageMediaList();
116 QString emptymedia(""), emptyclient("");
117 createPageJobList(emptymedia, emptyclient, NULL);
122 treeWidget->expandItem(topItem);
123 stackedWidget->setCurrentWidget(m_currentConsole);
129 * create an instance of the the brestore class on the stack
131 void MainWin::createPagebRestore()
133 bRestore* brestore = new bRestore();
134 brestore->dockPage();
138 * create an instance of the the medialist class on the stack
140 void MainWin::createPageMediaList()
142 MediaList* medialist = new MediaList();
143 medialist->dockPage();
147 * create an instance of the the joblist class on the stack
149 void MainWin::createPageJobList(QString &media, QString &client,
150 QTreeWidgetItem *parentTreeWidgetItem)
152 QTreeWidgetItem *item, *holdItem;
154 /* save current tree widget item in case query produces no results */
155 holdItem = treeWidget->currentItem();
156 JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
158 /* If this is a query of jobs on a specific media */
159 if ((media != "") || (client != "")) {
160 item = getFromHash(joblist);
161 treeWidget->setCurrentItem(item);
162 /* did query produce results, if not close window and set back to hold */
163 if (joblist->m_resultCount == 0) {
164 joblist->closeStackPage();
165 treeWidget->setCurrentItem(holdItem);
171 * create an instance of the the Clients class on the stack
173 void MainWin::createPageClients()
175 Clients* clients = new Clients();
180 * create an instance of the the storage class on the stack
182 void MainWin::createPageStorage()
184 Storage* storage = new Storage();
189 * create an instance of the the fileset class on the stack
191 void MainWin::createPageFileSet()
193 FileSet* fileset = new FileSet();
197 /* Create a root Tree Widget */
198 QTreeWidgetItem *MainWin::createTopPage(char *name)
200 QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
201 item->setText(0, name);
205 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
206 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
208 QTreeWidgetItem *item = new QTreeWidgetItem(parent);
209 item->setText(0, name);
214 * Handle up and down arrow keys for the command line
217 void MainWin::keyPressEvent(QKeyEvent *event)
219 if (m_cmd_history.size() == 0) {
223 switch (event->key()) {
225 if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
232 if (m_cmd_last == 0) {
236 if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
237 m_cmd_last = m_cmd_history.size() - 1;
246 lineEdit->setText(m_cmd_history[m_cmd_last]);
249 void MainWin::createConnections()
251 /* Connect signals to slots */
252 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
253 connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
254 connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
255 SLOT(treeItemClicked(QTreeWidgetItem *, int)));
256 connect(treeWidget, SIGNAL(
257 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
258 this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
259 connect(stackedWidget, SIGNAL(currentChanged(int)),
260 this, SLOT(stackItemChanged(int)));
261 connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
262 connect(actionLabel, SIGNAL(triggered()), this, SLOT(labelDialogClicked()));
263 connect(actionRun, SIGNAL(triggered()), this, SLOT(runDialogClicked()));
264 connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreDialogClicked()));
265 connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
266 connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
267 connect(actionClosePage, SIGNAL(triggered()), this, SLOT(closePage()));
271 * Reimplementation of QWidget closeEvent virtual function
273 void MainWin::closeEvent(QCloseEvent *event)
276 foreach(Console *console, m_consoleHash){
277 console->writeSettings();
278 console->terminate();
281 foreach(Pages *page, m_pagehash) {
282 if (!page->isDocked())
287 void MainWin::writeSettings()
289 QSettings settings("bacula.org", "bat");
291 settings.beginGroup("MainWin");
292 settings.setValue("winSize", size());
293 settings.setValue("winPos", pos());
297 void MainWin::readSettings()
299 QSettings settings("bacula.org", "bat");
301 settings.beginGroup("MainWin");
302 resize(settings.value("winSize", QSize(1041, 801)).toSize());
303 move(settings.value("winPos", QPoint(200, 150)).toPoint());
308 * This subroutine is called with an item in the Page Selection window
311 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
313 /* Is this a page that has been inserted into the hash */
314 if (getFromHash(item)) {
315 Pages* page = getFromHash(item);
316 int stackindex=stackedWidget->indexOf(page);
318 if (stackindex >= 0) {
319 stackedWidget->setCurrentWidget(page);
321 /* run the virtual function in case this class overrides it */
322 page->PgSeltreeWidgetClicked();
327 * Called with a change of the highlighed tree widget item in the page selector.
329 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
331 Pages *previousPage, *nextPage;
332 Console *previousConsole, *nextConsole;
334 /* first determine the next item */
336 /* knowing the treeWidgetItem, get the page from the hash */
337 nextPage = getFromHash(currentitem);
338 nextConsole = m_consoleHash.value(currentitem);
339 /* Is this a page that has been inserted into the hash */
341 nextConsole = nextPage->console();
342 /* then is it a treeWidgetItem representing a director */
343 } else if (nextConsole) {
344 /* let the next page BE the console */
345 nextPage = nextConsole;
347 /* Should never get here */
352 /* The Previous item */
354 /* this condition prevents a segfault. The first time there is no previousitem*/
356 /* knowing the treeWidgetItem, get the page from the hash */
357 previousPage = getFromHash(previousitem);
358 previousConsole = m_consoleHash.value(previousitem);
360 previousConsole = previousPage->console();
361 } else if (previousConsole) {
362 previousPage = previousConsole;
364 if ((previousPage) || (previousConsole)) {
365 if (nextConsole != previousConsole) {
366 /* remove connections to the current console */
367 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
368 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
369 disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
370 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
371 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
372 QBrush greyBrush(Qt::lightGray);
373 dirItem->setBackground(0, greyBrush);
375 /* make sure the close window and toggle dock options are removed */
376 treeWidget->removeAction(actionClosePage);
377 treeWidget->removeAction(actionToggleDock);
378 /* Is this a page that has been inserted into the hash */
380 foreach(QAction* pageaction, previousPage->m_contextActions) {
381 treeWidget->removeAction(pageaction);
387 /* process the current (next) item */
389 if ((nextPage) || (nextConsole)) {
390 if (nextConsole != previousConsole) {
391 /* make connections to the current console */
392 m_currentConsole = nextConsole;
393 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
394 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
395 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
396 connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
397 /* Set director's tree widget background to magenta for ease of identification */
398 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
399 QBrush magentaBrush(Qt::magenta);
400 dirItem->setBackground(0, magentaBrush);
402 /* set the value for the currently active console */
403 int stackindex = stackedWidget->indexOf(nextPage);
405 /* Is this page currently on the stack or is it undocked */
406 if (stackindex >= 0) {
407 /* put this page on the top of the stack */
408 stackedWidget->setCurrentIndex(stackindex);
410 /* it is undocked, raise it to the front */
413 /* for the page selectors menu action to dock or undock, set the text */
414 setContextMenuDockText(nextPage, currentitem);
416 treeWidget->addAction(actionToggleDock);
417 /* if this page is closeable, then add that action */
418 if (nextPage->isCloseable()) {
419 treeWidget->addAction(actionClosePage);
422 /* Add the actions to the Page Selectors tree widget that are part of the
423 * current items list of desired actions regardless of whether on top of stack*/
424 treeWidget->addActions(nextPage->m_contextActions);
428 void MainWin::labelDialogClicked()
430 new labelDialog(m_currentConsole);
433 void MainWin::runDialogClicked()
435 new runDialog(m_currentConsole);
438 void MainWin::restoreDialogClicked()
440 new prerestoreDialog(m_currentConsole);
444 * The user just finished typing a line in the command line edit box
446 void MainWin::input_line()
448 QString cmdStr = lineEdit->text(); /* Get the text */
449 lineEdit->clear(); /* clear the lineEdit box */
450 if (m_currentConsole->is_connected()) {
451 m_currentConsole->display_text(cmdStr + "\n");
452 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
454 set_status("Director not connected. Click on connect button.");
456 m_cmd_history.append(cmdStr);
458 if (treeWidget->currentItem() != getFromHash(m_currentConsole)){
459 treeWidget->setCurrentItem(getFromHash(m_currentConsole));
464 void MainWin::about()
466 QMessageBox::about(this, tr("About bat"),
467 tr("<br><h2>bat 0.2, by Kern Sibbald</h2>"
468 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
469 "<p>The <b>bat</b> is an administrative console"
470 " interface to the Director."));
473 void MainWin::set_statusf(const char *fmt, ...)
478 va_start(arg_ptr, fmt);
479 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
484 void MainWin::set_status_ready()
486 set_status(" Ready");
489 void MainWin::set_status(const char *buf)
491 statusBar()->showMessage(buf);
495 * Function to respond to the button bar button to undock
497 void MainWin::undockWindowButton()
499 Pages* page = (Pages*)stackedWidget->currentWidget();
500 page->togglePageDocking();
501 /* The window has been undocked, lets change the context menu */
502 setContextMenuDockText();
506 * Function to respond to action on page selector context menu to toggle the
507 * dock status of the window associated with the page selectors current
510 void MainWin::toggleDockContextWindow()
512 QTreeWidgetItem *currentitem = treeWidget->currentItem();
514 /* Is this a page that has been inserted into the hash */
515 if (getFromHash(currentitem)) {
516 Pages* page = getFromHash(currentitem);
517 page->togglePageDocking();
518 if (page->isDocked()) {
519 stackedWidget->setCurrentWidget(page);
521 /* Toggle the menu item. The window's dock status has been toggled */
522 setContextMenuDockText(page, currentitem);
527 * Function to set the text of the toggle dock context menu when page and
528 * widget item are NOT known. This is an overoaded funciton.
529 * It is called from MainWin::undockWindowButton, it is not intended to change
530 * for the top pages tree widget, it is for the currently active tree widget
531 * item. Which is why the page is not passed.
533 void MainWin::setContextMenuDockText()
535 QTreeWidgetItem *currentitem = treeWidget->currentItem();
537 /* Is this a page that has been inserted into the hash */
538 if (getFromHash(currentitem)) {
539 Pages* page = getFromHash(currentitem);
540 setContextMenuDockText(page, currentitem);
545 * Function to set the text of the toggle dock context menu when page and
546 * widget item are known. This is the more commonly used.
548 void MainWin::setContextMenuDockText(Pages* page, QTreeWidgetItem* item)
550 QString docktext("");
551 if (page->isDocked()) {
552 docktext += "UnDock ";
554 docktext += "ReDock ";
556 docktext += item->text(0) += " Window";
558 actionToggleDock->setText(docktext);
559 setTreeWidgetItemDockColor(page, item);
563 * Function to set the color of the tree widget item based on whether it is
566 void MainWin::setTreeWidgetItemDockColor(Pages* page, QTreeWidgetItem* item)
568 if (item->text(0) != "Console") {
569 if (page->isDocked()) {
570 /* Set the brush to blue if undocked */
571 QBrush blackBrush(Qt::black);
572 item->setForeground(0, blackBrush);
574 /* Set the brush back to black if docked */
575 QBrush blueBrush(Qt::blue);
576 item->setForeground(0, blueBrush);
582 * Overload of previous function, use treeindex to get item from page
583 * This is called when an undocked window is closed.
585 void MainWin::setTreeWidgetItemDockColor(Pages* page)
587 QTreeWidgetItem* item = getFromHash(page);
589 setTreeWidgetItemDockColor(page, item);
594 * This function is called when the stack item is changed. Call
595 * the virtual function here. Avoids a window being undocked leaving
596 * a window at the top of the stack unpopulated.
598 void MainWin::stackItemChanged(int)
600 Pages* page = (Pages*)stackedWidget->currentWidget();
601 /* run the virtual function in case this class overrides it */
602 page->currentStackItem();
606 * Function to simplify insertion of QTreeWidgetItem <-> Page association
607 * into a double direction hash.
609 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
611 m_pagehash.insert(item, page);
612 m_widgethash.insert(page, item);
616 * Function to simplify removal of QTreeWidgetItem <-> Page association
617 * into a double direction hash.
619 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
621 /* I had all sorts of return status checking code here. Do we have a log
622 * level capability in bat. I would have left it in but it used printf's
623 * and it should really be some kind of log level facility ???
624 * ******FIXME********/
625 m_pagehash.remove(item);
626 m_widgethash.remove(page);
630 * Function to retrieve a Page* when the item in the page selector's tree is
633 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
635 return m_pagehash.value(item);
639 * Function to retrieve the page selectors tree widget item when the page is
642 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
644 return m_widgethash.value(page);
648 * Function to respond to action on page selector context menu to close the
651 void MainWin::closePage()
653 QTreeWidgetItem *currentitem = treeWidget->currentItem();
655 /* Is this a page that has been inserted into the hash */
656 if (getFromHash(currentitem)) {
657 Pages* page = getFromHash(currentitem);
658 if (page->isCloseable()) {
659 page->closeStackPage();