]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/tray-monitor/tray-ui.h
Big backport from Enterprise
[bacula/bacula] / bacula / src / qt-console / tray-monitor / tray-ui.h
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19
20 #ifndef TRAYUI_H
21 #define TRAYUI_H
22
23
24 #include "common.h"
25 #include <QAction>
26 #include <QApplication>
27 #include <QButtonGroup>
28 #include <QDialogButtonBox>
29 #include <QHeaderView>
30 #include <QMainWindow>
31 #include <QPlainTextEdit>
32 #include <QStatusBar>
33 #include <QTabWidget>
34 #include <QVBoxLayout>
35 #include <QWidget>
36 #include <QLabel>
37 #include <QSpinBox>
38 #include <QMenu>
39 #include <QIcon>
40 #include <QSystemTrayIcon>
41 #include <QTimer>
42 #include <QDebug>
43 #include <QMessageBox>
44 #include <QFont>
45 #include <QInputDialog>
46
47 #include "fdstatus.h"
48 #include "sdstatus.h"
49 #include "dirstatus.h"
50 #include "conf.h"
51 #include "runjob.h"
52
53 void display_error(const char *fmt, ...);
54
55 int tls_pem_callback(char *buf, int size, const void *userdata);
56
57 class TrayUI: public QMainWindow
58 {
59    Q_OBJECT
60
61 public:
62     QWidget *centralwidget;
63     QTabWidget *tabWidget;
64     QStatusBar *statusbar;
65
66     QSystemTrayIcon *tray;
67     QSpinBox *spinRefresh;
68     QTimer *timer;
69     bool    have_systray;
70     
71     TrayUI():
72     QMainWindow(),
73        tabWidget(NULL),
74        statusbar(NULL),
75        tray(NULL),
76        spinRefresh(NULL),
77        timer(NULL),
78        have_systray(QSystemTrayIcon::isSystemTrayAvailable())
79        {
80        };
81
82     ~TrayUI() {
83     };
84     void addTab(RESMON *r)
85     {
86        QWidget *tab;
87        QString t = QString(r->hdr.name);
88        if (r->tls_enable) {
89           char buf[512];
90           /* Generate passphrase prompt */
91           bsnprintf(buf, sizeof(buf), "Passphrase for \"%s\" TLS private key: ", r->hdr.name);
92
93           /* Initialize TLS context:
94            * Args: CA certfile, CA certdir, Certfile, Keyfile,
95            * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer
96            */
97           r->tls_ctx = new_tls_context(r->tls_ca_certfile,
98                                        r->tls_ca_certdir, r->tls_certfile,
99                                        r->tls_keyfile, tls_pem_callback, &buf, NULL, true);
100
101           if (!r->tls_ctx) {
102              display_error(_("Failed to initialize TLS context for \"%s\".\n"), r->hdr.name);
103           }
104        }
105        switch(r->type) {
106        case R_CLIENT:
107           tab = new FDStatus(r);
108           break;
109        case R_STORAGE:
110           tab = new SDStatus(r);
111           break;
112        case R_DIRECTOR:
113           tab = new DIRStatus(r);
114           break;
115        default:
116           return;
117        }
118        tabWidget->setUpdatesEnabled(false);
119        tabWidget->addTab(tab, t);
120        tabWidget->setUpdatesEnabled(true);
121     }
122     void clearTabs()
123     {
124        tabWidget->setUpdatesEnabled(false);
125        for(int i = tabWidget->count() - 1; i >= 0; i--) {
126           QWidget *w = tabWidget->widget(i);
127           tabWidget->removeTab(i);
128           delete w;
129        }
130        tabWidget->setUpdatesEnabled(true);
131        tabWidget->update();
132     }
133     void startTimer()
134     {
135        if (!timer) {
136           timer = new QTimer(this);
137           connect(timer, SIGNAL(timeout()), this, SLOT(refresh_screen()));
138        }
139        timer->start(spinRefresh->value()*1000);
140     }
141     void setupUi(QMainWindow *TrayMonitor, MONITOR *mon)
142     {
143         QPushButton *menubp = NULL;
144         timer = NULL;
145         if (TrayMonitor->objectName().isEmpty())
146             TrayMonitor->setObjectName(QString::fromUtf8("TrayMonitor"));
147         TrayMonitor->setWindowIcon(QIcon(":/images/cartridge1.png")); 
148         TrayMonitor->resize(789, 595);
149         centralwidget = new QWidget(TrayMonitor);
150         centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
151         QVBoxLayout *verticalLayout = new QVBoxLayout(centralwidget);
152         verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
153         tabWidget = new QTabWidget(centralwidget);
154         tabWidget->setObjectName(QString::fromUtf8("tabWidget"));
155         tabWidget->setTabPosition(QTabWidget::North);
156         tabWidget->setTabShape(QTabWidget::Rounded);
157         tabWidget->setTabsClosable(false);
158         verticalLayout->addWidget(tabWidget);
159
160         QDialogButtonBox *buttonBox = new QDialogButtonBox(centralwidget);
161         buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
162         if (have_systray) {
163            buttonBox->setStandardButtons(QDialogButtonBox::Close);
164            connect(buttonBox, SIGNAL(rejected()), this, SLOT(cb_show()));
165         } else {
166            /* Here we can display something else, now it's just a simple menu */
167            menubp = new QPushButton(tr("&Options"));
168            buttonBox->addButton(menubp, QDialogButtonBox::ActionRole);
169         }
170         TrayMonitor->setCentralWidget(centralwidget);
171         statusbar = new QStatusBar(TrayMonitor);
172         statusbar->setObjectName(QString::fromUtf8("statusbar"));
173         TrayMonitor->setStatusBar(statusbar);
174
175         QHBoxLayout *hLayout = new QHBoxLayout();
176         QLabel *refreshlabel = new QLabel(centralwidget);
177         refreshlabel->setText("Refresh:");
178         hLayout->addWidget(refreshlabel);
179         spinRefresh = new QSpinBox(centralwidget);
180         QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
181         sizePolicy.setHorizontalStretch(0);
182         sizePolicy.setVerticalStretch(0);
183         sizePolicy.setHeightForWidth(spinRefresh->sizePolicy().hasHeightForWidth());
184         spinRefresh->setSizePolicy(sizePolicy);
185         spinRefresh->setMinimum(1);
186         spinRefresh->setMaximum(600);
187         spinRefresh->setSingleStep(10);
188         spinRefresh->setValue(mon?mon->RefreshInterval:60);
189         hLayout->addWidget(spinRefresh);
190         hLayout->addWidget(buttonBox);
191
192         verticalLayout->addLayout(hLayout);
193         //QSystemTrayIcon::isSystemTrayAvailable
194         tray = new QSystemTrayIcon(TrayMonitor);
195         QMenu* stmenu = new QMenu(TrayMonitor);
196
197         QAction *actShow = new QAction(QApplication::translate("TrayMonitor",
198                                "Display",
199                                 0, QApplication::UnicodeUTF8),TrayMonitor);
200         QAction* actQuit = new QAction(QApplication::translate("TrayMonitor",
201                                "Quit",
202                                 0, QApplication::UnicodeUTF8),TrayMonitor);
203         QAction* actAbout = new QAction(QApplication::translate("TrayMonitor",
204                                "About",
205                                 0, QApplication::UnicodeUTF8),TrayMonitor);
206         QAction* actRun = new QAction(QApplication::translate("TrayMonitor",
207                                "Run...",
208                                 0, QApplication::UnicodeUTF8),TrayMonitor);
209 /* Not yet ready
210  *      QAction* actRes = new QAction(QApplication::translate("TrayMonitor",
211  *                             "Restore...",
212  *                              0, QApplication::UnicodeUTF8),TrayMonitor);
213  */
214         QAction* actConf = new QAction(QApplication::translate("TrayMonitor",
215                                "Configure...",
216                                 0, QApplication::UnicodeUTF8),TrayMonitor);
217         stmenu->addAction(actShow);
218         stmenu->addAction(actRun);
219         //stmenu->addAction(actRes);
220         stmenu->addSeparator();
221         stmenu->addAction(actConf);
222         stmenu->addSeparator();
223         stmenu->addAction(actAbout);
224         stmenu->addSeparator();
225         stmenu->addAction(actQuit);
226         
227         connect(actRun, SIGNAL(triggered()), this, SLOT(cb_run()));
228         connect(actShow, SIGNAL(triggered()), this, SLOT(cb_show()));
229         connect(actConf, SIGNAL(triggered()), this, SLOT(cb_conf()));
230         //connect(actRes, SIGNAL(triggered()), this, SLOT(cb_restore()));
231         connect(actQuit, SIGNAL(triggered()), this, SLOT(cb_quit()));
232         connect(actAbout, SIGNAL(triggered()), this, SLOT(cb_about()));
233         connect(spinRefresh, SIGNAL(valueChanged(int)), this, SLOT(cb_refresh(int)));
234         connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
235                 this, SLOT(cb_trayIconActivated(QSystemTrayIcon::ActivationReason)));
236         tray->setContextMenu(stmenu);
237
238         QIcon icon(":/images/cartridge1.png");
239         tray->setIcon(icon);
240         tray->setToolTip(QString("Bacula Tray Monitor"));
241         tray->show();
242         retranslateUi(TrayMonitor);
243         QMetaObject::connectSlotsByName(TrayMonitor);
244         startTimer();
245
246         /* When we don't have the systemtray, we keep the menu, but disabled */
247         if (!have_systray) {
248            actShow->setEnabled(false);
249            menubp->setMenu(stmenu);
250            TrayMonitor->show();
251         }
252     } // setupUi
253
254     void retranslateUi(QMainWindow *TrayMonitor)
255     {
256        TrayMonitor->setWindowTitle(QApplication::translate("TrayMonitor", "Bacula Tray Monitor", 0, QApplication::UnicodeUTF8));
257     } // retranslateUi
258
259 private slots:
260     void cb_quit() {
261        QApplication::quit();
262     }
263
264     void cb_refresh(int val) {
265        if (timer) {
266           timer->setInterval(val*1000);
267        }
268     }
269
270     void cb_about() {
271        QMessageBox::about(this, "Bacula Tray Monitor", "Bacula Tray Monitor\n"
272                           "For more information, see: www.bacula.org\n"
273                           "Copyright (C) 1999-2017, Kern Sibbald.\n"
274                           "All rights reserved.");
275     }
276     RESMON *get_director() {
277        QStringList dirs;
278        RESMON *d, *director=NULL;
279        bool ok;
280        foreach_res(d, R_DIRECTOR) {
281           if (!director) {
282              director = d;
283           }
284           dirs << QString(d->hdr.name);
285        }
286        foreach_res(d, R_CLIENT) {
287           if (d->use_remote) {
288              if (!director) {
289                 director = d;
290              }
291              dirs << QString(d->hdr.name);
292           }
293        }
294        if (dirs.count() > 1) {
295           /* TODO: Set Modal attribute */
296           QString dir = QInputDialog::getItem(this, _("Select a Director"), "Director:", dirs, 0, false, &ok, 0);
297           if (!ok) {
298              return NULL;
299           }
300           if (ok && !dir.isEmpty()) {
301              char *p = dir.toUtf8().data();
302              foreach_res(d, R_DIRECTOR) {
303                 if (strcmp(p, d->hdr.name) == 0) {
304                    director = d;
305                    break;
306                 }
307              }
308              foreach_res(d, R_CLIENT) {
309                 if (strcmp(p, d->hdr.name) == 0) {
310                    director = d;
311                    break;
312                 }
313              }
314           }
315        }
316        if (dirs.count() == 0 || director == NULL) {
317           /* We need the proxy feature */
318           display_error("No Director defined");
319           return NULL;
320        }
321        return director;
322     }
323     void cb_run() {
324        RESMON *dir = get_director();
325        if (!dir) {
326           return;
327        }
328        task *t = new task();
329        connect(t, SIGNAL(done(task *)), this, SLOT(run_job(task *)), Qt::QueuedConnection);
330        t->init(dir, TASK_RESOURCES);
331        dir->wrk->queue(t);
332     }
333     void refresh_item() {
334        /* Probably do only the first one */
335        int oldnbjobs = 0;
336
337        for (int i=tabWidget->count() - 1; i >= 0; i--) {
338           ResStatus *s = (ResStatus *) tabWidget->widget(i);
339           if (s->res->use_monitor) {
340              s->res->mutex->lock();
341              if (s->res->running_jobs) {
342                 oldnbjobs += s->res->running_jobs->size();
343              }
344              s->res->mutex->unlock();
345           }
346           if (isVisible() || s->res->use_monitor) {
347              s->doUpdate();
348           }
349        }
350        /* We need to find an other way to compute running jobs */
351        if (oldnbjobs) {
352           QString q;
353           tray->setIcon(QIcon(":/images/R.png"));
354           tray->setToolTip(q.sprintf("Bacula Tray Monitor - %d job%s running", oldnbjobs, oldnbjobs>1?"s":""));
355           //tray->showMessage();   Can use this function to display a popup
356
357        } else {
358           tray->setIcon(QIcon(":/images/cartridge1.png"));
359           tray->setToolTip("Bacula Tray Monitor");
360        }
361     }
362     void cb_conf() {
363        new Conf();
364     }
365     void cb_restore() {
366        RESMON *dir = get_director();
367        if (!dir) {
368           return;
369        }
370     }
371     void cb_trayIconActivated(QSystemTrayIcon::ActivationReason r) {
372        if (r == QSystemTrayIcon::Trigger) {
373           cb_show();
374        }
375     }
376
377     void refresh_screen() {
378        refresh_item();
379     }
380
381     void cb_show() {
382        if (isVisible()) {
383           hide();
384        } else {
385           refresh_item();
386           show();
387        }
388     }
389 public slots:
390     void task_done(task *t) {
391        Dmsg0(0, "Task done!\n");
392        t->deleteLater();
393     };
394     void run_job(task *t) {
395        Dmsg0(0, "Task done!\n");
396        RESMON *dir = t->res;
397        t->deleteLater();
398        new RunJob(dir);
399     };
400 };
401
402
403 #endif  /* TRAYUI_H */