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