source: trunk/FACT++/gui/FactGui.h @ 10415

Last change on this file since 10415 was 10415, checked in by tbretz, 9 years ago
Removed obsolete second and thrid button.
File size: 17.8 KB
Line 
1#ifndef FACT_FactGui
2#define FACT_FactGui
3
4#include "MainWindow.h"
5
6#include <iomanip>
7
8#include <boost/bind.hpp>
9
10#include <QtGui/QStandardItemModel>
11
12#include "CheckBoxDelegate.h"
13
14#include "src/Converter.h"
15#include "src/HeadersFTM.h"
16#include "src/DimNetwork.h"
17
18using namespace std;
19
20class FactGui : public MainWindow, public DimNetwork
21{
22private:
23    class FunctionEvent : public QEvent
24    {
25    public:
26        boost::function<void(const QEvent &)> fFunction;
27
28        FunctionEvent(const boost::function<void(const QEvent &)> &f)
29            : QEvent((QEvent::Type)QEvent::registerEventType()),
30            fFunction(f) { }
31
32        bool Exec() { fFunction(*this); return true; }
33    };
34
35    DimInfo fDimDNS;
36    map<string, DimInfo*> fServices;
37
38    // ======================================================================
39
40    QStandardItem *AddServiceItem(const std::string &server, const std::string &service, bool iscmd)
41    {
42        QListView *servers     = iscmd ? fDimCmdServers     : fDimSvcServers;
43        QListView *services    = iscmd ? fDimCmdCommands    : fDimSvcServices;
44        QListView *description = iscmd ? fDimCmdDescription : fDimSvcDescription;
45
46        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
47        if (!m)
48        {
49            m = new QStandardItemModel(this);
50            servers->setModel(m);
51            services->setModel(m);
52            description->setModel(m);
53        }
54
55        QList<QStandardItem*> l = m->findItems(server.c_str());
56
57        if (l.size()>1)
58        {
59            cout << "hae" << endl;
60            return 0;
61        }
62
63        QStandardItem *col = l.size()==0 ? NULL : l[0];
64
65        if (!col)
66        {
67            col = new QStandardItem(server.c_str());
68            m->appendRow(col);
69
70            if (!services->rootIndex().isValid())
71            {
72                services->setRootIndex(col->index());
73                servers->setCurrentIndex(col->index());
74            }
75        }
76
77        QStandardItem *item = 0;
78        for (int i=0; i<col->rowCount(); i++)
79        {
80            QStandardItem *coli = col->child(i);
81            if (coli->text().toStdString()==service)
82                return coli;
83        }
84
85        item = new QStandardItem(service.c_str());
86        col->appendRow(item);
87
88        if (!description->rootIndex().isValid())
89        {
90            description->setRootIndex(item->index());
91            services->setCurrentIndex(item->index());
92        }
93
94        if (!iscmd)
95            item->setCheckable(true);
96
97        return item;
98    }
99
100    void AddDescription(QStandardItem *item, const vector<Description> &vec)
101    {
102        if (!item)
103            return;
104        if (vec.size()==0)
105            return;
106
107        item->setToolTip(vec[0].comment.c_str());
108
109        const string str = Description::GetHtmlDescription(vec);
110
111        QStandardItem *desc = new QStandardItem(str.c_str());
112        desc->setSelectable(false);
113        item->setChild(0, 0, desc);
114    }
115
116    // ======================================================================
117
118    void handleAddServer(const std::string &server)
119    {
120        const State s = GetState(server, GetCurrentState(server));
121        handleStateChanged(Time(), server, s);
122    }
123
124    void handleRemoveServer(const string &server)
125    {
126        handleStateOffline(server);
127        handleRemoveAllServices(server);
128    }
129
130    void handleRemoveAllServers()
131    {
132        QStandardItemModel *m = 0;
133        if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
134            m->removeRows(0, m->rowCount());
135
136        if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
137            m->removeRows(0, m->rowCount());
138    }
139
140    void handleAddService(const std::string &server, const std::string &service, const std::string &/*fmt*/, bool iscmd)
141    {
142        QStandardItem *item = AddServiceItem(server, service, iscmd);
143        const vector<Description> v = GetDescription(server, service);
144        AddDescription(item, v);
145    }
146
147    void handleRemoveService(const std::string &server, const std::string &service, bool iscmd)
148    {
149        QListView *servers = iscmd ? fDimCmdServers : fDimSvcServers;
150
151        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
152        if (!m)
153            return;
154
155        QList<QStandardItem*> l = m->findItems(server.c_str());
156        if (l.size()!=1)
157            return;
158
159        for (int i=0; i<l[0]->rowCount(); i++)
160        {
161            QStandardItem *row = l[0]->child(i);
162            if (row->text().toStdString()==service)
163            {
164                l[0]->removeRow(row->index().row());
165                return;
166            }
167        }
168    }
169
170    void handleRemoveAllServices(const std::string &server)
171    {
172        QStandardItemModel *m = 0;
173        if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
174        {
175            QList<QStandardItem*> l = m->findItems(server.c_str());
176            if (l.size()==1)
177                m->removeRow(l[0]->index().row());
178        }
179
180        if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
181        {
182            QList<QStandardItem*> l = m->findItems(server.c_str());
183            if (l.size()==1)
184                m->removeRow(l[0]->index().row());
185        }
186    }
187
188    void handleAddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
189    {
190        const bool iscmd = IsCommand(server, service)==true;
191
192        QStandardItem *item = AddServiceItem(server, service, iscmd);
193        AddDescription(item, vec);
194    }
195
196    void handleStateChanged(const Time &/*time*/, const std::string &server,
197                            const State &s)
198    {
199        // FIXME: Prefix tooltip with time
200        if (server=="FTM_CONTROL")
201        {
202            fStatusFTMLabel->setText(s.name.c_str());
203            fStatusFTMLabel->setToolTip(s.comment.c_str());
204
205            if (s.index<FTM::kDisconnected) // No Dim connection
206                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
207            if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
208                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
209            if (s.index==FTM::kConnected) // Dim connection / FTM connected
210                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
211        }
212
213        if (server=="FAD_CONTROL")
214        {
215            fStatusFADLabel->setText(s.name.c_str());
216            fStatusFADLabel->setToolTip(s.comment.c_str());
217
218            if (s.index<FTM::kDisconnected) // No Dim connection
219                fStatusFADLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
220            if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
221                fStatusFADLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
222            if (s.index==FTM::kConnected) // Dim connection / FTM connected
223                fStatusFADLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
224        }
225
226        if (server=="DATA_LOGGER")
227        {
228            fStatusLoggerLabel->setText(s.name.c_str());
229            fStatusLoggerLabel->setToolTip(s.comment.c_str());
230
231            if (s.index<-1) // Error
232                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
233            if (s.index>=0x100) // Error
234                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
235            if (s.index<=30)   // Waiting
236                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
237            if (s.index==40)   // Logging
238                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
239        }
240
241        if (server=="CHAT")
242        {
243            fStatusChatLabel->setText(s.name.c_str());
244
245            if (s.index==FTM::kConnected) // Dim connection / FTM connected
246                fStatusChatLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
247            else
248                fStatusChatLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
249        }
250    }
251
252    void handleStateOffline(const string &server)
253    {
254        handleStateChanged(Time(), server, State(-2, "Offline", "No connection via DIM."));
255    }
256
257    void handleWrite(const Time &time, const string &text, int qos)
258    {
259        stringstream out;
260
261        if (text.substr(0, 6)=="CHAT: ")
262        {
263            out << "<font size='-1' color='navy'>[<B>";
264            out << Time::fmt("%H:%M:%S") << time << "</B>]</FONT>  ";
265            out << text.substr(6);
266            fChatText->append(out.str().c_str());
267            return;
268        }
269
270
271        out << "<font color='";
272
273        switch (qos)
274        {
275        case kMessage: out << "black";   break;
276        case kInfo:    out << "green";   break;
277        case kWarn:    out << "#FF6600"; break;
278        case kError:   out << "maroon";  break;
279        case kFatal:   out << "maroon";  break;
280        case kDebug:   out << "navy";    break;
281        default:       out << "navy";    break;
282        }
283        out << "'>" << time.GetAsStr() << " - " << text << "</font>";
284
285        fLogText->append(out.str().c_str());
286
287        if (qos>=kWarn)
288            fTextEdit->append(out.str().c_str());
289    }
290
291    void handleDimService(const string &txt)
292    {
293        fDimSvcText->append(txt.c_str());
294    }
295
296    void handleDimDNS(int version)
297    {
298        ostringstream str;
299        str << "DIM V" << version/100 << 'r' << version%100;
300
301        if (version==0)
302            fStatusDNSLed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
303        else
304            fStatusDNSLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
305
306        fStatusDNSLabel->setText(version==0?"Offline":str.str().c_str());
307        fStatusDNSLabel->setToolTip(version==0?"No connection to DIM DNS.":"Connection to DIM DNS established.");
308    }
309
310    // ======================================================================
311
312    void AddServer(const std::string &s)
313    {
314        DimNetwork::AddServer(s);
315
316        QApplication::postEvent(this,
317           new FunctionEvent(boost::bind(&FactGui::handleAddServer, this, s)));
318    }
319
320    void RemoveServer(const std::string &s)
321    {
322        UnsubscribeServer(s);
323
324        DimNetwork::RemoveServer(s);
325
326        QApplication::postEvent(this,
327           new FunctionEvent(boost::bind(&FactGui::handleRemoveServer, this, s)));
328    }
329
330    void RemoveAllServers()
331    {
332        UnsubscribeAllServers();
333
334        vector<string> v = GetServerList();
335        for (vector<string>::iterator i=v.begin(); i<v.end(); i++)
336            QApplication::postEvent(this,
337                                    new FunctionEvent(boost::bind(&FactGui::handleStateOffline, this, *i)));
338
339        DimNetwork::RemoveAllServers();
340
341        QApplication::postEvent(this,
342           new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServers, this)));
343    }
344
345    void AddService(const std::string &server, const std::string &service, const std::string &fmt, bool iscmd)
346    {
347        QApplication::postEvent(this,
348           new FunctionEvent(boost::bind(&FactGui::handleAddService, this, server, service, fmt, iscmd)));
349    }
350
351    void RemoveService(const std::string &server, const std::string &service, bool iscmd)
352    {
353        if (fServices.find(server+'/'+service)!=fServices.end())
354            UnsubscribeService(server+'/'+service);
355
356        QApplication::postEvent(this,
357           new FunctionEvent(boost::bind(&FactGui::handleRemoveService, this, server, service, iscmd)));
358    }
359
360    void RemoveAllServices(const std::string &server)
361    {
362        UnsubscribeServer(server);
363
364        QApplication::postEvent(this,
365           new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServices, this, server)));
366    }
367
368    void AddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
369    {
370        QApplication::postEvent(this,
371           new FunctionEvent(boost::bind(&FactGui::handleAddDescription, this, server, service, vec)));
372    }
373
374
375    void IndicateStateChange(const Time &time, const std::string &server)
376    {
377        const State s = GetState(server, GetCurrentState(server));
378
379        QApplication::postEvent(this,
380           new FunctionEvent(boost::bind(&FactGui::handleStateChanged, this, time, server, s)));
381    }
382
383    int Write(const Time &time, const string &txt, int qos)
384    {
385        QApplication::postEvent(this,
386           new FunctionEvent(boost::bind(&FactGui::handleWrite, this, time, txt, qos)));
387
388        return 0;
389    }
390
391    void infoHandler(DimInfo &info)
392    {
393        const string fmt = string("DIS_DNS/SERVER_INFO")==info.getName() ? "C" : info.getFormat();
394
395        stringstream dummy;
396        const Converter conv(dummy, fmt, false);
397
398        const Time tm(info.getTimestamp(), info.getTimestampMillisecs());
399
400        stringstream out;
401        out << Time::fmt("%H:%M:%S.%f") << tm << "   <B>" << info.getName() << "</B> - ";
402
403        bool iserr = false;
404        if (!conv)
405        {
406            out << "Compilation of format string '" << fmt << "' failed!";
407            iserr = true;
408        }
409        else
410        {
411            try
412            {
413                const string dat = conv.GetString(info.getData(), info.getSize());
414                out << dat;
415            }
416            catch (const runtime_error &e)
417            {
418                out << "Conversion to string failed!<pre>" << e.what() << "</pre>";
419                iserr = true;
420            }
421        }
422
423        // srand(hash<string>()(string(info.getName())));
424        // int bg = rand()&0xffffff;
425
426        int bg = hash<string>()(string(info.getName()));
427
428        int r = bg&0x1f0000;
429        int g = bg&0x001f00;
430        int b = bg&0x00001f;
431
432        bg = ~(b|g|r)&0xffffff;
433
434        if (iserr)
435            bg = 0xffffff;
436
437        stringstream bgcol;
438        bgcol << hex << setfill('0') << setw(6) << bg;
439
440        const string col = iserr ? "red" : "black";
441        const string str = "<table width='100%' bgcolor=#"+bgcol.str()+"><tr><td><font color='"+col+"'>"+out.str()+"</font></td></tr></table>";
442
443        QApplication::postEvent(this,
444                                new FunctionEvent(boost::bind(&FactGui::handleDimService, this, str)));
445    }
446
447    void infoHandler()
448    {
449        if (getInfo()==&fDimDNS)
450        {
451            QApplication::postEvent(this,
452                                    new FunctionEvent(boost::bind(&FactGui::handleDimDNS, this, getInfo()->getInt())));
453            return;
454        }
455
456        for (map<string,DimInfo*>::iterator i=fServices.begin(); i!=fServices.end(); i++)
457            if (i->second==getInfo())
458            {
459                infoHandler(*i->second);
460                return;
461            }
462
463        DimNetwork::infoHandler();
464    }
465
466    // ======================================================================
467
468
469    void SubscribeService(const string &service)
470    {
471        if (fServices.find(service)!=fServices.end())
472        {
473            cout << "ERROR - We are already subscribed to " << service << endl;
474            return;
475        }
476
477        fServices[service] = new DimStampedInfo(service.c_str(), (void*)NULL, 0, this);
478    }
479
480    void UnsubscribeService(const string &service)
481    {
482        const map<string,DimInfo*>::iterator i=fServices.find(service);
483
484        if (i==fServices.end())
485        {
486            cout << "ERROR - We are not subscribed to " << service << endl;
487            return;
488        }
489
490        delete i->second;
491
492        fServices.erase(i);
493    }
494
495    void UnsubscribeServer(const string &server)
496    {
497        for (map<string,DimInfo*>::iterator i=fServices.begin();
498             i!=fServices.end(); i++)
499            if (i->first.substr(0, server.length()+1)==server+'/')
500            {
501                delete i->second;
502                fServices.erase(i);
503            }
504    }
505
506    void UnsubscribeAllServers()
507    {
508        for (map<string,DimInfo*>::iterator i=fServices.begin();
509             i!=fServices.end(); i++)
510            delete i->second;
511
512        fServices.clear();
513    }
514
515    // ======================================================================
516
517    bool event(QEvent *evt)
518    {
519        if (dynamic_cast<FunctionEvent*>(evt))
520            return static_cast<FunctionEvent*>(evt)->Exec();
521
522        if (dynamic_cast<CheckBoxEvent*>(evt))
523        {
524            const QStandardItem &item = static_cast<CheckBoxEvent*>(evt)->item;
525            const QStandardItem *par  = item.parent();
526            if (par)
527            {
528                const QString server  = par->text();
529                const QString service = item.text();
530
531                const string s = (server+'/'+service).toStdString();
532
533                if (item.checkState()==Qt::Checked)
534                    SubscribeService(s);
535                else
536                    UnsubscribeService(s);
537            }
538        }
539
540        return MainWindow::event(evt); // unrecognized
541    }
542
543    void on_fDimCmdSend_clicked(bool)
544    {
545        const QString server    = fDimCmdServers->currentIndex().data().toString();
546        const QString command   = fDimCmdCommands->currentIndex().data().toString();
547        const QString arguments = fDimCmdLineEdit->displayText();
548
549        // FIXME: Sending a command exactly when the info Handler changes
550        //        the list it might lead to confusion.
551        try
552        {
553            SendDimCommand(server.toStdString(), command.toStdString()+" "+arguments.toStdString());
554            fTextEdit->append("<font color='green'>Command '"+server+'/'+command+"' successfully emitted.</font>");
555            fDimCmdLineEdit->clear();
556        }
557        catch (const runtime_error &e)
558        {
559            stringstream txt;
560            txt << e.what();
561
562            string buffer;
563            while (getline(txt, buffer, '\n'))
564                fTextEdit->append(("<font color='red'><pre>"+buffer+"</pre></font>").c_str());
565        }
566    }
567
568public:
569    FactGui() : fDimDNS("DIS_DNS/VERSION_NUMBER", 1, int(0), this)
570    {
571        DimClient::sendCommand("CHAT/MSG", "GUI online.");
572        // + MessageDimRX
573    }
574    ~FactGui()
575    {
576        UnsubscribeAllServers();
577    }
578};
579
580#endif
Note: See TracBrowser for help on using the repository browser.