alarm.cpp 16.7 KB
Newer Older
Giacomo Strangolino's avatar
Giacomo Strangolino committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/***************************************************************************
 *   Copyright (C) 2007 by Claudio Scafuri, Giacomo Strangolino   *
 *   claudio@hyo   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/


#include "alarm.h"
#include "filter.h"
Giacomo Strangolino's avatar
Giacomo Strangolino committed
24
#include "acmd.h"
Giacomo Strangolino's avatar
Giacomo Strangolino committed
25
26
27
28
29
30
#include "AlarmTreeWidget.h"
#include "AlarmTreeWidgetItem.h"
#include <QMessageBox>
#include <QCloseEvent>
#include "AlarmHistoryTree.h"
#include <QDebug>
31
#include <QDesktopServices> // open url
Giacomo Strangolino's avatar
Giacomo Strangolino committed
32

33
34
35
36
37
38
39
// cumbia
#include <qulogimpl.h>
#include <cucontrolsfactorypool.h>
#include <cumbiapool.h>
#include <quapps.h>
#include <quwriter.h>
#include <quwatcher.h>
40
41
#include <qustring.h>
#include <qustringlist.h>
42
#include <QTimer>
43
44
45
// cumbia

Alarm::Alarm(CumbiaPool *cu_p, QWidget *parent) : QWidget(parent)
Giacomo Strangolino's avatar
Giacomo Strangolino committed
46
{
47
48
49
50
51
52
53
54
55
    // cumbia
    CuModuleLoader mloader(cu_p, &m_ctrl_factory_pool, &m_log_impl);
    cu_pool = cu_p;
    ui = new Ui::Alarm;
    ui->setupUi(this, cu_p, m_ctrl_factory_pool);

    // mloader.modules() to get the list of loaded modules
    // cumbia

Giacomo Strangolino's avatar
Giacomo Strangolino committed
56
57
58
    QString soundFileName, alarmSysTestServerName;
    QStringList args = qApp->arguments();

59
    connect(ui->pBAckAll, SIGNAL(clicked()), this, SLOT(ackAll()));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
60
    connect(ui->pBStopSound, SIGNAL(clicked()), this, SLOT(stopSound()));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
61

62
63
64
65
    // view types
    ui->treeWidgetAlarms->setType(AlarmTreeWidget::AlarmType);
    ui->twDisabledAlarms->setType(AlarmTreeWidget::DisabledAlarmType);

Giacomo Strangolino's avatar
Giacomo Strangolino committed
66
    /* silence alarm */
67
68
    connect(ui->treeWidgetAlarms, SIGNAL(silence()), this, SLOT(silence()));
    connect(ui->treeWidgetAlarms, SIGNAL(silence()), this, SLOT(stopSound()));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
69
    /* ack. Also uses QTWriter to impart StopNew command */
70
    connect(ui->treeWidgetAlarms, SIGNAL(ack()), this, SLOT(ack()));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
71

72
73
74
75
    connect(ui->pBApplyFilter, SIGNAL(clicked()), this, SLOT(applyFilter()));
    connect(ui->pBClearFilter, SIGNAL(clicked()), this, SLOT(clearFilter()));
    connect(ui->pBStopSound, SIGNAL(clicked()), this, SLOT(stopSound()));
    connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
76
77
78


    /* message label */
79
80
81
82
83
84
    ui->msgLabel->setVisible(false);
    ui->pBClearFilter->setDisabled(true);
    ui->tWGroup->sortItems(0, Qt::AscendingOrder);
    ui->tWGroup->header()->setHidden(true);
    ui->pBConfHistory->setHidden(true);

85
86
87
88
    // device list from Tango DB free prop
    QString devlist_prop;
    args.contains("--device-list-prop") && args.size() > args.indexOf("--device-list-prop") + 1
            ? devlist_prop = args.at(args.indexOf("--device-list-prop") + 1) : devlist_prop = "DeviceList";
