]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
Addressed issue of long compiles. Simplify with Pages::setCurrent
[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 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
51 {
52
53    mainWin = this;
54    setupUi(this);                     /* Setup UI defined by main.ui (designer) */
55    treeWidget->clear();
56    treeWidget->setColumnCount(1);
57    treeWidget->setHeaderLabel("Select Page");
58    treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
59
60    createPages();
61
62    resetFocus();
63
64    createConnections();
65
66    this->show();
67
68    readSettings();
69
70    foreach(Console *console, m_consoleHash){
71       console->connect();
72    }
73    m_currentConsole = (Console*)getFromHash(m_firstItem);
74    m_currentConsole->setCurrent();
75    /*  FIXME
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());
79     */
80 }
81
82 void MainWin::createPages()
83 {
84    DIRRES *dir;
85    QTreeWidgetItem *item, *topItem;
86    m_firstItem = NULL;
87
88    LockRes();
89    foreach_res(dir, R_DIRECTOR) {
90
91       /* Create console tree stacked widget item */
92       m_currentConsole = new Console(stackedWidget);
93       m_currentConsole->setDirRes(dir);
94       m_currentConsole->readSettings();
95
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);
104
105       /* Create Tree Widget Item */
106       item = createPage("Console", topItem);
107       if (!m_firstItem){ m_firstItem = item; }
108
109       /* insert the cosole and tree widget item into the hashes */
110       hashInsert(item, m_currentConsole);
111
112       /* Set Color of treeWidgetItem for the console
113       * It will be set to green in the console class if the connection is made.
114       */
115       QBrush redBrush(Qt::red);
116       item->setForeground(0, redBrush);
117       m_currentConsole->dockPage();
118
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);
125       createPageClients();
126       createPageStorage();
127       createPageFileSet();
128
129       treeWidget->expandItem(topItem);
130       stackedWidget->setCurrentWidget(m_currentConsole);
131    }
132    UnlockRes();
133 }
134
135 /*
136  * create an instance of the the brestore class on the stack
137  */
138 void MainWin::createPagebRestore()
139 {
140    bRestore* brestore = new bRestore();
141    brestore->dockPage();
142 }
143
144 /*
145  * create an instance of the the medialist class on the stack
146  */
147 void MainWin::createPageMediaList()
148 {
149    MediaList* medialist = new MediaList();
150    medialist->dockPage();
151 }
152
153 /*
154  * create an instance of the the joblist class on the stack
155  */
156 void MainWin::createPageJobList(QString &media, QString &client,
157               QTreeWidgetItem *parentTreeWidgetItem)
158 {
159    QTreeWidgetItem *holdItem;
160
161    /* save current tree widget item in case query produces no results */
162    holdItem = treeWidget->currentItem();
163    JobList* joblist = new JobList(media, client, parentTreeWidgetItem);
164    joblist->dockPage();
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);
172       }
173    }
174 }
175
176 /*
177  * create an instance of the the Clients class on the stack
178  */
179 void MainWin::createPageClients()
180 {
181    Clients* clients = new Clients();
182    clients->dockPage();
183 }
184
185 /*
186  * create an instance of the the storage class on the stack
187  */
188 void MainWin::createPageStorage()
189 {
190    Storage* storage = new Storage();
191    storage->dockPage();
192 }
193
194 /*
195  * create an instance of the the fileset class on the stack
196  */
197 void MainWin::createPageFileSet()
198 {
199    FileSet* fileset = new FileSet();
200    fileset->dockPage();
201 }
202
203 /* Create a root Tree Widget */
204 QTreeWidgetItem *MainWin::createTopPage(char *name)
205 {
206    QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
207    item->setText(0, name);
208    return item;
209 }
210
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)
213 {
214    QTreeWidgetItem *item = new QTreeWidgetItem(parent);
215    item->setText(0, name);
216    return item;
217 }
218
219 /*
220  * Handle up and down arrow keys for the command line
221  *  history.
222  */
223 void MainWin::keyPressEvent(QKeyEvent *event)
224 {
225    if (m_cmd_history.size() == 0) {
226       event->ignore();
227       return;
228    }
229    switch (event->key()) {
230    case Qt::Key_Down:
231       if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
232          event->ignore();
233          return;
234       }
235       m_cmd_last++;
236       break;
237    case Qt::Key_Up:
238       if (m_cmd_last == 0) {
239          event->ignore();
240          return;
241       }
242       if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
243          m_cmd_last = m_cmd_history.size() - 1;
244       } else {
245          m_cmd_last--;
246       }
247       break;
248    default:
249       event->ignore();
250       return;
251    }
252    lineEdit->setText(m_cmd_history[m_cmd_last]);
253 }
254
255 void MainWin::createConnections()
256 {
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(labelDialogClicked()));
269    connect(actionRun, SIGNAL(triggered()), this,  SLOT(runDialogClicked()));
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()));
274 }
275
276 /* 
277  * Reimplementation of QWidget closeEvent virtual function   
278  */
279 void MainWin::closeEvent(QCloseEvent *event)
280 {
281    writeSettings();
282    foreach(Console *console, m_consoleHash){
283       console->writeSettings();
284       console->terminate();
285    }
286    event->accept();
287    foreach(Pages *page, m_pagehash) {
288       if (!page->isDocked())
289          page->close();
290    }
291 }
292
293 void MainWin::writeSettings()
294 {
295    QSettings settings("bacula.org", "bat");
296
297    settings.beginGroup("MainWin");
298    settings.setValue("winSize", size());
299    settings.setValue("winPos", pos());
300    settings.endGroup();
301 }
302
303 void MainWin::readSettings()
304
305    QSettings settings("bacula.org", "bat");
306
307    settings.beginGroup("MainWin");
308    resize(settings.value("winSize", QSize(1041, 801)).toSize());
309    move(settings.value("winPos", QPoint(200, 150)).toPoint());
310    settings.endGroup();
311 }
312
313 /*
314  * This subroutine is called with an item in the Page Selection window
315  *   is clicked 
316  */
317 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
318 {
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);
323
324       if (stackindex >= 0) {
325          stackedWidget->setCurrentWidget(page);
326       }
327       /* run the virtual function in case this class overrides it */
328       page->PgSeltreeWidgetClicked();
329    }
330 }
331
332 /*
333  * Called with a change of the highlighed tree widget item in the page selector.
334  */
335 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
336 {
337    Pages *previousPage, *nextPage;
338    Console *previousConsole, *nextConsole;
339
340    /* first determine the next item */
341
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  */
346    if (nextPage) {
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;
352    } else {
353       /* Should never get here */
354       nextPage = NULL;
355       nextConsole = NULL;
356    }
357           
358    /* The Previous item */
359
360    /* this condition prevents a segfault.  The first time there is no previousitem*/
361    if (previousitem) {
362       /* knowing the treeWidgetItem, get the page from the hash */
363       previousPage = getFromHash(previousitem);
364       previousConsole = m_consoleHash.value(previousitem);
365       if (previousPage) {
366          previousConsole = previousPage->console();
367       } else if (previousConsole) {
368          previousPage = previousConsole;
369       }
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);
380          }
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  */
385          if (previousPage) {
386             foreach(QAction* pageaction, previousPage->m_contextActions) {
387                treeWidget->removeAction(pageaction);
388             }
389          } 
390       }
391    }
392
393    /* process the current (next) item */
394    
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);
407       }
408       /* set the value for the currently active console */
409       int stackindex = stackedWidget->indexOf(nextPage);
410    
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);
415       } else {
416          /* it is undocked, raise it to the front */
417          nextPage->raise();
418       }
419       /* for the page selectors menu action to dock or undock, set the text */
420       setContextMenuDockText(nextPage, currentitem);
421
422       treeWidget->addAction(actionToggleDock);
423       /* if this page is closeable, then add that action */
424       if (nextPage->isCloseable()) {
425          treeWidget->addAction(actionClosePage);
426       }
427
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);
431    }
432 }
433
434 void MainWin::labelDialogClicked() 
435 {
436    new labelDialog(m_currentConsole);
437 }
438
439 void MainWin::runDialogClicked() 
440 {
441    new runDialog(m_currentConsole);
442 }
443
444 void MainWin::restoreButtonClicked() 
445 {
446    new prerestorePage(m_currentConsole);
447 }
448
449 /*
450  * The user just finished typing a line in the command line edit box
451  */
452 void MainWin::input_line()
453 {
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 */
459    } else {
460       set_status("Director not connected. Click on connect button.");
461    }
462    m_cmd_history.append(cmdStr);
463    m_cmd_last = -1;
464    if (treeWidget->currentItem() != getFromHash(m_currentConsole))
465       m_currentConsole->setCurrent();
466 }
467
468
469 void MainWin::about()
470 {
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 &copy; " BYEAR " Free Software Foundation Europe e.V."
474          "<p>The <b>bat</b> is an administrative console"
475          " interface to the Director."));
476 }
477
478 void MainWin::set_statusf(const char *fmt, ...)
479 {
480    va_list arg_ptr;
481    char buf[1000];
482    int len;
483    va_start(arg_ptr, fmt);
484    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
485    va_end(arg_ptr);
486    set_status(buf);
487 }
488
489 void MainWin::set_status_ready()
490 {
491    set_status(" Ready");
492 }
493
494 void MainWin::set_status(const char *buf)
495 {
496    statusBar()->showMessage(buf);
497 }
498
499 /*
500  * Function to respond to the button bar button to undock
501  */
502 void MainWin::undockWindowButton()
503 {
504    Pages* page = (Pages*)stackedWidget->currentWidget();
505    page->togglePageDocking();
506    /* The window has been undocked, lets change the context menu */
507    setContextMenuDockText();
508 }
509
510 /*
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
513  * tree widget item.
514  */
515 void MainWin::toggleDockContextWindow()
516 {
517    QTreeWidgetItem *currentitem = treeWidget->currentItem();
518    
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);
525       }
526       /* Toggle the menu item.  The window's dock status has been toggled */
527       setContextMenuDockText(page, currentitem);
528    }
529 }
530
531 /*
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.
537  */
538 void MainWin::setContextMenuDockText()
539 {
540    QTreeWidgetItem *currentitem = treeWidget->currentItem();
541    
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);
546    }
547 }
548
549 /*
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.
552  */
553 void MainWin::setContextMenuDockText(Pages* page, QTreeWidgetItem* item)
554 {
555    QString docktext("");
556    if (page->isDocked()) {
557       docktext += "UnDock ";
558    } else {
559       docktext += "ReDock ";
560    }
561    docktext += item->text(0) += " Window";
562    
563    actionToggleDock->setText(docktext);
564    setTreeWidgetItemDockColor(page, item);
565 }
566
567 /*
568  * Function to set the color of the tree widget item based on whether it is
569  * docked or not.
570  */
571 void MainWin::setTreeWidgetItemDockColor(Pages* page, QTreeWidgetItem* item)
572 {
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);
578       } else {
579       /* Set the brush back to black if docked */
580          QBrush blueBrush(Qt::blue);
581          item->setForeground(0, blueBrush);
582       }
583    }
584 }
585
586 /*
587  *  Overload of previous function, use treeindex to get item from page
588  *  This is called when an undocked window is closed.
589  */
590 void MainWin::setTreeWidgetItemDockColor(Pages* page)
591 {
592    QTreeWidgetItem* item = getFromHash(page);
593    if (item) {
594      setTreeWidgetItemDockColor(page, item);
595    }
596 }
597
598 /*
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.
602  */
603 void MainWin::stackItemChanged(int)
604 {
605    Pages* page = (Pages*)stackedWidget->currentWidget();
606    /* run the virtual function in case this class overrides it */
607    page->currentStackItem();
608 }
609
610 /*
611  * Function to simplify insertion of QTreeWidgetItem <-> Page association
612  * into a double direction hash.
613  */
614 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
615 {
616    m_pagehash.insert(item, page);
617    m_widgethash.insert(page, item);
618 }
619
620 /*
621  * Function to simplify removal of QTreeWidgetItem <-> Page association
622  * into a double direction hash.
623  */
624 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
625 {
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);
632 }
633
634 /*
635  * Function to retrieve a Page* when the item in the page selector's tree is
636  * known.
637  */
638 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
639 {
640    return m_pagehash.value(item);
641 }
642
643 /*
644  * Function to retrieve the page selectors tree widget item when the page is
645  * known.
646  */
647 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
648 {
649    return m_widgethash.value(page);
650 }
651
652 /*
653  * Function to respond to action on page selector context menu to close the
654  * current window.
655  */
656 void MainWin::closePage()
657 {
658    QTreeWidgetItem *currentitem = treeWidget->currentItem();
659    
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();
665       }
666    }
667 }
668
669 /* Quick function to return the current console */
670 Console *MainWin::currentConsole()
671 {
672    return m_currentConsole;
673 }
674 /* Quick function to return the tree item for the director */
675 QTreeWidgetItem *MainWin::currentTopItem()
676 {
677    return m_currentConsole->directorTreeItem();
678 }