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