AlarmTreeWidget.cpp 12.4 KB
Newer Older
Giacomo Strangolino's avatar
Giacomo Strangolino committed
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "AlarmTreeWidget.h"
#include "filter.h"
#include <QStringList>
#include<QHeaderView>
#include <QApplication>
#include <QDateTime>
#include <elettracolors.h>
#include "AlarmTreeWidgetItem.h"
#include <QMouseEvent>
#include <QMenu>
#include <QAction>
#include <QDesktopServices>
#include <QUrl>
14
#include <QScrollBar>
Giacomo Strangolino's avatar
Giacomo Strangolino committed
15
16
#include <QtDebug>

17
18
19
20
21
#include <cudata.h>
#include <cumacros.h>
#include <qustring.h>
#include <qustringlist.h>

Giacomo Strangolino's avatar
Giacomo Strangolino committed
22
23
24
25
26
27
28
29
using namespace std;

AlarmTreeWidget::AlarmTreeWidget(QWidget *parent) : QTreeWidget(parent)
{
    setColumnCount(9);
    setRootIsDecorated(false);
    setAutoScroll(true);
    setSelectionMode(QAbstractItemView::ExtendedSelection);
30
    setHeaderLabels(QStringList() << "Date/time" << "microsecs" << "Alarm" << "Status" << "Ack" << "Count" << "Level" << "Silenced min." << "Device" << "Message");
Giacomo Strangolino's avatar
Giacomo Strangolino committed
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
    //    setSortingEnabled(true);
#if QT_VERSION > 0x050000
    header()->setSectionResizeMode(  QHeaderView::ResizeToContents);
#else
    header()->setResizeMode(  QHeaderView::ResizeToContents);
#endif
    _filter_enabled = false;

    setMouseTracking(true);
    connect(this, SIGNAL(itemEntered(QTreeWidgetItem*,int)), this, SLOT(slotItemEntered(QTreeWidgetItem*,int)));
}

void AlarmTreeWidget::showEvent(QShowEvent *e)
{
    //  header()->setResizeMode(  QHeaderView::Interactive);
    QWidget::showEvent(e);
}

void AlarmTreeWidget::applyFilter(AlarmFilter f)
{
    QList<QTreeWidgetItem *> items;
    int i;

    if(_filter_enabled)
        removeFilter();

    items = findItems("*", Qt::MatchWildcard);

    if(f.ack_enable)
    {
        QString sack = f.ack ? "ACK" : "NACK";
        for(i = 0; i < items.size(); i++)
            if(items[i]->text(ACK) != sack)
                items[i]->setHidden(true);
        headerItem()->setIcon(ACK, QIcon(ICON_PATH + "filter.png"));
    }
    else
        headerItem()->setIcon(ACK, QIcon(ICON_PATH + ""));


    if(f.lev)
    {
        for(i = 0; i < items.size(); i++)
        {
            /* must not have been hidden previously */
            if(!items[i]->isHidden())
            {
                if(items[i]->text(LEVEL) != f.level)
                    items[i]->setHidden(true);
            }
        }
        headerItem()->setIcon(LEVEL, QIcon(ICON_PATH + "filter.png"));
    }
    else
        headerItem()->setIcon(LEVEL, QIcon(ICON_PATH + ""));


    if(f.stat)
    {
        for(i = 0; i < items.size(); i++)
        {
            /* must not have been hidden previously */
            if(!items[i]->isHidden())
            {
                if(items[i]->text(STATUS) != f.status)
                    items[i]->setHidden(true);
            }
        }
        headerItem()->setIcon(STATUS, QIcon(ICON_PATH + "filter.png"));
    }
    else
        headerItem()->setIcon(STATUS, QIcon(ICON_PATH + ""));


    if(f.grp)
    {
        for(i = 0; i < items.size(); i++)
        {
            /* must not have been hidden previously */
            if(!items[i]->isHidden())
            {
                for(int j = 0; j < f.groups.size(); j++)
                {
114
                    if(!items[i]->text(DEVICE).contains(f.groups[j]))
Giacomo Strangolino's avatar
Giacomo Strangolino committed
115
116
117
118
119
120
121
                    {
                        items[i]->setHidden(true);
                        break;
                    }
                }
            }
        }
122
        headerItem()->setIcon(DEVICE, QIcon(ICON_PATH + "filter.png"));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
123
124
    }
    else
125
        headerItem()->setIcon(DEVICE, QIcon(ICON_PATH + ""));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

    _filter_enabled = true;

}