89
    QuWatcher *db_dlist_w = new QuWatcher(this, cu_pool, m_ctrl_factory_pool); // device prop watcher
90
    db_dlist_w->setObjectName("free_prop_w");
91
92
93
    db_dlist_w->setSingleShot(true);
    db_dlist_w->setAutoDestroy(true);
    connect(db_dlist_w, SIGNAL(newData(CuData)), this, SLOT(onDevList(CuData)));
94
    db_dlist_w->setSource(QString("tango://#AlarmHandler#%1").arg(devlist_prop));
95

96
97
98
99
100
101
102
103
    // groups
    QuWatcher *grpW = new QuWatcher(this, cu_pool, m_ctrl_factory_pool);
    grpW->setObjectName("group_w");
    grpW->setSingleShot(true);
    grpW->setAutoDestroy(true);
    connect(grpW, SIGNAL(newData(CuData)), this, SLOT(onGroupList(CuData)));
    grpW->setSource(QString("tango://AlarmHandler(GroupNames)").arg(devlist_prop));

Giacomo Strangolino's avatar
Giacomo Strangolino committed
104
    //---------------------------------------------------------------------------------------
Giacomo Strangolino's avatar
Giacomo Strangolino committed
105
    if(args.contains("--alarm-test-devname") && args.size() > args.indexOf("--alarm-test-devname") + 1) {
Giacomo Strangolino's avatar
Giacomo Strangolino committed
106
107
        alarmSysTestServerName = args.at(args.indexOf("--alarm-test-devname") + 1);
        // printf("\e[1;32m --alarm-test-devname specified: \"%s\"\e[0m\n", qstoc(alarmSysTestServerName));
108
109
        ui->tPBTestAlarm->setTarget(alarmSysTestServerName + "/alarm_test(true)");
        ui->tPBTestAlarmStop->setTarget(alarmSysTestServerName + "/alarm_test(false)");
Giacomo Strangolino's avatar
Giacomo Strangolino committed
110
    }
Giacomo Strangolino's avatar
Giacomo Strangolino committed
111
    else if(args.contains("--alarm-test-default-dev")) {
Giacomo Strangolino's avatar
Giacomo Strangolino committed
112
        printf("no --alarm-test-devname specified: using ecrfpsa/alarmtest/0/alarm_test\n");
113
114
        ui->tPBTestAlarm->setTarget("ecrfpsa/alarmtest/0/alarm_test(true)");
        ui->tPBTestAlarmStop->setTarget("ecrfpsa/alarmtest/0/alarm_test(false)");
Giacomo Strangolino's avatar
Giacomo Strangolino committed
115
116
117
    }
    //---------------------------------------------------------------------------------------

Giacomo Strangolino's avatar
Giacomo Strangolino committed
118
    if(args.contains("--sound-file-name") && args.size() > args.indexOf("--sound-file-name")) {
Giacomo Strangolino's avatar
Giacomo Strangolino committed
119
        soundFileName = args.at(args.indexOf("--sound-file-name") + 1);
120
        qDebug() <<"Sound file name: "<< soundFileName;
Giacomo Strangolino's avatar
Giacomo Strangolino committed
121
122
    }
    else
123
        printf("--> Alarm::Alarm: use \e[1;32m--sound-file-name path/to/sound_file_name.wav\e[0m to enable sounds\n");
Giacomo Strangolino's avatar
Giacomo Strangolino committed
124
    sound = new Sound(soundFileName);
125
126
127
128
    connect( ui->pBTestSoundOn,SIGNAL(clicked()), sound, SLOT(play()));
    connect( ui->pBTestSoundOff,SIGNAL(clicked()), sound, SLOT(stop()));
    ui->groupBoxFilter->setHidden(true);
    connect(ui->pBFilter, SIGNAL(toggled(bool)), ui->groupBoxFilter, SLOT(setVisible(bool)));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
