]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
Implement crude preferences dialog
[bacula/bacula] / bacula / src / qt-console / mainwin.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
5
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.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28
29 /*
30  *   Version $Id$
31  *
32  *  Main Window control for bat (qt-console)
33  *
34  *   Kern Sibbald, January MMVII
35  *
36  */ 
37
38 #include "bat.h"
39 #include "joblist/joblist.h"
40 #include "storage/storage.h"
41 #include "fileset/fileset.h"
42 #include "label/label.h"
43 #include "run/run.h"
44 #include "pages.h"
45 #include "restore/restore.h"
46 #include "medialist/medialist.h"
47 #include "joblist/joblist.h"
48 #include "clients/clients.h"
49
50 extern bool commDebug;
51
52 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
53 {
54
55    mainWin = this;
56    setupUi(this);                     /* Setup UI defined by main.ui (designer) */
57    treeWidget->clear();
58    treeWidget->setColumnCount(1);
59    treeWidget->setHeaderLabel("Select Page");
60    treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
61
62    createPages();
63
64    resetFocus();
65
66    createConnections();
67
68    this->show();
69
70    readSettings();
71
72    foreach(Console *console, m_consoleHash){
73       console->connect();
74    }
75    m_currentConsole = (Console*)getFromHash(m_firstItem);
76    m_currentConsole->setCurrent();
77    /*  FIXME
78     *  I'd like to turn this into a debug item
79     *  DIRRES* dirres = m_currentConsole->getDirRes();
80     *  printf("Setting initial window to %s\n", dirres->name());
81     */
82 }
83
84 void MainWin::createPages()
85 {
86    DIRRES *dir;
87    QTreeWidgetItem *item, *topItem;
88    m_firstItem = NULL;
89
90    LockRes();
91    foreach_res(dir, R_DIRECTOR) {
92
93       /* Create console tree stacked widget item */
94       m_currentConsole = new Console(stackedWidget);
95       m_currentConsole->setDirRes(dir);
96       m_currentConsole->readSettings();
97
98       /* The top tree item representing the director */
99       topItem = createTopPage(dir->name());
100       topItem->setIcon(0, QIcon(":images/server.png"));
101       /* Set background to grey for ease of identification of inactive dirfector */
102       QBrush greyBrush(Qt::lightGray);
103       topItem->setBackground(0, greyBrush);
104       m_currentConsole->setDirectorTreeItem(topItem);
105       m_consoleHash.insert(topItem, m_currentConsole);
106
107       /* Create Tree Widget Item */
108       item = createPage("Console", topItem);
109       if (!m_firstItem){ m_firstItem = item; }
110
111       /* insert the cosole and tree widget item into the hashes */
112       hashInsert(item, m_currentConsole);
113
114       /* Set Color of treeWidgetItem for the console
115       * It will be set to green in the console class if the connection is made.
116       */
117       QBrush redBrush(Qt::red);
118       item->setForeground(0, redBrush);
119       m_currentConsole->dockPage();
120
121       /* create instances of the rest of the classes that will by default exist
122       * under each director */
123 //    createPagebRestore();
124       createPageMediaList();
125       QString emptymedia(""), emptyclient("");
126       createPageJobList(emptymedia, emptyclient, NULL);
127       createPageClients();
128       createPageStorage();
129       createPageFileSet();
130
131       treeWidget->expandItem(topItem);
132       stackedWidget->setCurrentWidget(m_currentConsole);
133    }
134    UnlockRes();
135 }
136
137 /*
138  * create an instance of the the brestore class on the stack
139  */
140 void MainWin::createPagebRestore()
141 {
142    bRestore* brestore = new bRestore();
143    brestore->dockPage();
144 }
145
146 /*
147  * create an instance of the the medialist class on the stack
148  */
149 void MainWin::createPageMediaList()
150 {
151    MediaList* medialist = new MediaList();
152    medialist->dockPage();
153 }
154
155 /*
156  * create an instance of the the joblist class on the stack
157  */
158 void MainWin::createPageJobList(QString &media, QString &client,
159               QTreeWidgetItem *parentTreeWidgetItem)
160 {
161    QTreeWidgetItem *holdItem;
162
163    /* save current tree widget item in case query produces no results */
164    holdItem = treeWidget->currentItem();
165    JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
166    joblist->dockPage();
167    /* If this is a query of jobs on a specific media */
168    if ((media != "") || (client != "")) {
169       joblist->setCurrent();
170       /* did query produce results, if not close window and set back to hold */
171       if (joblist->m_resultCount == 0) {
172          joblist->closeStackPage();
173          treeWidget->setCurrentItem(holdItem);
174       }
175    }
176 }
177
178 /*
179  * create an instance of the the Clients class on the stack
180  */
181 void MainWin::createPageClients()
182 {
183    Clients* clients = new Clients();
184    clients->dockPage();
185 }
186
187 /*
188  * create an instance of the the storage class on the stack
189  */
190 void MainWin::createPageStorage()
191 {
192    Storage* storage = new Storage();
193    storage->dockPage();
194 }
195
196 /*
197  * create an instance of the the fileset class on the stack
198  */
199 void MainWin::createPageFileSet()
200 {
201    FileSet* fileset = new FileSet();
202    fileset->dockPage();
203 }
204
205 /* Create a root Tree Widget */
206 QTreeWidgetItem *MainWin::createTopPage(char *name)
207 {
208    QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
209    item->setText(0, name);
210    return item;
211 }
212
213 /* Create A Tree Widget Item which will be associated with a Page in the stacked widget */
214 QTreeWidgetItem *MainWin::createPage(char *name, QTreeWidgetItem *parent)
215 {
216    QTreeWidgetItem *item = new QTreeWidgetItem(parent);
217    item->setText(0, name);
218    return item;
219 }
220
221 /*
222  * Handle up and down arrow keys for the command line
223  *  history.
224  */
225 void MainWin::keyPressEvent(QKeyEvent *event)
226 {
227    if (m_cmd_history.size() == 0) {
228       event->ignore();
229       return;
230    }
231    switch (event->key()) {
232    case Qt::Key_Down:
233       if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
234          event->ignore();
235          return;
236       }
237       m_cmd_last++;
238       break;
239    case Qt::Key_Up:
240       if (m_cmd_last == 0) {
241          event->ignore();
242          return;
243       }
244       if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
245          m_cmd_last = m_cmd_history.size() - 1;
246       } else {
247          m_cmd_last--;
248       }
249       break;
250    default:
251       event->ignore();
252       return;
253    }
254    lineEdit->setText(m_cmd_history[m_cmd_last]);
255 }
256
257 void MainWin::createConnections()
258 {
259    /* Connect signals to slots */
260    connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
261    connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
262    connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, 
263            SLOT(treeItemClicked(QTreeWidgetItem *, int)));
264    connect(treeWidget, SIGNAL(
265            currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
266            this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
267    connect(stackedWidget, SIGNAL(currentChanged(int)),
268            this, SLOT(stackItemChanged(int)));
269    connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
270    connect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
271    connect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
272    connect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
273    connect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
274    connect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
275    connect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closePage()));
276    connect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
277 }
278
279 /* 
280  * Reimplementation of QWidget closeEvent virtual function   
281  */
282 void MainWin::closeEvent(QCloseEvent *event)
283 {
284    writeSettings();
285    foreach(Console *console, m_consoleHash){
286       console->writeSettings();
287       console->terminate();
288    }
289    event->accept();
290    foreach(Pages *page, m_pagehash) {
291       if (!page->isDocked())
292          page->close();
293    }
294 }
295
296 void MainWin::writeSettings()
297 {
298    QSettings settings("bacula.org", "bat");
299
300    settings.beginGroup("MainWin");
301    settings.setValue("winSize", size());
302    settings.setValue("winPos", pos());
303    settings.endGroup();
304 }
305
306 void MainWin::readSettings()
307
308    QSettings settings("bacula.org", "bat");
309
310    settings.beginGroup("MainWin");
311    resize(settings.value("winSize", QSize(1041, 801)).toSize());
312    move(settings.value("winPos", QPoint(200, 150)).toPoint());
313    settings.endGroup();
314 }
315
316 /*
317  * This subroutine is called with an item in the Page Selection window
318  *   is clicked 
319  */
320 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
321 {
322    /* Is this a page that has been inserted into the hash  */
323    if (getFromHash(item)) {
324       Pages* page = getFromHash(item);
325       int stackindex=stackedWidget->indexOf(page);
326
327       if (stackindex >= 0) {
328          stackedWidget->setCurrentWidget(page);
329       }
330       /* run the virtual function in case this class overrides it */
331       page->PgSeltreeWidgetClicked();
332    }
333 }
334
335 /*
336  * Called with a change of the highlighed tree widget item in the page selector.
337  */
338 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
339 {
340    Pages *previousPage, *nextPage;
341    Console *previousConsole, *nextConsole;
342
343    /* first determine the next item */
344
345    /* knowing the treeWidgetItem, get the page from the hash */
346    nextPage = getFromHash(currentitem);
347    nextConsole = m_consoleHash.value(currentitem);
348    /* Is this a page that has been inserted into the hash  */
349    if (nextPage) {
350       nextConsole = nextPage->console();
351       /* then is it a treeWidgetItem representing a director */
352    } else if (nextConsole) {
353       /* let the next page BE the console */
354       nextPage = nextConsole;
355    } else {
356       /* Should never get here */
357       nextPage = NULL;
358       nextConsole = NULL;
359    }
360           
361    /* The Previous item */
362
363    /* this condition prevents a segfault.  The first time there is no previousitem*/
364    if (previousitem) {
365       /* knowing the treeWidgetItem, get the page from the hash */
366       previousPage = getFromHash(previousitem);
367       previousConsole = m_consoleHash.value(previousitem);
368       if (previousPage) {
369          previousConsole = previousPage->console();
370       } else if (previousConsole) {
371          previousPage = previousConsole;
372       }
373       if ((previousPage) || (previousConsole)) {
374          if (nextConsole != previousConsole) {
375             /* remove connections to the current console */
376             disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect()));
377             disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
378             disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
379             disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
380             QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
381             QBrush greyBrush(Qt::lightGray);
382             dirItem->setBackground(0, greyBrush);
383          }
384          /* make sure the close window and toggle dock options are removed */
385          treeWidget->removeAction(actionClosePage);
386          treeWidget->removeAction(actionToggleDock);
387          /* Is this a page that has been inserted into the hash  */
388          if (previousPage) {
389             foreach(QAction* pageaction, previousPage->m_contextActions) {
390                treeWidget->removeAction(pageaction);
391             }
392          } 
393       }
394    }
395
396    /* process the current (next) item */
397    
398    if ((nextPage) || (nextConsole)) {
399       if (nextConsole != previousConsole) {
400          /* make connections to the current console */
401          m_currentConsole = nextConsole;
402          connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect()));
403          connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
404          connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
405          connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
406          /* Set director's tree widget background to magenta for ease of identification */
407          QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
408          QBrush magentaBrush(Qt::magenta);
409          dirItem->setBackground(0, magentaBrush);
410       }
411       /* set the value for the currently active console */
412       int stackindex = stackedWidget->indexOf(nextPage);
413    
414       /* Is this page currently on the stack or is it undocked */
415       if (stackindex >= 0) {
416          /* put this page on the top of the stack */
417          stackedWidget->setCurrentIndex(stackindex);
418       } else {
419          /* it is undocked, raise it to the front */
420          nextPage->raise();
421       }
422       /* for the page selectors menu action to dock or undock, set the text */
423       nextPage->setContextMenuDockText();
424
425       treeWidget->addAction(actionToggleDock);
426       /* if this page is closeable, then add that action */
427       if (nextPage->isCloseable()) {
428          treeWidget->addAction(actionClosePage);
429       }
430
431       /* Add the actions to the Page Selectors tree widget that are part of the
432        * current items list of desired actions regardless of whether on top of stack*/
433       treeWidget->addActions(nextPage->m_contextActions);
434    }
435 }
436
437 void MainWin::labelButtonClicked() 
438 {
439    new labelPage();
440 }
441
442 void MainWin::runButtonClicked() 
443 {
444    new runPage();
445 }
446
447 void MainWin::restoreButtonClicked() 
448 {
449    new prerestorePage();
450 }
451
452 /*
453  * The user just finished typing a line in the command line edit box
454  */
455 void MainWin::input_line()
456 {
457    QString cmdStr = lineEdit->text();    /* Get the text */
458    lineEdit->clear();                    /* clear the lineEdit box */
459    if (m_currentConsole->is_connected()) {
460       m_currentConsole->display_text(cmdStr + "\n");
461       m_currentConsole->write_dir(cmdStr.toUtf8().data());         /* send to dir */
462    } else {
463       set_status("Director not connected. Click on connect button.");
464    }
465    m_cmd_history.append(cmdStr);
466    m_cmd_last = -1;
467    if (treeWidget->currentItem() != getFromHash(m_currentConsole))
468       m_currentConsole->setCurrent();
469 }
470
471
472 void MainWin::about()
473 {
474    QMessageBox::about(this, tr("About bat"),
475       tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
476          "<p>Copyright &copy; " BYEAR " Free Software Foundation Europe e.V."
477          "<p>The <b>bat</b> is an administrative console"
478          " interface to the Director."));
479 }
480
481 void MainWin::set_statusf(const char *fmt, ...)
482 {
483    va_list arg_ptr;
484    char buf[1000];
485    int len;
486    va_start(arg_ptr, fmt);
487    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
488    va_end(arg_ptr);
489    set_status(buf);
490 }
491
492 void MainWin::set_status_ready()
493 {
494    set_status(" Ready");
495 }
496
497 void MainWin::set_status(const char *buf)
498 {
499    statusBar()->showMessage(buf);
500 }
501
502 /*
503  * Function to respond to the button bar button to undock
504  */
505 void MainWin::undockWindowButton()
506 {
507    Pages* page = (Pages*)stackedWidget->currentWidget();
508    page->togglePageDocking();
509 }
510
511 /*
512  * Function to respond to action on page selector context menu to toggle the 
513  * dock status of the window associated with the page selectors current
514  * tree widget item.
515  */
516 void MainWin::toggleDockContextWindow()
517 {
518    QTreeWidgetItem *currentitem = treeWidget->currentItem();
519    
520    /* Is this a page that has been inserted into the hash  */
521    if (getFromHash(currentitem)) {
522       Pages* page = getFromHash(currentitem);
523       page->togglePageDocking();
524    }
525 }
526
527 /*
528  * This function is called when the stack item is changed.  Call
529  * the virtual function here.  Avoids a window being undocked leaving
530  * a window at the top of the stack unpopulated.
531  */
532 void MainWin::stackItemChanged(int)
533 {
534    Pages* page = (Pages*)stackedWidget->currentWidget();
535    /* run the virtual function in case this class overrides it */
536    page->currentStackItem();
537 }
538
539 /*
540  * Function to simplify insertion of QTreeWidgetItem <-> Page association
541  * into a double direction hash.
542  */
543 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
544 {
545    m_pagehash.insert(item, page);
546    m_widgethash.insert(page, item);
547 }
548
549 /*
550  * Function to simplify removal of QTreeWidgetItem <-> Page association
551  * into a double direction hash.
552  */
553 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
554 {
555    /* I had all sorts of return status checking code here.  Do we have a log
556     * level capability in bat.  I would have left it in but it used printf's
557     * and it should really be some kind of log level facility ???
558     * ******FIXME********/
559    m_pagehash.remove(item);
560    m_widgethash.remove(page);
561 }
562
563 /*
564  * Function to retrieve a Page* when the item in the page selector's tree is
565  * known.
566  */
567 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
568 {
569    return m_pagehash.value(item);
570 }
571
572 /*
573  * Function to retrieve the page selectors tree widget item when the page is
574  * known.
575  */
576 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
577 {
578    return m_widgethash.value(page);
579 }
580
581 /*
582  * Function to respond to action on page selector context menu to close the
583  * current window.
584  */
585 void MainWin::closePage()
586 {
587    QTreeWidgetItem *currentitem = treeWidget->currentItem();
588    
589    /* Is this a page that has been inserted into the hash  */
590    if (getFromHash(currentitem)) {
591       Pages* page = getFromHash(currentitem);
592       if (page->isCloseable()) {
593          page->closeStackPage();
594       }
595    }
596 }
597
598 /* Quick function to return the current console */
599 Console *MainWin::currentConsole()
600 {
601    return m_currentConsole;
602 }
603 /* Quick function to return the tree item for the director */
604 QTreeWidgetItem *MainWin::currentTopItem()
605 {
606    return m_currentConsole->directorTreeItem();
607 }
608
609 /* Preferences menu item clicked */
610 void MainWin::setPreferences()
611 {
612    prefsDialog prefs;
613    prefs.checkBox->setCheckState(commDebug ? Qt::Checked : Qt::Unchecked);
614    prefs.exec();
615 }
616
617 /* Preferences dialog */
618 prefsDialog::prefsDialog()
619 {
620    setupUi(this);
621 }
622
623 void prefsDialog::accept()
624 {
625    this->hide();
626    commDebug = this->checkBox->checkState() == Qt::Checked;
627 }
628
629 void prefsDialog::reject()
630 {
631    this->hide();
632    mainWin->set_status("Canceled");
633 }