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"
41 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
45 setupUi(this); /* Setup UI defined by main.ui (designer) */
47 treeWidget->setColumnCount(1);
48 treeWidget->setHeaderLabel("Select Page");
49 treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
61 foreach(Console *console, m_consoleHash){
64 m_currentConsole = (Console*)getFromHash(m_firstItem);
65 treeWidget->setCurrentItem(getFromHash(m_currentConsole));
66 DIRRES* dirres = m_currentConsole->getDirRes();
67 printf("Setting initial window to %s\n", dirres->name());
70 void MainWin::createPages()
73 QTreeWidgetItem *item, *topItem;
77 foreach_res(dir, R_DIRECTOR) {
79 /* Create console tree stacked widget item */
80 m_currentConsole = new Console(stackedWidget);
81 m_currentConsole->setDirRes(dir);
82 m_currentConsole->readSettings();
84 /* The top tree item representing the director */
85 topItem = createTopPage(dir->name());
86 topItem->setIcon(0, QIcon(QString::fromUtf8("images/server.png")));
87 /* Set background to grey for ease of identification of inactive dirfector */
88 QBrush greyBrush(Qt::lightGray);
89 topItem->setBackground(0, greyBrush);
90 m_currentConsole->setDirectorTreeItem(topItem);
91 m_consoleHash.insert(topItem, m_currentConsole);
93 /* Create Tree Widget Item */
94 item = createPage("Console", topItem);
95 if (!m_firstItem){ m_firstItem = item; }
97 /* insert the cosole and tree widget item into the hashes */
98 hashInsert(item, m_currentConsole);
100 /* Set Color of treeWidgetItem for the console
101 * It will be set to green in the console class if the connection is made.
103 QBrush redBrush(Qt::red);
104 item->setForeground(0, redBrush);
105 m_currentConsole->dockPage();
107 /* create instances of the rest of the classes that will by default exist
108 * under each director */
109 createPagebRestore();
110 createPageMediaList();
111 QString emptymedia(""), emptyclient("");
112 createPageJobList(emptymedia, emptyclient);
115 treeWidget->expandItem(topItem);
116 stackedWidget->setCurrentWidget(m_currentConsole);
122 * create an instance of the the brestore class on the stack
124 void MainWin::createPagebRestore()
126 bRestore* brestore = new bRestore();
127 brestore->dockPage();
131 * create an instance of the the medialist class on the stack
133 void MainWin::createPageMediaList()
135 MediaList* medialist = new MediaList();
136 medialist->dockPage();
140 * create an instance of the the joblist class on the stack
142 void MainWin::createPageJobList(QString &media, QString &client)
144 QTreeWidgetItem *item, *holdItem;
146 /* save current tree widget item in case query produces no results */
147 holdItem = treeWidget->currentItem();
148 JobList* joblist = new JobList(media, client);
150 /* If this is a query of jobs on a specific media */
151 if ((media != "") || (client != "")) {
152 item = getFromHash(joblist);
153 treeWidget->setCurrentItem(item);
154 /* did query produce results, if not close window and set back to hold */
155 if (joblist->m_resultCount == 0) {
156 joblist->closeStackPage();
157 treeWidget->setCurrentItem(holdItem);
163 * create an instance of the the Clients class on the stack
165 void MainWin::createPageClients()
167 Clients* clients = new Clients();
172 /* Create a root Tree Widget */
173 QTreeWidgetItem *MainWin::createTopPage(char *name)
175 QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
176 item->setText(0, name);
180 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
181 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
183 QTreeWidgetItem *item = new QTreeWidgetItem(parent);
184 item->setText(0, name);
189 * Handle up and down arrow keys for the command line
192 void MainWin::keyPressEvent(QKeyEvent *event)
194 if (m_cmd_history.size() == 0) {
198 switch (event->key()) {
200 if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
207 if (m_cmd_last == 0) {
211 if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
212 m_cmd_last = m_cmd_history.size() - 1;
221 lineEdit->setText(m_cmd_history[m_cmd_last]);
224 void MainWin::createConnections()
226 /* Connect signals to slots */
227 connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
228 connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
229 connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this,
230 SLOT(treeItemClicked(QTreeWidgetItem *, int)));
231 connect(treeWidget, SIGNAL(
232 currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
233 this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
234 connect(stackedWidget, SIGNAL(currentChanged(int)),
235 this, SLOT(stackItemChanged(int)));
236 connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
237 connect(actionLabel, SIGNAL(triggered()), this, SLOT(labelDialogClicked()));
238 connect(actionRun, SIGNAL(triggered()), this, SLOT(runDialogClicked()));
239 connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreDialogClicked()));
240 connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
241 connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
242 connect(actionClosePage, SIGNAL(triggered()), this, SLOT(closePage()));
246 * Reimplementation of QWidget closeEvent virtual function
248 void MainWin::closeEvent(QCloseEvent *event)
251 foreach(Console *console, m_consoleHash){
252 console->writeSettings();
253 console->terminate();
256 foreach(Pages *page, m_pagehash) {
257 if (!page->isDocked())
262 void MainWin::writeSettings()
264 QSettings settings("bacula.org", "bat");
266 settings.beginGroup("MainWin");
267 settings.setValue("winSize", size());
268 settings.setValue("winPos", pos());
272 void MainWin::readSettings()
274 QSettings settings("bacula.org", "bat");
276 settings.beginGroup("MainWin");
277 resize(settings.value("winSize", QSize(1041, 801)).toSize());
278 move(settings.value("winPos", QPoint(200, 150)).toPoint());
283 * This subroutine is called with an item in the Page Selection window
286 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
288 /* Is this a page that has been inserted into the hash */
289 if (getFromHash(item)) {
290 Pages* page = getFromHash(item);
291 int stackindex=stackedWidget->indexOf(page);
293 if (stackindex >= 0) {
294 stackedWidget->setCurrentWidget(page);
296 /* run the virtual function in case this class overrides it */
297 page->PgSeltreeWidgetClicked();
302 * Called with a change of the highlighed tree widget item in the page selector.
304 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
306 Pages *previousPage, *nextPage;
307 Console *previousConsole, *nextConsole;
309 /* first determine the next item */
311 /* knowing the treeWidgetItem, get the page from the hash */
312 nextPage = getFromHash(currentitem);
313 nextConsole = m_consoleHash.value(currentitem);
314 /* Is this a page that has been inserted into the hash */
316 nextConsole = nextPage->console();
317 /* then is it a treeWidgetItem representing a director */
318 } else if (nextConsole) {
319 /* let the next page BE the console */
320 nextPage = nextConsole;
322 printf("Should never get here\n");
327 /* The Previous item */
329 /* this condition prevents a segfault. The first time there is no previousitem*/
331 /* knowing the treeWidgetItem, get the page from the hash */
332 previousPage = getFromHash(previousitem);
333 previousConsole = m_consoleHash.value(previousitem);
335 previousConsole = previousPage->console();
336 } else if (previousConsole) {
337 previousPage = previousConsole;
339 if ((previousPage) || (previousConsole)) {
340 if (nextConsole != previousConsole) {
341 /* remove connections to the current console */
342 disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
343 disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
344 disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
345 QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
346 QBrush greyBrush(Qt::lightGray);
347 dirItem->setBackground(0, greyBrush);
349 /* make sure the close window and toggle dock options are removed */
350 treeWidget->removeAction(actionClosePage);
351 treeWidget->removeAction(actionToggleDock);
352 /* Is this a page that has been inserted into the hash */
354 foreach(QAction* pageaction, previousPage->m_contextActions) {
355 treeWidget->removeAction(pageaction);
361 /* now process the next item */
363 if ((nextPage) || (nextConsole)) {
364 if (nextConsole != previousConsole) {
365 /* make connections to the current console */
366 m_currentConsole = nextConsole;
367 connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
368 connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
369 connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
370 /* Set director's tree widget background to magenta for ease of identification */
371 QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
372 QBrush magentaBrush(Qt::magenta);
373 dirItem->setBackground(0, magentaBrush);
375 /* set the value for the currently active console */
376 int stackindex = stackedWidget->indexOf(nextPage);
378 /* Is this page currently on the stack or is it undocked */
379 if (stackindex >= 0) {
380 /* put this page on the top of the stack */
381 stackedWidget->setCurrentIndex(stackindex);
383 /* it is undocked, raise it to the front */
386 /* for the page selectors menu action to dock or undock, set the text */
387 setContextMenuDockText(nextPage, currentitem);
389 treeWidget->addAction(actionToggleDock);
390 /* if this page is closeable, then add that action */
391 if (nextPage->isCloseable()) {
392 treeWidget->addAction(actionClosePage);
395 /* Add the actions to the Page Selectors tree widget that are part of the
396 * current items list of desired actions regardless of whether on top of stack*/
397 treeWidget->addActions(nextPage->m_contextActions);
401 void MainWin::labelDialogClicked()
403 new labelDialog(m_currentConsole);
406 void MainWin::runDialogClicked()
408 new runDialog(m_currentConsole);
411 void MainWin::restoreDialogClicked()
413 new prerestoreDialog(m_currentConsole);
417 * The user just finished typing a line in the command line edit box
419 void MainWin::input_line()
421 QString cmdStr = lineEdit->text(); /* Get the text */
422 lineEdit->clear(); /* clear the lineEdit box */
423 if (m_currentConsole->is_connected()) {
424 m_currentConsole->display_text(cmdStr + "\n");
425 m_currentConsole->write_dir(cmdStr.toUtf8().data()); /* send to dir */
427 set_status("Director not connected. Click on connect button.");
429 m_cmd_history.append(cmdStr);
434 void MainWin::about()
436 QMessageBox::about(this, tr("About bat"),
437 tr("<br><h2>bat 0.2, by Kern Sibbald</h2>"
438 "<p>Copyright © " BYEAR " Free Software Foundation Europe e.V."
439 "<p>The <b>bat</b> is an administrative console"
440 " interface to the Director."));
443 void MainWin::set_statusf(const char *fmt, ...)
448 va_start(arg_ptr, fmt);
449 len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
454 void MainWin::set_status_ready()
456 set_status(" Ready");
459 void MainWin::set_status(const char *buf)
461 statusBar()->showMessage(buf);
465 * Function to respond to the button bar button to undock
467 void MainWin::undockWindowButton()
469 Pages* page = (Pages*)stackedWidget->currentWidget();
470 page->togglePageDocking();
471 /* The window has been undocked, lets change the context menu */
472 setContextMenuDockText();
476 * Function to respond to action on page selector context menu to toggle the
477 * dock status of the window associated with the page selectors current
480 void MainWin::toggleDockContextWindow()
482 QTreeWidgetItem *currentitem = treeWidget->currentItem();
484 /* Is this a page that has been inserted into the hash */
485 if (getFromHash(currentitem)) {
486 Pages* page = getFromHash(currentitem);
487 page->togglePageDocking();
488 if (page->isDocked()) {
489 stackedWidget->setCurrentWidget(page);
491 /* Toggle the menu item. The window's dock status has been toggled */
492 setContextMenuDockText(page, currentitem);
497 * Function to set the text of the toggle dock context menu when page and
498 * widget item are NOT known. This is an overoaded funciton.
499 * It is called from MainWin::undockWindowButton, it is not intended to change
500 * for the top pages tree widget, it is for the currently active tree widget
501 * item. Which is why the page is not passed.
503 void MainWin::setContextMenuDockText()
505 QTreeWidgetItem *currentitem = treeWidget->currentItem();
507 /* Is this a page that has been inserted into the hash */
508 if (getFromHash(currentitem)) {
509 Pages* page = getFromHash(currentitem);
510 setContextMenuDockText(page, currentitem);
515 * Function to set the text of the toggle dock context menu when page and
516 * widget item are known. This is the more commonly used.
518 void MainWin::setContextMenuDockText(Pages* page, QTreeWidgetItem* item)
520 QString docktext("");
521 if (page->isDocked()) {
522 docktext += "UnDock ";
524 docktext += "ReDock ";
526 docktext += item->text(0) += " Window";
528 actionToggleDock->setText(docktext);
529 setTreeWidgetItemDockColor(page, item);
533 * Function to set the color of the tree widget item based on whether it is
536 void MainWin::setTreeWidgetItemDockColor(Pages* page, QTreeWidgetItem* item)
538 if (item->text(0) != "Console") {
539 if (page->isDocked()) {
540 /* Set the brush to blue if undocked */
541 QBrush blackBrush(Qt::black);
542 item->setForeground(0, blackBrush);
544 /* Set the brush back to black if docked */
545 QBrush blueBrush(Qt::blue);
546 item->setForeground(0, blueBrush);
552 * Overload of previous function, use treeindex to get item from page
553 * This is called when an undocked window is closed.
555 void MainWin::setTreeWidgetItemDockColor(Pages* page)
557 QTreeWidgetItem* item = getFromHash(page);
559 setTreeWidgetItemDockColor(page, item);
564 * This function is called when the stack item is changed. Call
565 * the virtual function here. Avoids a window being undocked leaving
566 * a window at the top of the stack unpopulated.
568 void MainWin::stackItemChanged(int)
570 Pages* page = (Pages*)stackedWidget->currentWidget();
571 /* run the virtual function in case this class overrides it */
572 page->currentStackItem();
576 * Function to simplify insertion of QTreeWidgetItem <-> Page association
577 * into a double direction hash.
579 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
581 m_pagehash.insert(item, page);
582 m_widgethash.insert(page, item);
586 * Function to simplify removal of QTreeWidgetItem <-> Page association
587 * into a double direction hash.
589 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
591 /* I had all sorts of return status checking code here. Do we have a log
592 * level capability in bat. I would have left it in but it used printf's
593 * and it should really be some kind of log level facility ???
594 * ******FIXME********/
595 m_pagehash.remove(item);
596 m_widgethash.remove(page);
600 * Function to retrieve a Page* when the item in the page selector's tree is
603 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
605 return m_pagehash.value(item);
609 * Function to retrieve the page selectors tree widget item when the page is
612 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
614 return m_widgethash.value(page);
618 * Function to respond to action on page selector context menu to close the
621 void MainWin::closePage()
623 QTreeWidgetItem *currentitem = treeWidget->currentItem();
625 /* Is this a page that has been inserted into the hash */
626 if (getFromHash(currentitem)) {
627 Pages* page = getFromHash(currentitem);
628 if (page->isCloseable()) {
629 page->closeStackPage();