129
130

    /* connections for filter group box */
131
132
133
134
135
    connect(ui->cBAck, SIGNAL(toggled(bool)), ui->rBAck, SLOT(setEnabled(bool)));
    connect(ui->cBAck, SIGNAL(toggled(bool)), ui->rBNack, SLOT(setEnabled(bool)));
    connect(ui->cBLevel, SIGNAL(toggled(bool)), ui->comboLog, SLOT(setEnabled(bool)));
    connect(ui->cBStatus, SIGNAL(toggled(bool)), ui->comboStatus, SLOT(setEnabled(bool)));
    connect(ui->cBGroup, SIGNAL(toggled(bool)), ui->tWGroup, SLOT(setEnabled(bool)));
136
137
    ui->pbInfo->setEnabled(false);
    ui->liViewInfo->setVisible(false);
138
    connect(ui->liViewInfo, SIGNAL(urlClicked(QString)), this, SLOT(openUrl(QString)));
139
    connect(ui->pbInfo, SIGNAL(toggled(bool)), this, SLOT(onInfoListViewVisibilityChange(bool)));
140
141
142
143
144
145
146

    foreach(QTreeWidget *tw, QList<QTreeWidget *>() << ui->treeWidgetAlarms << ui->twDisabledAlarms) {
        connect(tw, SIGNAL(message(QString)), ui->msgLabel, SLOT(setText(QString)));
        connect(tw, SIGNAL(mouseOverItem(bool)), ui->msgLabel, SLOT(setVisible(bool)));
        connect(tw, SIGNAL(itemSelectionChanged()), this, SLOT(onItemSelectionChange()));
        connect(tw, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onItemDoubleClicked(QModelIndex)));
    }
Giacomo Strangolino's avatar
Giacomo Strangolino committed
147
    /* connections for test section */
148
149
    //connect(ui->pBTestSoundOn, SIGNAL(clicked()), this, SLOT(testSound()));
    //connect(ui->pBTestSoundOff, SIGNAL(clicked()), this, SLOT(stopSound()));
150
151
    /* sound: beep on new alarm */
    connect(ui->treeWidgetAlarms, SIGNAL(newAlarmDetected()), this, SLOT(beep()));
152
153
154
155
156
157
158
159

    // database
    ui->dateStart->setDate(QDate::currentDate());
    ui->dateStop->setDate(QDate::currentDate());
    ui->timeStart->setTime(QTime::currentTime());
    ui->timeStop->setTime(QTime::currentTime());
    connect(ui->pBApplyHistory, SIGNAL(clicked()), this, SLOT(queryDB()));
    connect(ui->comboPeriod, SIGNAL(currentIndexChanged(int)), this, SLOT(enableFrameHistoryInterval(int)));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
160
161
}

162
163
Alarm::~Alarm() {
    if(sound) {
Giacomo Strangolino's avatar
Giacomo Strangolino committed
164
165
166
        sound->stop();
        delete sound;
    }
167
}
Giacomo Strangolino's avatar
Giacomo Strangolino committed
168

169
void Alarm::refresh(const CuData &da) {
170
171
172
    const QString& att = QuString(da, "src").section('/', -1, -1);
    AlarmTreeWidget *tw = att == "alarm" ? ui->treeWidgetAlarms : ui->twDisabledAlarms;
    tw->refresh(da);
173
174
    if(filtering && ui->cBDynamic->isChecked())
        applyFilter();
175
176
177
    QString tn = "%1 [%2]";
    if(att == "alarm") ui->tabWidget->setTabText(0, tn.arg("Alarm").arg(tw->countAlarmed()));
    else ui->tabWidget->setTabText(1, tn.arg("Disabled Alarms").arg(tw->countAll()));
178
}
Giacomo Strangolino's avatar
Giacomo Strangolino committed
179