void AlarmTreeWidget::removeFilter()
{
    QList<QTreeWidgetItem *> items;
    int i;
    items = findItems("*", Qt::MatchWildcard);
    for(i = 0; i < items.size(); i++)
        if(items[i]->isHidden())
            items[i]->setHidden(false);
    _filter_enabled = false;
    headerItem()->setIcon(ACK, QIcon(ICON_PATH + ""));
    headerItem()->setIcon(LEVEL, QIcon(ICON_PATH + ""));
    headerItem()->setIcon(STATUS, QIcon(ICON_PATH + ""));
143
    headerItem()->setIcon(DEVICE, QIcon(ICON_PATH + ""));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
144
145
}

146
147
148
149
void AlarmTreeWidget::refresh(const CuData &v) {
    double d = static_cast<int>(v["timestamp_us"].toDouble());
    QString ts = QDateTime::fromSecsSinceEpoch(d).toString("HH:mm:ss");
    ts += QString("+%1").arg(d - static_cast<int>(d));
Giacomo Strangolino's avatar
Giacomo Strangolino committed
150
    QuString src(v, "src");
151
    bool err = v["err"].toBool();
Giacomo Strangolino's avatar
Giacomo Strangolino committed
152
    QStringList data = QuStringList(v, "value");
Giacomo Strangolino's avatar
tooltip    
Giacomo Strangolino committed
153
    setToolTip(QuString(v, "msg"));
154
    /* remove the filter */
155
    if (err) {
Giacomo Strangolino's avatar
Giacomo Strangolino committed
156
157
        src = QuString(v, "device");
        data = m_gen_error_item(v);
Giacomo Strangolino's avatar
tooltip    
Giacomo Strangolino committed
158
        perr("%s: %s\n", qstoc(src), qstoc(toolTip()));
159
    }
160
    else {
161
162
163
164
        int scrollBarPos;
        QStringList fields;
        QStringList alrnames;
        AlarmTreeWidgetItem* item = NULL;
Giacomo Strangolino's avatar
Giacomo Strangolino committed
165
        data = QuStringList(v, "value");
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
        QStringList high, medium, low, lowest, unknown_level;
        // group by level in order to sort view
        foreach(QString row, data) {
            QString level = row.split("\t").at(AlarmTreeWidget::LEVEL);
            if(level.contains("high"))
                high << row;
            else if(level.contains("lowest"))
                lowest << row;
            else if(level.contains("medium"))
                medium << row;
            else if(level.contains("low"))
                low << row;
            else
                unknown_level << row;
        }
        data = unknown_level + lowest + low + medium + high;

        int index = 0;
        const QSet<QString> oldset = mSrcAlarmHash.value(src);
        QSet<QString>& alsrcset = mSrcAlarmHash[src];
        alsrcset.clear(); // empty set for src
        /* add items to the tree(s) if not already present */
        for (int i = data.size() - 1; i >= 0; i--) {
            fields = data[i].split("\t");
            alrnames << fields.at(AlarmTreeWidgetItem::Alarm);
            /* save current scroll bar value */
            scrollBarPos = verticalScrollBar()->value();
193
            /* instead of GROUP information, show DEVICE */
Giacomo Strangolino's avatar
Giacomo Strangolino committed
194
            fields[DEVICE] = src.section('/', 0, src.count('/') - 1);
195
196
197

            item =  mItemHash.value(fields.at(AlarmTreeWidgetItem::Alarm));
            if(!item) /* create a new item */ {
198
199
200
201
202
                index = findPos(fields[0].toUInt(), fields[AlarmTreeWidgetItem::Level], fields[AlarmTreeWidgetItem::Status]);
                m_insert_item(src, fields, index);
//                printf("\e[1;33m%s \e[1;34m%s - number of tabs %d  -- index %d\e[0m\n",
//                       qstoc(QDateTime::fromTime_t(fields.first().toUInt()).toString()),
//                       qstoc(data[i]), data[i].count("\t"), index);
203
204
205
206
207
208
209
210
211
212
213
            }
            else /* update fields of existing items */
                item->update(fields);

            /* restore scrollbar value */
            verticalScrollBar()->setValue(scrollBarPos);

            // add alarm name to set of alarm names for this src
            alsrcset.insert(fields.at(AlarmTreeWidgetItem::Alarm));

            // notify new alarm detected. connected to Alarm::beep
214
            if(fields.size() > 5 && (fields[3] == "ALARM" || fields[3] == "ERROR") && fields.last()  == "NEW")
215
216
217
218
219
220
221
222
223
224
                emit newAlarmDetected();
        }

        /* remove stale items */
        QSet<QString> stale = oldset - alsrcset;
        m_remove_stale_items(stale);
    }
}


