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