180
181
182
void Alarm::onDevList(const CuData &da) {
    if(da["err"].toBool()) {
        perr("Alarm.onDevList: error fetching device list from database: src: \"%s\" msg: \"%s\"", vtoc2(da, "src"), vtoc2(da, "msg"));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
183
    }
184
185
186
    else {
        QuStringList devs(da, "value");
        m_connect_devs(devs);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
187
188
189
    }
}

190
191
192
193
194
195
196
197
void Alarm::onGroupList(const CuData &da) {
    if(!da["err"].toBool() && da.containsKey("value")) {
        foreach(QString g, QuStringList(da, "value"))
            new QTreeWidgetItem(ui->tWGroup, QStringList() << g.remove("gr_"));
    } else
        perr("Alarm.onGroupList: error fetching groups from %s: %s", vtoc2(da, "src"), vtoc2(da, "msg"));
}

198
void Alarm::m_connect_devs(const QStringList &devs) {
199
200
201
202
203
204
205
    foreach(const QString& att, QStringList() << "alarm" << "alarmDisabled") {
        foreach(const QString dev, devs) {
            QuWatcher *alrw = new QuWatcher(this, cu_pool, m_ctrl_factory_pool);
            alrw->setObjectName(dev + "/alarm" + "+watcher");
            connect(alrw, SIGNAL(newData(CuData)), this, SLOT(refresh(CuData)));
            alrw->setSource(dev + "/" + att);
        }
Giacomo Strangolino's avatar
Giacomo Strangolino committed
206
207
208
209
210
211
212
    }
}

QList<QTreeWidgetItem *> Alarm::mGetSelectedItems()
{
    QList<QTreeWidgetItem *> selItems;
    /* get the tree widget that is currently visible */
213
214
    if(ui->treeWidgetAlarms->isVisible())
        selItems = ui->treeWidgetAlarms->selectedItems();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
215
216
217
218
219
    return selItems;
}

void Alarm::silence()
{
Giacomo Strangolino's avatar
Giacomo Strangolino committed
220
221
    Acmd acmd;
    acmd.silence(ui->treeWidgetAlarms, false, cu_pool, m_ctrl_factory_pool);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
222
223
}

224
void Alarm::testSound() {
Giacomo Strangolino's avatar
Giacomo Strangolino committed
225
226
227
    sound->play();
}

228
229
230
void Alarm::beep() {
    showNormal();
    sound->play();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
231
232
}

233
234
235
236
void Alarm::openUrl(const QString &u) const {
    QDesktopServices::openUrl(QUrl(u));
}

237
void Alarm::stopSound() {
238
239
    Acmd acmd;
    acmd.stop_new(ui->treeWidgetAlarms, true, cu_pool, m_ctrl_factory_pool);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
240
241
242
    sound->stop();
}

243
void Alarm::ack() {
Giacomo Strangolino's avatar
Giacomo Strangolino committed
244
    Acmd acmd;
Giacomo Strangolino's avatar
Giacomo Strangolino committed
245
    acmd.ack(ui->treeWidgetAlarms, false, cu_pool, m_ctrl_factory_pool);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
246
247
}

Giacomo Strangolino's avatar
Giacomo Strangolino committed
248
void Alarm::ackAll() {
Giacomo Strangolino's avatar
Giacomo Strangolino committed
249
    Acmd acmd;
Giacomo Strangolino's avatar
Giacomo Strangolino committed
250
    acmd.ack(ui->treeWidgetAlarms, true, cu_pool, m_ctrl_factory_pool);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
251
252
253
254
255
256
}