225
226
227
228
229
int AlarmTreeWidget::findPos(time_t ts, const QString &pri, const QString& status) {
    int i = 0, prio =  m_pri_to_int(pri), stat = m_status_to_int(status);
//    printf("findPos called with ts %ld, pri %d\n", ts, prio);
    while(i < topLevelItemCount() && topLevelItem(i)->data(AlarmTreeWidgetItem::Status, Qt::UserRole).toInt() > stat) {
//        printf("1st pri %d pri %d --> i %d\n", prio, topLevelItem(i)->data(AlarmTreeWidgetItem::Level, Qt::UserRole).toInt(), i);
230
        i++;
231
232
233
234
235
236
237
    }

    while(i < topLevelItemCount() && topLevelItem(i)->data(AlarmTreeWidgetItem::Level, Qt::UserRole).toInt() > prio
          && topLevelItem(i)->data(AlarmTreeWidgetItem::Status, Qt::UserRole).toInt() == stat) {
//        printf("1st pri %d pri %d --> i %d\n", prio, topLevelItem(i)->data(AlarmTreeWidgetItem::Level, Qt::UserRole).toInt(), i);
        i++;
    }
238
239
240
    // i points to the first item with same pri or to the very last item in the view

    while(i < topLevelItemCount() && topLevelItem(i)->data(AlarmTreeWidgetItem::DateTime, Qt::UserRole).toUInt() > ts
241
242
243
          && topLevelItem(i)->data(AlarmTreeWidgetItem::Level, Qt::UserRole).toInt() == prio
          && topLevelItem(i)->data(AlarmTreeWidgetItem::Status, Qt::UserRole).toInt() == stat) {
//        printf("1st ts %u item ts %u --> i %d\n", ts, topLevelItem(i)->data(AlarmTreeWidgetItem::DateTime, Qt::UserRole).toUInt(), i);
244
        i++;
Giacomo Strangolino's avatar
Giacomo Strangolino committed
245
    }
246
    return i;
Giacomo Strangolino's avatar
Giacomo Strangolino committed
247
}
248

Giacomo Strangolino's avatar
Giacomo Strangolino committed
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
void AlarmTreeWidget::contextMenuEvent(QContextMenuEvent *e)
{
    bool silenceAvail = true;
    QList<QTreeWidgetItem *>items = this->selectedItems();
    foreach(QTreeWidgetItem *it, items)
    {
        int sil = it->text(AlarmTreeWidgetItem::SilencedMin).toInt();
        if(sil < 0)
        {
            silenceAvail = false;
            break;
        }
    }
    if(items.size()) {
        QMenu *menu = new QMenu(this);
        menu->addAction("Acknowledge", this, SIGNAL(ack()));
        if(silenceAvail)
            menu->addAction("Silence", this, SIGNAL(silence()));

        QTreeWidgetItem* it = itemAt(e->pos());
        if(it && it->text(MESSAGE).contains("   ")) {
            QAction* wikiAction = menu->addAction("Wiki...");
            wikiAction->setProperty("url", it->text(MESSAGE).split("   ").last());
            connect(wikiAction, SIGNAL(triggered()), this, SLOT(openUrl()));
        }
        menu->exec(QCursor::pos());
        delete menu;
    }
}

