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