void Alarm::applyFilter()
{
    AlarmFilter filter;

257
    filter.ack_enable = ui->cBAck->isChecked();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
258
259

    if(filter.ack_enable)
260
        filter.ack = ui->rBAck->isChecked();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
261

262
    filter.lev = ui->cBLevel->isChecked();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
263
    if(filter.lev)
264
        filter.level = ui->comboLog->currentText();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
265

266
    filter.stat = ui->cBStatus->isChecked();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
267
    if(filter.stat)
268
        filter.status = ui->comboStatus->currentText();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
269

270
    filter.grp = ui->cBGroup->isChecked();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
271
272
    if(filter.grp)
    {
273
        QList<QTreeWidgetItem* >groups = ui->tWGroup->selectedItems();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
274
275
276
        for(int i = 0; i < groups.size(); i++)
            filter.groups << groups[i]->text(0);
    }
277
    ui->treeWidgetAlarms->applyFilter(filter);
278
    ui->twDisabledAlarms->applyFilter(filter);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
279
    filtering = true;
280
    ui->pBClearFilter->setDisabled(false);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
281
282
}

283
void Alarm::clearFilter() {
284
    ui->treeWidgetAlarms->removeFilter();
285
    ui->twDisabledAlarms->removeFilter();
286
287
    ui->pBClearFilter->setDisabled(true);
    ui->cBDynamic->setChecked(false);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
288
289
290
    filtering = false;
}

291
292
293
void Alarm::onInfoListViewVisibilityChange(bool vis) {
    if(!vis)
        ui->liViewInfo->activate("", "");
294
295
296
297
298
    else {
        AlarmTreeWidget *atw = ui->tabWidget->currentIndex() == 0 ? ui->treeWidgetAlarms : ui->twDisabledAlarms;
        atw->selectedItems().size() == 1 ?
                    ui->liViewInfo->activate(atw->selectedItems().first()->data(AlarmTreeWidgetItem::Device, Qt::UserRole).toString(),
                                             atw->selectedItems().first()->text(AlarmTreeWidgetItem::Alarm))
299
                  : ui->liViewInfo->activate("", "");
300
    }
Giacomo Strangolino's avatar
Giacomo Strangolino committed
301
302
}

303
void Alarm::onItemSelectionChange() {
304
    QList<QTreeWidgetItem *> sits = qobject_cast<AlarmTreeWidget *>(sender())->selectedItems();
305
306
307
308
309
310
    QTreeWidgetItem *it = nullptr;
    if(sits.size() == 1)
        it = sits.first();
    ui->pbInfo->setEnabled(it != nullptr);
    if(ui->liViewInfo->isVisible() && it)
        ui->liViewInfo->activate(it->data(AlarmTreeWidgetItem::Device, Qt::UserRole).toString(), it->text(AlarmTreeWidgetItem::Alarm));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
311
312
}

313
void Alarm::onItemDoubleClicked(const QModelIndex &mi) {
314
315
    //    if(mi.column() == AlarmTreeWidgetItem::Alarm)
    ui->pbInfo->setChecked(true);
316
317
}

318
void Alarm::tabChanged(int t) {
319
320
    if(t == 2)
        queryDB();
321
    if(t > 1) {
322
323
324
325
326
327
328
        ui->pBAckAll->setHidden(true);
        ui->pBConfHistory->setHidden(false);
        ui->pBConfHistory->setChecked(true);
        ui->groupBoxFilter->setDisabled(true);
        ui->pBFilter->setHidden(true);
        ui->pBConfHistory->setHidden(true);
        ui->pBStopSound->setHidden(true);
Giacomo Strangolino's avatar
Giacomo Strangolino committed
329
    }
330
    else if(t < 2) {
331
332
333
334
335
        ui->pBStopSound->setHidden(false);
        ui->pBAckAll->setHidden(false);
        ui->pBConfHistory->setHidden(true);
        ui->groupBoxFilter->setDisabled(false);
        ui->pBFilter->setHidden(false);
336
        onInfoListViewVisibilityChange(ui->liViewInfo->isVisible());
Giacomo Strangolino's avatar
Giacomo Strangolino committed
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
    }
}