279
void AlarmTreeWidget::m_insert_item(const QString& src, const QStringList &list, int index)
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
{
    qDebug() << __PRETTY_FUNCTION__ << "inserting " << list << index;
    AlarmTreeWidgetItem *item;
    QStringList fields(list);
    bool isNew = false;
    if(fields.size() > 0)
        fields[AlarmTreeWidgetItem::DateTime] = QDateTime::fromTime_t(list.at(AlarmTreeWidgetItem::DateTime).toUInt()).toString();

    if(fields.at(AlarmTreeWidgetItem::Alarm).contains("internal_error_"))
        item = new AlarmTreeWidgetItem(this, fields);
    else
    {
        if(fields.last().toUpper() == "NEW"){
            isNew = true;
        }
295
        fields.removeLast(); /* the last element contains "NEW" flag, need not be displayed */
296
        item = new AlarmTreeWidgetItem(fields);
297
298
299
300
301
        item->setData(AlarmTreeWidgetItem::Level, Qt::UserRole, m_pri_to_int(list[AlarmTreeWidgetItem::Level]));
        item->setData(AlarmTreeWidgetItem::DateTime, Qt::UserRole, list.at(AlarmTreeWidgetItem::DateTime).toUInt());
        item->setData(AlarmTreeWidgetItem::Status, Qt::UserRole, m_status_to_int(list.at(AlarmTreeWidgetItem::Status)));
        QString s = src.section('/', 0, src.count('/') - 1);
        item->setData(AlarmTreeWidgetItem::Device, Qt::UserRole, src.section('/', 0, src.count('/') - 1));
302
303
304
305
306
307
308
        insertTopLevelItem(index, item);
        item->setNew(isNew);
    }
    /* add the couple identifier/AlarmTreeWidgetItem to the hash */
    mItemHash.insert(fields.at(AlarmTreeWidgetItem::Alarm), item);
}

Giacomo Strangolino's avatar
Giacomo Strangolino committed
309
310
311
312
313
314
315
QStringList AlarmTreeWidget::m_gen_error_item(const CuData &da) const {
    QStringList l;
    QDateTime dt = QDateTime::currentDateTime();
    l << dt.toString() << "-" << QuString(da, "device") << "ERROR" << "NACK" << "1" << "high" << "-1" << "gr_handler" << QuString(da, "msg");
    return l;
}

316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333

void AlarmTreeWidget::m_remove_stale_items(const QSet<QString> stale_names) {
    foreach(const QString& name, stale_names) {
        AlarmTreeWidgetItem *item = mItemHash.value(name);
        if(item) {
            mItemHash.remove(name);
            delete item;
        }
    }
}

int AlarmTreeWidget::m_pri_to_int(const QString &pri) const {
    if(pri == "high") return 100;
    else if(pri == "medium") return 80;
    else if(pri == "low") return 50;
    else return 10;
}

334
335
336
int AlarmTreeWidget::m_status_to_int(const QString &stat) {
    if(stat == "ALARM")
        return 100;
337
338
    else if(stat == "ERROR")
        return 80;
339
340
341
    return 50;
}

Giacomo Strangolino's avatar
Giacomo Strangolino committed
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
void AlarmTreeWidget::mouseMoveEvent(QMouseEvent *event)
{
    QTreeWidget::mouseMoveEvent(event);
    QPoint p = event->pos();
    emit mouseOverItem(this->itemAt(p) != NULL);
}

void AlarmTreeWidget::slotItemEntered(QTreeWidgetItem* it, int)
{
    QString mes = it->text(AlarmTreeWidgetItem::Message);
    emit message(mes);
}

void AlarmTreeWidget::openUrl()
{
    QObject *send = sender();
    if(send->property("url").isValid()) {
        QDesktopServices::openUrl(QUrl(send->property("url").toString()));
    }
}