2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
26 #include <QApplication>
27 #include <QButtonGroup>
28 #include <QDialogButtonBox>
29 #include <QHeaderView>
30 #include <QMainWindow>
31 #include <QPlainTextEdit>
34 #include <QVBoxLayout>
40 #include <QSystemTrayIcon>
43 #include <QMessageBox>
45 #include <QInputDialog>
49 #include "dirstatus.h"
53 void display_error(const char *fmt, ...);
55 int tls_pem_callback(char *buf, int size, const void *userdata);
57 class TrayUI: public QMainWindow
62 QWidget *centralwidget;
63 QTabWidget *tabWidget;
64 QStatusBar *statusbar;
66 QSystemTrayIcon *tray;
67 QSpinBox *spinRefresh;
78 have_systray(QSystemTrayIcon::isSystemTrayAvailable())
84 void addTab(RESMON *r)
87 QString t = QString(r->hdr.name);
90 /* Generate passphrase prompt */
91 bsnprintf(buf, sizeof(buf), "Passphrase for \"%s\" TLS private key: ", r->hdr.name);
93 /* Initialize TLS context:
94 * Args: CA certfile, CA certdir, Certfile, Keyfile,
95 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer
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);
102 display_error(_("Failed to initialize TLS context for \"%s\".\n"), r->hdr.name);
107 tab = new FDStatus(r);
110 tab = new SDStatus(r);
113 tab = new DIRStatus(r);
118 tabWidget->setUpdatesEnabled(false);
119 tabWidget->addTab(tab, t);
120 tabWidget->setUpdatesEnabled(true);
124 tabWidget->setUpdatesEnabled(false);
125 for(int i = tabWidget->count() - 1; i >= 0; i--) {
126 QWidget *w = tabWidget->widget(i);
127 tabWidget->removeTab(i);
130 tabWidget->setUpdatesEnabled(true);
136 timer = new QTimer(this);
137 connect(timer, SIGNAL(timeout()), this, SLOT(refresh_screen()));
139 timer->start(spinRefresh->value()*1000);
141 void setupUi(QMainWindow *TrayMonitor, MONITOR *mon)
143 QPushButton *menubp = 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);
160 QDialogButtonBox *buttonBox = new QDialogButtonBox(centralwidget);
161 buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
163 buttonBox->setStandardButtons(QDialogButtonBox::Close);
164 connect(buttonBox, SIGNAL(rejected()), this, SLOT(cb_show()));
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);
170 TrayMonitor->setCentralWidget(centralwidget);
171 statusbar = new QStatusBar(TrayMonitor);
172 statusbar->setObjectName(QString::fromUtf8("statusbar"));
173 TrayMonitor->setStatusBar(statusbar);
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);
192 verticalLayout->addLayout(hLayout);
193 //QSystemTrayIcon::isSystemTrayAvailable
194 tray = new QSystemTrayIcon(TrayMonitor);
195 QMenu* stmenu = new QMenu(TrayMonitor);
197 QAction *actShow = new QAction(QApplication::translate("TrayMonitor",
199 0, QApplication::UnicodeUTF8),TrayMonitor);
200 QAction* actQuit = new QAction(QApplication::translate("TrayMonitor",
202 0, QApplication::UnicodeUTF8),TrayMonitor);
203 QAction* actAbout = new QAction(QApplication::translate("TrayMonitor",
205 0, QApplication::UnicodeUTF8),TrayMonitor);
206 QAction* actRun = new QAction(QApplication::translate("TrayMonitor",
208 0, QApplication::UnicodeUTF8),TrayMonitor);
210 * QAction* actRes = new QAction(QApplication::translate("TrayMonitor",
212 * 0, QApplication::UnicodeUTF8),TrayMonitor);
214 QAction* actConf = new QAction(QApplication::translate("TrayMonitor",
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);
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);
238 QIcon icon(":/images/cartridge1.png");
240 tray->setToolTip(QString("Bacula Tray Monitor"));
242 retranslateUi(TrayMonitor);
243 QMetaObject::connectSlotsByName(TrayMonitor);
246 /* When we don't have the systemtray, we keep the menu, but disabled */
248 actShow->setEnabled(false);
249 menubp->setMenu(stmenu);
254 void retranslateUi(QMainWindow *TrayMonitor)
256 TrayMonitor->setWindowTitle(QApplication::translate("TrayMonitor", "Bacula Tray Monitor", 0, QApplication::UnicodeUTF8));
261 QApplication::quit();
264 void cb_refresh(int val) {
266 timer->setInterval(val*1000);
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.");
276 RESMON *get_director() {
278 RESMON *d, *director=NULL;
280 foreach_res(d, R_DIRECTOR) {
284 dirs << QString(d->hdr.name);
286 foreach_res(d, R_CLIENT) {
291 dirs << QString(d->hdr.name);
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);
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) {
308 foreach_res(d, R_CLIENT) {
309 if (strcmp(p, d->hdr.name) == 0) {
316 if (dirs.count() == 0 || director == NULL) {
317 /* We need the proxy feature */
318 display_error("No Director defined");
324 RESMON *dir = get_director();
328 task *t = new task();
329 connect(t, SIGNAL(done(task *)), this, SLOT(run_job(task *)), Qt::QueuedConnection);
330 t->init(dir, TASK_RESOURCES);
333 void refresh_item() {
334 /* Probably do only the first one */
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();
344 s->res->mutex->unlock();
346 if (isVisible() || s->res->use_monitor) {
350 /* We need to find an other way to compute running jobs */
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
358 tray->setIcon(QIcon(":/images/cartridge1.png"));
359 tray->setToolTip("Bacula Tray Monitor");
366 RESMON *dir = get_director();
371 void cb_trayIconActivated(QSystemTrayIcon::ActivationReason r) {
372 if (r == QSystemTrayIcon::Trigger) {
377 void refresh_screen() {
390 void task_done(task *t) {
391 Dmsg0(0, "Task done!\n");
394 void run_job(task *t) {
395 Dmsg0(0, "Task done!\n");
396 RESMON *dir = t->res;
403 #endif /* TRAYUI_H */