void Alarm::closeEvent(QCloseEvent *e)
{
    int reply = QMessageBox::question(this, "Warning", "Are you really sure you want to close this application?\n"
                                                       "If you do, you will not receive alarm notifications",
                                      QMessageBox::Yes|QMessageBox::No);

    if(reply == QMessageBox::Yes)
        reply = QMessageBox::question(this, "Warning", "By closing this panel, I am aware that I will not receive"
                                                       "\nalarms from now on",
                                      QMessageBox::Yes|QMessageBox::Cancel);
    if(reply == QMessageBox::Yes)
        e->accept();

    else
        e->ignore();

}
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

void Alarm::queryDB()
{
    QDateTime startSearch;
    QDateTime now = QDateTime::currentDateTime();
    QString query;
    QDateTime dts, dte;
    switch(ui->comboPeriod->currentIndex())  {
    case 0:
        startSearch = now.addDays(-1);
        break;
    case 1:
        startSearch = now.addDays(-7);
        break;
    case 2:
        startSearch = now.addMonths(-1);
        break;
    case 3:
        dts.setDate(ui->dateStart->date());
        dts.setTime(ui->timeStart->time());
        dte.setDate(ui->dateStop->date());
        dte.setTime(ui->timeStop->time());
        break;
    }

    if(startSearch.isValid()) {
        query = QString("SELECT asd.data_time,ac.att_name, "
        "COALESCE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(asd.value_r,'0','NORMAL'),'1','ALARM UNACK'),'2','ALARM ACKED'),'3','RETURNED NORMAL'),'4','SHELVED'),'6','DISABLED'),aed.error_desc) as value_r "
        "FROM att_scalar_devenum_ro asd "
        "JOIN att_conf ac ON asd.att_conf_id=ac.att_conf_id "
        "LEFT OUTER JOIN att_error_desc aed ON aed.att_error_desc_id=asd.att_error_desc_id "
        "WHERE ac.att_name in (SELECT att_name FROM att_conf WHERE att_name LIKE '%alarm/test/0/%' OR att_name LIKE '%alarm/fermi/test/%') "
        "AND asd.data_time > '%1' ORDER BY asd.data_time DESC;").arg(startSearch.toString("yyyy-MM-dd hh:mm:ss.zzz"));
    }
    else if(dts.isValid()  && dte.isValid() && dts < dte) {
        query = QString("SELECT asd.data_time,ac.att_name, "
        "COALESCE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(asd.value_r,'0','NORMAL'),'1','ALARM UNACK'),'2','ALARM ACKED'),'3','RETURNED NORMAL'),'4','SHELVED'),'6','DISABLED'),aed.error_desc) as value_r "
        "FROM att_scalar_devenum_ro asd "
        "JOIN att_conf ac ON asd.att_conf_id=ac.att_conf_id "
        "LEFT OUTER JOIN att_error_desc aed ON aed.att_error_desc_id=asd.att_error_desc_id "
        "WHERE ac.att_name in (SELECT att_name FROM att_conf WHERE att_name LIKE '%alarm/test/0/%' OR att_name LIKE '%alarm/fermi/test/%') "
        "AND asd.data_time > '%1' AND asd.data_time < '%2' ORDER BY asd.data_time DESC;").arg(dts.toString("yyyy-MM-dd hh:mm:ss.zzz")).arg(dte.toString("yyyy-MM-dd hh:mm:ss.zzz"));
    }
    else if(dts.isValid()  && dte.isValid() && dts >= dte)
        QMessageBox::information(this, "Invalid date / time range",  "Stop date/time is ahead of start date/time");

    if(query.length() > 0)
        ui->twHistory->executeQuery(query);

    printf("executing query \"%s\"\n", qstoc(query));

    if(ui->cBDynamic->isChecked()) {
        applyFilter();
    }
}

void Alarm::enableFrameHistoryInterval(int i) {
    ui->widgetHistoryConf->setEnabled(i == 3);
}