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