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

Last change on this file since 10633 was 10633, checked in by tbretz, 9 years ago
Fixed case of sclaing in Rates plot == 0
File size: 53.4 KB
Line 
1#ifndef FACT_FactGui
2#define FACT_FactGui
3
4#include "MainWindow.h"
5
6#include <iomanip>
7#include <valarray>
8
9#include <boost/bind.hpp>
10
11#include <QTimer>
12#include <QStandardItemModel>
13
14#include "CheckBoxDelegate.h"
15
16#include "src/Converter.h"
17#include "src/HeadersFTM.h"
18#include "src/DimNetwork.h"
19#include "src/tools.h"
20
21#include "TROOT.h"
22#include "TSystem.h"
23#include "TGraph.h"
24#include "TH1.h"
25#include "TStyle.h"
26#include "TMarker.h"
27#include "TColor.h"
28
29#define HAS_ROOT
30
31using namespace std;
32
33// #########################################################################
34
35class Camera : public TObject
36{
37    typedef pair<double,double> Position;
38    typedef vector<Position> Positions;
39
40    Positions fGeom;
41
42    void CreatePalette()
43    {
44        /*
45         double ss[5] = {0., 0.10, 0.45, 0.75, 1.00};
46         double rr[5] = {0., 0.35, 0.85, 1.00, 1.00};
47         double gg[5] = {0., 0.10, 0.20, 0.73, 1.00};
48         double bb[5] = {0., 0.03, 0.06, 0.00, 1.00};
49         */
50        double ss[5] = {0., 0.25, 0.50, 0.75, 1.00};
51        double rr[5] = {0., 0.00, 0.00, 1.00, 1.00};
52        double gg[5] = {0., 0.00, 1.00, 0.00, 1.00};
53        double bb[5] = {0., 1.00, 0.00, 0.00, 1.00};
54
55        const Int_t nn = 1438;
56
57        Int_t idx = TColor::CreateGradientColorTable(5, ss, rr, gg, bb, nn);
58        for (int i=0; i<nn; i++)
59            fPalette.push_back(idx++);
60    }
61
62    void CreateGeometry()
63    {
64        const double gsSin60 = sqrt(3.)/2;
65
66        const int rings = 23;
67
68        //  add the first pixel to the list
69
70        fGeom.push_back(make_pair(0, -0.5));
71
72        for (int ring=1; ring<=rings; ring++)
73        {
74            for (int s=0; s<6; s++)
75            {
76                for (int i=1; i<=ring; i++)
77                {
78                    double xx, yy;
79                    switch (s)
80                    {
81                    case 0: // Direction South East
82                        xx = (ring+i)*0.5;
83                        yy = (-ring+i)*gsSin60;
84                        break;
85
86                    case 1: // Direction North East
87                        xx = ring-i*0.5;
88                        yy = i*gsSin60;
89                        break;
90
91                    case 2: // Direction North
92                        xx = ring*0.5-i;
93                        yy = ring*gsSin60;
94                        break;
95
96                    case 3: // Direction North West
97                        xx = -(ring+i)*0.5;
98                        yy = (ring-i)*gsSin60;
99                        break;
100
101                    case 4: // Direction South West
102                        xx = 0.5*i-ring;
103                        yy = -i*gsSin60;
104                        break;
105
106                    case 5: // Direction South
107                        xx = i-ring*0.5;
108                        yy = -ring*gsSin60;
109                        break;
110                    }
111
112                    if (xx*xx + yy*yy - xx > 395.75)
113                        continue;
114
115                    fGeom.push_back(make_pair(yy, xx-0.5));
116                }
117            }
118        }
119    }
120
121    valarray<double> fData;
122    map<int, bool>   fBold;
123    map<int, bool>   fEnable;
124
125    int fWhite;
126
127public:
128    Camera() : fData(0., 1438), fWhite(-1)
129    {
130        CreatePalette();
131        CreateGeometry();
132
133        for (int i=0; i<1438; i++)
134            fData[i] = i;
135    }
136
137    void Reset() { fBold.clear(); }
138
139    void SetBold(int idx) { fBold[idx]=true; }
140    void SetWhite(int idx) { fWhite=idx; }
141    void SetEnable(int idx, bool b) { fEnable[idx]=b; }
142    void Toggle(int idx) { fEnable[idx]=!fEnable[idx]; }
143
144    const char *GetName() const { return "Camera"; }
145
146    vector<Int_t> fPalette;
147
148    void Paint(const Position &p)
149    {
150        static const Double_t fgCos60 = 0.5;        // TMath::Cos(60/TMath::RadToDeg());
151        static const Double_t fgSin60 = sqrt(3.)/2; // TMath::Sin(60/TMath::RadToDeg());
152
153        static const Double_t fgDy[6] = { fgCos60,   0.,         -fgCos60,   -fgCos60,    0.,           fgCos60   };
154        static const Double_t fgDx[6] = { fgSin60/3, fgSin60*2/3, fgSin60/3, -fgSin60/3, -fgSin60*2/3, -fgSin60/3 };
155
156        //
157        //  calculate the positions of the pixel corners
158        //
159        Double_t x[7], y[7];
160        for (Int_t i=0; i<7; i++)
161        {
162            x[i] = p.first  + fgDx[i%6];
163            y[i] = p.second + fgDy[i%6];
164        }
165
166        gPad->PaintFillArea(6, x, y);
167        gPad->PaintPolyLine(7, x, y);
168
169    }
170
171    void Paint(Option_t *)
172    {
173        gStyle->SetPalette(fPalette.size(), fPalette.data());
174
175
176        const double r   = double(gPad->GetWw())/gPad->GetWh();
177        const double max = 20.5; // 20.5 rings in x and y
178
179        if (r>1)
180            gPad->Range(-r*max, -max, r*max, max);
181        else
182            gPad->Range(-max, -max/r, max, max/r);
183
184
185        const double min   = fData.min();
186        const double scale = fData.max()==fData.min() ? 1 : fData.max()-fData.min();
187
188        TAttFill fill(0, 1001);
189        TAttLine line;
190
191        int cnt=0;
192        for (Positions::iterator p=fGeom.begin(); p!=fGeom.end(); p++, cnt++)
193        {
194            if (fBold[cnt])
195                continue;
196
197            const int col = (fData[cnt]-min)/scale*(fPalette.size()-1);
198
199            if (fEnable[cnt])
200                fill.SetFillColor(gStyle->GetColorPalette(col));
201            else
202                fill.SetFillColor(kWhite);
203
204            fill.Modify();
205
206            Paint(*p);
207        }
208
209        line.SetLineWidth(2);
210        line.Modify();
211
212        cnt = 0;
213        for (Positions::iterator p=fGeom.begin(); p!=fGeom.end(); p++, cnt++)
214        {
215            if (!fBold[cnt])
216                continue;
217
218            const int col = (fData[cnt]-min)/scale*(fPalette.size()-1);
219
220            if (fEnable[cnt])
221                fill.SetFillColor(gStyle->GetColorPalette(col));
222            else
223                fill.SetFillColor(kWhite);
224            fill.Modify();
225
226            Paint(*p);
227        }
228
229        TMarker m(0,0,kStar);
230        m.DrawMarker(0, 0);
231
232        if (fWhite<0)
233            return;
234
235        const Position &p = fGeom[fWhite];
236
237        line.SetLineColor(kWhite);
238        line.Modify();
239
240        const int col = (fData[fWhite]-min)/scale*(fPalette.size()-1);
241
242        if (fEnable[fWhite])
243            fill.SetFillColor(gStyle->GetColorPalette(col));
244        else
245            fill.SetFillColor(kWhite);
246        fill.Modify();
247
248        Paint(p);
249    }
250
251    int GetIdx(float px, float py) const
252    {
253        static const double sqrt3 = sqrt(3);
254
255        int idx = 0;
256        for (Positions::const_iterator p=fGeom.begin(); p!=fGeom.end(); p++, idx++)
257        {
258            const Double_t dy = py - p->second;
259            if (fabs(dy)>0.5)
260                continue;
261
262            const Double_t dx = px - p->first;
263
264            if  (TMath::Abs(dy + dx*sqrt3) > 1)
265                continue;
266
267            if  (TMath::Abs(dy - dx*sqrt3) > 1)
268                continue;
269
270            return idx;
271        }
272        return -1;
273    }
274
275    char* GetObjectInfo(Int_t px, Int_t py) const
276    {
277        static stringstream stream;
278        static string       str;
279
280        const float x = gPad->PadtoX(gPad->AbsPixeltoX(px));
281        const float y = gPad->PadtoY(gPad->AbsPixeltoY(py));
282
283        const int idx = GetIdx(x, y);
284
285        stream.seekp(0);
286        if (idx>=0)
287            stream << "Pixel=" << idx << "   Data=" << fData[idx] << '\0';
288
289        str = stream.str();
290        return const_cast<char*>(str.c_str());
291    }
292
293    Int_t DistancetoPrimitive(Int_t px, Int_t py)
294    {
295        const float x = gPad->PadtoX(gPad->AbsPixeltoX(px));
296        const float y = gPad->PadtoY(gPad->AbsPixeltoY(py));
297
298        return GetIdx(x, y)>=0 ? 0 : 99999;
299    }
300
301    void SetData(const valarray<double> &data)
302    {
303        fData = data;
304    }
305};
306
307// #########################################################################
308
309
310class FactGui : public MainWindow, public DimNetwork
311{
312private:
313    class FunctionEvent : public QEvent
314    {
315    public:
316        boost::function<void(const QEvent &)> fFunction;
317
318        FunctionEvent(const boost::function<void(const QEvent &)> &f)
319            : QEvent((QEvent::Type)QEvent::registerEventType()),
320            fFunction(f) { }
321
322        bool Exec() { fFunction(*this); return true; }
323    };
324
325    valarray<int8_t> fFtuStatus;
326
327    DimStampedInfo fDimDNS;
328
329    DimStampedInfo fDimLoggerStats;
330    DimStampedInfo fDimLoggerFilenameNight;
331    DimStampedInfo fDimLoggerFilenameRun;
332    DimStampedInfo fDimLoggerNumSubs;
333
334    DimStampedInfo fDimFtmPassport;
335    DimStampedInfo fDimFtmTriggerCounter;
336    DimStampedInfo fDimFtmError;
337    DimStampedInfo fDimFtmFtuList;
338    DimStampedInfo fDimFtmStaticData;
339    DimStampedInfo fDimFtmDynamicData;
340    DimStampedInfo fDimFtmCounter;
341
342    map<string, DimInfo*> fServices;
343
344    // ===================== Services and Commands ==========================
345
346    QStandardItem *AddServiceItem(const std::string &server, const std::string &service, bool iscmd)
347    {
348        QListView *servers     = iscmd ? fDimCmdServers     : fDimSvcServers;
349        QListView *services    = iscmd ? fDimCmdCommands    : fDimSvcServices;
350        QListView *description = iscmd ? fDimCmdDescription : fDimSvcDescription;
351
352        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
353        if (!m)
354        {
355            m = new QStandardItemModel(this);
356            servers->setModel(m);
357            services->setModel(m);
358            description->setModel(m);
359        }
360
361        QList<QStandardItem*> l = m->findItems(server.c_str());
362
363        if (l.size()>1)
364        {
365            cout << "hae" << endl;
366            return 0;
367        }
368
369        QStandardItem *col = l.size()==0 ? NULL : l[0];
370
371        if (!col)
372        {
373            col = new QStandardItem(server.c_str());
374            m->appendRow(col);
375
376            if (!services->rootIndex().isValid())
377            {
378                services->setRootIndex(col->index());
379                servers->setCurrentIndex(col->index());
380            }
381        }
382
383        QStandardItem *item = 0;
384        for (int i=0; i<col->rowCount(); i++)
385        {
386            QStandardItem *coli = col->child(i);
387            if (coli->text().toStdString()==service)
388                return coli;
389        }
390
391        item = new QStandardItem(service.c_str());
392        col->appendRow(item);
393        col->sortChildren(0);
394
395        if (!description->rootIndex().isValid())
396        {
397            description->setRootIndex(item->index());
398            services->setCurrentIndex(item->index());
399        }
400
401        if (!iscmd)
402            item->setCheckable(true);
403
404        return item;
405    }
406
407    void AddDescription(QStandardItem *item, const vector<Description> &vec)
408    {
409        if (!item)
410            return;
411        if (vec.size()==0)
412            return;
413
414        item->setToolTip(vec[0].comment.c_str());
415
416        const string str = Description::GetHtmlDescription(vec);
417
418        QStandardItem *desc = new QStandardItem(str.c_str());
419        desc->setSelectable(false);
420        item->setChild(0, 0, desc);
421    }
422
423    void AddServer(const std::string &s)
424    {
425        DimNetwork::AddServer(s);
426
427        QApplication::postEvent(this,
428           new FunctionEvent(boost::bind(&FactGui::handleAddServer, this, s)));
429    }
430
431    void RemoveServer(const std::string &s)
432    {
433        UnsubscribeServer(s);
434
435        DimNetwork::RemoveServer(s);
436
437        QApplication::postEvent(this,
438           new FunctionEvent(boost::bind(&FactGui::handleRemoveServer, this, s)));
439    }
440
441    void RemoveAllServers()
442    {
443        UnsubscribeAllServers();
444
445        vector<string> v = GetServerList();
446        for (vector<string>::iterator i=v.begin(); i<v.end(); i++)
447            QApplication::postEvent(this,
448                                    new FunctionEvent(boost::bind(&FactGui::handleStateOffline, this, *i)));
449
450        DimNetwork::RemoveAllServers();
451
452        QApplication::postEvent(this,
453           new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServers, this)));
454    }
455
456    void AddService(const std::string &server, const std::string &service, const std::string &fmt, bool iscmd)
457    {
458        QApplication::postEvent(this,
459           new FunctionEvent(boost::bind(&FactGui::handleAddService, this, server, service, fmt, iscmd)));
460    }
461
462    void RemoveService(const std::string &server, const std::string &service, bool iscmd)
463    {
464        if (fServices.find(server+'/'+service)!=fServices.end())
465            UnsubscribeService(server+'/'+service);
466
467        QApplication::postEvent(this,
468           new FunctionEvent(boost::bind(&FactGui::handleRemoveService, this, server, service, iscmd)));
469    }
470
471    void RemoveAllServices(const std::string &server)
472    {
473        UnsubscribeServer(server);
474
475        QApplication::postEvent(this,
476           new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServices, this, server)));
477    }
478
479    void AddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
480    {
481        QApplication::postEvent(this,
482           new FunctionEvent(boost::bind(&FactGui::handleAddDescription, this, server, service, vec)));
483    }
484
485    // ======================================================================
486
487    void handleAddServer(const std::string &server)
488    {
489        const State s = GetState(server, GetCurrentState(server));
490        handleStateChanged(Time(), server, s);
491    }
492
493    void handleRemoveServer(const string &server)
494    {
495        handleStateOffline(server);
496        handleRemoveAllServices(server);
497    }
498
499    void handleRemoveAllServers()
500    {
501        QStandardItemModel *m = 0;
502        if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
503            m->removeRows(0, m->rowCount());
504
505        if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
506            m->removeRows(0, m->rowCount());
507    }
508
509    void handleAddService(const std::string &server, const std::string &service, const std::string &/*fmt*/, bool iscmd)
510    {
511        QStandardItem *item = AddServiceItem(server, service, iscmd);
512        const vector<Description> v = GetDescription(server, service);
513        AddDescription(item, v);
514    }
515
516    void handleRemoveService(const std::string &server, const std::string &service, bool iscmd)
517    {
518        QListView *servers = iscmd ? fDimCmdServers : fDimSvcServers;
519
520        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
521        if (!m)
522            return;
523
524        QList<QStandardItem*> l = m->findItems(server.c_str());
525        if (l.size()!=1)
526            return;
527
528        for (int i=0; i<l[0]->rowCount(); i++)
529        {
530            QStandardItem *row = l[0]->child(i);
531            if (row->text().toStdString()==service)
532            {
533                l[0]->removeRow(row->index().row());
534                return;
535            }
536        }
537    }
538
539    void handleRemoveAllServices(const std::string &server)
540    {
541        QStandardItemModel *m = 0;
542        if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
543        {
544            QList<QStandardItem*> l = m->findItems(server.c_str());
545            if (l.size()==1)
546                m->removeRow(l[0]->index().row());
547        }
548
549        if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
550        {
551            QList<QStandardItem*> l = m->findItems(server.c_str());
552            if (l.size()==1)
553                m->removeRow(l[0]->index().row());
554        }
555    }
556
557    void handleAddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
558    {
559        const bool iscmd = IsCommand(server, service)==true;
560
561        QStandardItem *item = AddServiceItem(server, service, iscmd);
562        AddDescription(item, vec);
563    }
564
565    // ======================================================================
566
567    void SubscribeService(const string &service)
568    {
569        if (fServices.find(service)!=fServices.end())
570        {
571            cout << "ERROR - We are already subscribed to " << service << endl;
572            return;
573        }
574
575        fServices[service] = new DimStampedInfo(service.c_str(), (void*)NULL, 0, this);
576    }
577
578    void UnsubscribeService(const string &service)
579    {
580        const map<string,DimInfo*>::iterator i=fServices.find(service);
581
582        if (i==fServices.end())
583        {
584            cout << "ERROR - We are not subscribed to " << service << endl;
585            return;
586        }
587
588        delete i->second;
589
590        fServices.erase(i);
591    }
592
593    void UnsubscribeServer(const string &server)
594    {
595        for (map<string,DimInfo*>::iterator i=fServices.begin();
596             i!=fServices.end(); i++)
597            if (i->first.substr(0, server.length()+1)==server+'/')
598            {
599                delete i->second;
600                fServices.erase(i);
601            }
602    }
603
604    void UnsubscribeAllServers()
605    {
606        for (map<string,DimInfo*>::iterator i=fServices.begin();
607             i!=fServices.end(); i++)
608            delete i->second;
609
610        fServices.clear();
611    }
612
613    // ======================================================================
614
615    struct DimData
616    {
617        Time time;
618        int  qos;
619        string name;
620        string format;
621        vector<char> data;
622
623        DimInfo *info;  // this is ONLY for a fast check of the type of the DimData!!
624
625        DimData(DimInfo *inf) :
626            qos(inf->getQuality()),
627            name(inf->getName()),
628            format(inf->getFormat()),
629            data(inf->getString(), inf->getString()+inf->getSize()),
630            info(inf)
631        {
632            // Must be called in exactly this order!
633            const int tsec = inf->getTimestamp();
634            const int tms  = inf->getTimestampMillisecs();
635
636            time = Time(tsec, tms*1000);
637        }
638
639        template<typename T>
640                T get() const { return *reinterpret_cast<const T*>(data.data()); }
641
642            vector<char> vec(int b) const { return vector<char>(data.begin()+b, data.end()); }
643            string str(unsigned int b) const { return b>=data.size()?string():string(data.data()+b, data.size()-b); }
644            const char *c_str() const { return (char*)data.data(); }
645
646            vector<boost::any> any() const
647            {
648                const Converter conv(format);
649                conv.Print();
650                return conv.GetAny(data.data(), data.size());
651            }
652            int size() const { return data.size(); }
653            const void *ptr() const { return data.data(); }
654    };
655
656    // ======================= DNS ==========================================
657
658    void handleDimDNS(const DimData &d)
659    {
660        const int version = d.get<unsigned int>();
661
662        ostringstream str;
663        str << "V" << version/100 << 'r' << version%100;
664
665        if (version==0)
666            fStatusDNSLed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
667        else
668            fStatusDNSLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
669
670        fStatusDNSLabel->setText(version==0?"Offline":str.str().c_str());
671        fStatusDNSLabel->setToolTip(version==0?"No connection to DIM DNS.":"Connection to DIM DNS established.");
672    }
673
674
675    // ======================= Logger =======================================
676
677    void handleLoggerStats(const DimData &d)
678    {
679        const bool connected = d.size()!=0;
680
681        fLoggerET->setEnabled(connected);
682        fLoggerRate->setEnabled(connected);
683        fLoggerWritten->setEnabled(connected);
684        fLoggerFreeSpace->setEnabled(connected);
685        fLoggerSpaceLeft->setEnabled(connected);
686
687        if (!connected)
688            return;
689
690        const uint64_t *vals = reinterpret_cast<const uint64_t*>(d.ptr());
691
692        const size_t written = vals[0];
693        const size_t space   = vals[1];
694        const size_t rate    = vals[2];
695
696        fLoggerFreeSpace->setSuffix(" MB");
697        fLoggerFreeSpace->setDecimals(0);
698        fLoggerFreeSpace->setValue(space*1e-6);
699
700        if (space>   1000000)  // > 1GB
701        {
702            fLoggerFreeSpace->setSuffix(" GB");
703            fLoggerFreeSpace->setDecimals(2);
704            fLoggerFreeSpace->setValue(space*1e-9);
705        }
706        if (space>=  3000000)  // >= 3GB
707        {
708            fLoggerFreeSpace->setSuffix(" GB");
709            fLoggerFreeSpace->setDecimals(1);
710            fLoggerFreeSpace->setValue(space*1e-9);
711        }
712        if (space>=100000000)  // >= 100GB
713        {
714            fLoggerFreeSpace->setSuffix(" GB");
715            fLoggerFreeSpace->setDecimals(0);
716            fLoggerFreeSpace->setValue(space*1e-9);
717        }
718
719        fLoggerET->setTime(QTime().addSecs(rate>0?space/rate:0));
720        fLoggerRate->setValue(rate*1e-3); // kB/s
721        fLoggerWritten->setValue(written*1e-6);
722
723        fLoggerRate->setSuffix(" kB/s");
724        fLoggerRate->setDecimals(2);
725        fLoggerRate->setValue(rate*1e-3);
726        if (rate>   2000)  // > 2kB/s
727        {
728            fLoggerRate->setSuffix(" kB/s");
729            fLoggerRate->setDecimals(1);
730            fLoggerRate->setValue(rate*1e-3);
731        }
732        if (rate>=100000)  // >100kB/s
733        {
734            fLoggerRate->setSuffix(" kB/s");
735            fLoggerRate->setDecimals(0);
736            fLoggerRate->setValue(rate*1e-3);
737        }
738        if (rate>=1000000)  // >100kB/s
739        {
740            fLoggerRate->setSuffix(" MB/s");
741            fLoggerRate->setDecimals(2);
742            fLoggerRate->setValue(rate*1e-6);
743        }
744        if (rate>=10000000)  // >1MB/s
745        {
746            fLoggerRate->setSuffix(" MB/s");
747            fLoggerRate->setDecimals(1);
748            fLoggerRate->setValue(rate*1e-6);
749        }
750        if (rate>=100000000)  // >10MB/s
751        {
752            fLoggerRate->setSuffix(" MB/s");
753            fLoggerRate->setDecimals(0);
754            fLoggerRate->setValue(rate*1e-6);
755        }
756
757        if (space/1000000>static_cast<size_t>(fLoggerSpaceLeft->maximum()))
758            fLoggerSpaceLeft->setValue(fLoggerSpaceLeft->maximum());  // GB
759        else
760            fLoggerSpaceLeft->setValue(space/1000000);  // MB
761    }
762
763    void handleLoggerFilenameNight(const DimData &d)
764    {
765        const bool connected = d.size()!=0;
766
767        fLoggerFilenameNight->setEnabled(connected);
768        if (!connected)
769            return;
770
771        fLoggerFilenameNight->setText(d.c_str()+4);
772
773        const uint32_t files = d.get<uint32_t>();
774
775        if (files&1)
776            fLoggerLedLog->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
777        else
778            fLoggerLedLog->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
779
780        if (files&2)
781            fLoggerLedRep->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
782        else
783            fLoggerLedRep->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
784
785        if (files&4)
786            fLoggerLedFits->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
787        else
788            fLoggerLedFits->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
789    }
790
791    void handleLoggerFilenameRun(const DimData &d)
792    {
793        const bool connected = d.size()!=0;
794
795        fLoggerFilenameRun->setEnabled(connected);
796        if (!connected)
797            return;
798
799        fLoggerFilenameRun->setText(d.c_str()+4);
800
801        const uint32_t files = d.get<uint32_t>();
802
803        if (files&1)
804            fLoggerLedLog->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
805        else
806            fLoggerLedLog->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
807
808        if (files&2)
809            fLoggerLedRep->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
810        else
811            fLoggerLedRep->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
812
813        if (files&4)
814            fLoggerLedFits->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
815        else
816            fLoggerLedFits->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
817    }
818
819    void handleLoggerNumSubs(const DimData &d)
820    {
821        const bool connected = d.size()!=0;
822
823        fLoggerSubscriptions->setEnabled(connected);
824        fLoggerOpenFiles->setEnabled(connected);
825        if (!connected)
826            return;
827
828        const uint32_t *vals = reinterpret_cast<const uint32_t*>(d.ptr());
829
830        fLoggerSubscriptions->setValue(vals[0]);
831        fLoggerOpenFiles->setValue(vals[1]);
832    }
833
834    // ===================== FTM ============================================
835
836    void handleFtmTriggerCounter(const DimData &d)
837    {
838        if (d.size()==0)
839            return;
840
841        if (d.size()!=sizeof(FTM::DimTriggerCounter))
842        {
843            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimTriggerCounter) << endl;
844            return;
845        }
846
847        const FTM::DimTriggerCounter &sdata = *reinterpret_cast<const FTM::DimTriggerCounter*>(d.ptr());
848
849        fFtmTime->setText(QString::number(sdata.fTimeStamp));
850        fTriggerCounter->setText(QString::number(sdata.fTriggerCounter));
851    }
852
853    void handleFtmCounter(const DimData &d)
854    {
855        if (d.size()==0)
856            return;
857
858        if (d.size()!=sizeof(uint32_t)*6)
859        {
860            cout << "Size mismatch: " << d.size() << " " << sizeof(uint32_t)*6 << endl;
861            return;
862        }
863
864        const uint32_t *sdata = reinterpret_cast<const uint32_t*>(d.ptr());
865
866        fFtmCounterH->setValue(sdata[0]);
867        fFtmCounterS->setValue(sdata[1]);
868        fFtmCounterD->setValue(sdata[2]);
869        fFtmCounterF->setValue(sdata[3]);
870        fFtmCounterE->setValue(sdata[4]);
871        fFtmCounterR->setValue(sdata[5]);
872    }
873
874    void handleFtmDynamicData(const DimData &d)
875    {
876        if (d.size()==0)
877            return;
878
879        if (d.size()!=sizeof(FTM::DimDynamicData))
880        {
881            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimDynamicData) << endl;
882            return;
883        }
884
885        const FTM::DimDynamicData &sdata = *reinterpret_cast<const FTM::DimDynamicData*>(d.ptr());
886
887        fFtmTime->setText(QString::number(sdata.fTimeStamp));
888        fOnTime->setText(QString::number(sdata.fOnTimeCounter));
889
890        fFtmTemp0->setValue(sdata.fTempSensor[0]*0.1);
891        fFtmTemp1->setValue(sdata.fTempSensor[1]*0.1);
892        fFtmTemp2->setValue(sdata.fTempSensor[2]*0.1);
893        fFtmTemp3->setValue(sdata.fTempSensor[3]*0.1);
894
895
896        // ----------------------------------------------
897#ifdef HAS_ROOT
898        TCanvas *c = fFtmTempCanv->GetCanvas();
899
900        static int cntr = 0;
901        double_t tm = cntr++;//Time().RootTime();
902
903        TH1 *h = (TH1*)c->FindObject("MyFrame");
904        h->FindBin(tm);
905
906        fGraphFtmTemp[0].SetPoint(fGraphFtmTemp[0].GetN(), tm, sdata.fTempSensor[0]*0.1);
907        fGraphFtmTemp[1].SetPoint(fGraphFtmTemp[1].GetN(), tm, sdata.fTempSensor[1]*0.1);
908        fGraphFtmTemp[2].SetPoint(fGraphFtmTemp[2].GetN(), tm, sdata.fTempSensor[2]*0.1);
909        fGraphFtmTemp[3].SetPoint(fGraphFtmTemp[3].GetN(), tm, sdata.fTempSensor[3]*0.1);
910
911        c->Modified();
912        c->Update();
913
914        // ----------------------------------------------
915
916        valarray<double> dat(0., 1438);
917
918        for (int i=0; i<1438; i++)
919            dat[i] = sdata.fRatePatch[fPatch[i]];
920
921        c = fRatesCanv->GetCanvas();
922        Camera *cam = (Camera*)c->FindObject("Camera");
923
924        cam->SetData(dat);
925
926        c->Modified();
927        c->Update();
928#endif
929    }
930
931    FTM::DimStaticData fFtmStaticData;
932
933    void SetFtuLed(int idx, int counter)
934    {
935        if (counter==0)
936            counter = 3;
937
938        if (counter==-1)
939            counter = 0;
940
941        switch (counter)
942        {
943        case 0:
944            fFtuLED[idx]->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
945            break;
946
947        case 1:
948            fFtuLED[idx]->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
949            break;
950
951        case 2:
952            fFtuLED[idx]->setIcon(QIcon(":/Resources/icons/orange circle 1.png"));
953            break;
954
955        case 3:
956            fFtuLED[idx]->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
957            break;
958        }
959
960        fFtuStatus[idx] = counter;
961    }
962
963    void SetFtuStatusLed()
964    {
965        const int max = fFtuStatus.max();
966
967        switch (max)
968        {
969        case 0:
970            fStatusFTULed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
971            fStatusFTULabel->setText("All disabled");
972            fStatusFTULabel->setToolTip("All FTUs are disabled");
973            break;
974
975        case 1:
976            fStatusFTULed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
977            fStatusFTULabel->setToolTip("Communication with FTU is smooth.");
978            fStatusFTULabel->setText("Ok");
979            break;
980
981        case 2:
982            fStatusFTULed->setIcon(QIcon(":/Resources/icons/orange circle 1.png"));
983            fStatusFTULabel->setText("Warning");
984            fStatusFTULabel->setToolTip("At least one FTU didn't answer immediately");
985            break;
986
987        case 3:
988            fStatusFTULed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
989            fStatusFTULabel->setToolTip("At least one FTU didn't answer!");
990            fStatusFTULabel->setText("ERROR");
991            break;
992        }
993    }
994
995    void handleFtmStaticData(const DimData &d)
996    {
997        if (d.size()==0)
998            return;
999
1000        if (d.size()!=sizeof(FTM::DimStaticData))
1001        {
1002            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimStaticData) << endl;
1003            return;
1004        }
1005
1006        const FTM::DimStaticData &sdata = *reinterpret_cast<const FTM::DimStaticData*>(d.ptr());
1007
1008        fTriggerInterval->setValue(sdata.fTriggerInterval);
1009        fPhysicsCoincidence->setValue(sdata.fCoincidencePhysics);
1010        fCalibCoincidence->setValue(sdata.fCoincidenceCalib);
1011        fPhysicsWindow->setValue(sdata.fWindowPhysics);
1012        fCalibWindow->setValue(sdata.fWindowCalib);
1013
1014        fTriggerDelay->setValue(sdata.fDelayTrigger);
1015        fTimeMarkerDelay->setValue(sdata.fDelayTimeMarker);
1016        fDeadTime->setValue(sdata.fDeadTime);
1017
1018        fClockCondR0->setValue(sdata.fClockConditioner[0]);
1019        fClockCondR1->setValue(sdata.fClockConditioner[1]);
1020        fClockCondR8->setValue(sdata.fClockConditioner[2]);
1021        fClockCondR9->setValue(sdata.fClockConditioner[3]);
1022        fClockCondR11->setValue(sdata.fClockConditioner[4]);
1023        fClockCondR13->setValue(sdata.fClockConditioner[5]);
1024        fClockCondR14->setValue(sdata.fClockConditioner[6]);
1025        fClockCondR15->setValue(sdata.fClockConditioner[7]);
1026
1027        fTriggerSeqPed->setValue(sdata.fTriggerSeqPed);
1028        fTriggerSeqLPint->setValue(sdata.fTriggerSeqLPint);
1029        fTriggerSeqLPext->setValue(sdata.fTriggerSeqLPext);
1030
1031        fEnableTrigger->setChecked(sdata.HasTrigger());
1032        fEnableVeto->setChecked(sdata.HasVeto());
1033        fEnableExt1->setChecked(sdata.HasExt1());
1034        fEnableExt2->setChecked(sdata.HasExt2());
1035        fEnableTimeMarker->setChecked(sdata.HasTimeMarker());
1036
1037        for (int i=0; i<40; i++)
1038        {
1039            if (!sdata.IsActive(i))
1040                SetFtuLed(i, -1);
1041            else
1042            {
1043                if (fFtuStatus[i]==0)
1044                    SetFtuLed(i, 1);
1045            }
1046            fFtuLED[i]->setChecked(false);
1047        }
1048        SetFtuStatusLed();
1049
1050#ifdef HAS_ROOT
1051        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1052        for (int i=0; i<1438; i++)
1053            cam->SetEnable(i, sdata.IsEnabled(i));
1054#endif
1055
1056        const int patch1 = fThresholdIdx->value();
1057        fThresholdVal->setValue(sdata.fThreshold[patch1<0?0:patch1]);
1058
1059        fPrescalingVal->setValue(sdata.fPrescaling[0]);
1060
1061        fFtmStaticData = sdata;
1062    }
1063
1064    void handleFtmPassport(const DimData &d)
1065    {
1066        if (d.size()==0)
1067            return;
1068
1069        if (d.size()!=sizeof(FTM::DimPassport))
1070        {
1071            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimPassport) << endl;
1072            return;
1073        }
1074
1075        const FTM::DimPassport &sdata = *reinterpret_cast<const FTM::DimPassport*>(d.ptr());
1076
1077        stringstream str1, str2;
1078        str1 << hex << "0x" << setfill('0') << setw(16) << sdata.fBoardId;
1079        str2 << sdata.fFirmwareId;
1080
1081        fFtmBoardId->setText(str1.str().c_str());
1082        fFtmFirmwareId->setText(str2.str().c_str());
1083    }
1084
1085    void handleFtmFtuList(const DimData &d)
1086    {
1087        if (d.size()==0)
1088            return;
1089
1090        if (d.size()!=sizeof(FTM::DimFtuList))
1091        {
1092            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimFtuList) << endl;
1093            return;
1094        }
1095
1096        fPing->setChecked(false);
1097
1098        const FTM::DimFtuList &sdata = *reinterpret_cast<const FTM::DimFtuList*>(d.ptr());
1099
1100        stringstream str;
1101        str << "<table width='100%'>" << setfill('0');
1102        str << "<tr><th>Num</th><th></th><th>Addr</th><th></th><th>DNA</th></tr>";
1103        for (int i=0; i<40; i++)
1104        {
1105            str << "<tr>";
1106            str << "<td align='center'>"   << dec << i << hex << "</td>";
1107            str << "<td align='center'>:</td>";
1108            str << "<td align='center'>0x" << setw(2)  << (int)sdata.fAddr[i] << "</td>";
1109            str << "<td align='center'>:</td>";
1110            str << "<td align='center'>0x" << setw(16) << sdata.fDNA[i] << "</td>";
1111            str << "</tr>";
1112        }
1113        str << "</table>";
1114
1115        fFtuDNA->setText(str.str().c_str());
1116
1117        fFtuAnswersTotal->setValue(sdata.fNumBoards);
1118        fFtuAnswersCrate0->setValue(sdata.fNumBoardsCrate[0]);
1119        fFtuAnswersCrate1->setValue(sdata.fNumBoardsCrate[1]);
1120        fFtuAnswersCrate2->setValue(sdata.fNumBoardsCrate[2]);
1121        fFtuAnswersCrate3->setValue(sdata.fNumBoardsCrate[3]);
1122
1123        for (int i=0; i<40; i++)
1124            SetFtuLed(i, sdata.IsActive(i) ? sdata.fPing[i] : -1);
1125
1126        SetFtuStatusLed();
1127    }
1128
1129    void handleFtmError(const DimData &d)
1130    {
1131        if (d.size()==0)
1132            return;
1133
1134        const FTM::DimError &sdata = *reinterpret_cast<const FTM::DimError*>(d.ptr());
1135
1136        SetFtuLed(sdata.fError.fDestAddress , sdata.fError.fNumCalls);
1137        SetFtuStatusLed();
1138
1139        // Write to special window!
1140        Out() << "Error:" << endl;
1141        Out() << sdata.fError << endl;
1142    }
1143
1144    // ====================== MessageImp ====================================
1145
1146    bool fChatOnline;
1147
1148    void handleStateChanged(const Time &/*time*/, const std::string &server,
1149                            const State &s)
1150    {
1151        // FIXME: Prefix tooltip with time
1152        if (server=="FTM_CONTROL")
1153        {
1154            fStatusFTMLabel->setText(s.name.c_str());
1155            fStatusFTMLabel->setToolTip(s.comment.c_str());
1156
1157            bool enable = false;
1158
1159            if (s.index<FTM::kDisconnected) // No Dim connection
1160                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1161            if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
1162                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
1163            if (s.index==FTM::kConnected || s.index==FTM::kIdle) // Dim connection / FTM connected
1164            {
1165                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1166                enable = true;
1167            }
1168
1169            fTriggerWidget->setEnabled(enable);
1170            fFtuWidget->setEnabled(enable);
1171            fRatesWidget->setEnabled(enable);
1172
1173            if (!enable)
1174            {
1175                fStatusFTULed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1176                fStatusFTULabel->setText("Offline");
1177                fStatusFTULabel->setToolTip("FTM is not online.");
1178            }
1179    }
1180
1181        if (server=="FAD_CONTROL")
1182        {
1183            fStatusFADLabel->setText(s.name.c_str());
1184            fStatusFADLabel->setToolTip(s.comment.c_str());
1185
1186            if (s.index<FTM::kDisconnected) // No Dim connection
1187                fStatusFADLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1188            if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
1189                fStatusFADLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
1190            if (s.index==FTM::kConnected) // Dim connection / FTM connected
1191                fStatusFADLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1192        }
1193
1194        if (server=="DATA_LOGGER")
1195        {
1196            fStatusLoggerLabel->setText(s.name.c_str());
1197            fStatusLoggerLabel->setToolTip(s.comment.c_str());
1198
1199            bool enable = true;
1200
1201            if (s.index<=30)   // Ready/Waiting
1202                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
1203            if (s.index<-1)     // Offline
1204            {
1205                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1206                enable = false;
1207            }
1208            if (s.index>=0x100) // Error
1209                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
1210            if (s.index==40)   // Logging
1211                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1212
1213            fLoggerWidget->setEnabled(enable);
1214        }
1215
1216        if (server=="CHAT")
1217        {
1218            fStatusChatLabel->setText(s.name.c_str());
1219
1220            fChatOnline = s.index==0;
1221
1222            if (fChatOnline) // Dim connection / FTM connected
1223                fStatusChatLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1224            else
1225                fStatusChatLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1226
1227            fChatSend->setEnabled(fChatOnline);
1228            fChatMessage->setEnabled(fChatOnline);
1229        }
1230
1231        if (server=="SCHEDULER")
1232        {
1233            fStatusSchedulerLabel->setText(s.name.c_str());
1234
1235            if (s.index>=0) // Dim connection / FTM connected
1236                fStatusSchedulerLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1237            else
1238                fStatusSchedulerLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1239        }
1240    }
1241
1242    void handleStateOffline(const string &server)
1243    {
1244        handleStateChanged(Time(), server, State(-2, "Offline", "No connection via DIM."));
1245    }
1246
1247    void on_fTabWidget_currentChanged(int which)
1248    {
1249        if (fTabWidget->tabText(which)=="Chat")
1250            fTabWidget->setTabIcon(which, QIcon());
1251    }
1252
1253    void handleWrite(const Time &time, const string &text, int qos)
1254    {
1255        stringstream out;
1256
1257        if (text.substr(0, 6)=="CHAT: ")
1258        {
1259            out << "<font size='-1' color='navy'>[<B>";
1260            out << Time::fmt("%H:%M:%S") << time << "</B>]</FONT>  ";
1261            out << text.substr(6);
1262            fChatText->append(out.str().c_str());
1263
1264            if (fTabWidget->tabText(fTabWidget->currentIndex())=="Chat")
1265                return;
1266
1267            static int num = 0;
1268            if (num++<2)
1269                return;
1270
1271            for (int i=0; i<fTabWidget->count(); i++)
1272                if (fTabWidget->tabText(i)=="Chat")
1273                {
1274                    fTabWidget->setTabIcon(i, QIcon(":/Resources/icons/warning 3.png"));
1275                    break;
1276                }
1277
1278            return;
1279        }
1280
1281
1282        out << "<font style='font-family:monospace' color='";
1283
1284        switch (qos)
1285        {
1286        case kMessage: out << "black";   break;
1287        case kInfo:    out << "green";   break;
1288        case kWarn:    out << "#FF6600"; break;
1289        case kError:   out << "maroon";  break;
1290        case kFatal:   out << "maroon";  break;
1291        case kDebug:   out << "navy";    break;
1292        default:       out << "navy";    break;
1293        }
1294        out << "'>" << time.GetAsStr() << " - " << text << "</font>";
1295
1296        fLogText->append(out.str().c_str());
1297
1298        if (qos>=kWarn)
1299            fTextEdit->append(out.str().c_str());
1300    }
1301
1302    void IndicateStateChange(const Time &time, const std::string &server)
1303    {
1304        const State s = GetState(server, GetCurrentState(server));
1305
1306        QApplication::postEvent(this,
1307           new FunctionEvent(boost::bind(&FactGui::handleStateChanged, this, time, server, s)));
1308    }
1309
1310    int Write(const Time &time, const string &txt, int qos)
1311    {
1312        QApplication::postEvent(this,
1313           new FunctionEvent(boost::bind(&FactGui::handleWrite, this, time, txt, qos)));
1314
1315        return 0;
1316    }
1317
1318    // ====================== Dim infoHandler================================
1319
1320    void handleDimService(const string &txt)
1321    {
1322        fDimSvcText->append(txt.c_str());
1323    }
1324
1325    void infoHandlerService(DimInfo &info)
1326    {
1327        const string fmt = string(info.getFormat()).empty() ? "C" : info.getFormat();
1328
1329        stringstream dummy;
1330        const Converter conv(dummy, fmt, false);
1331
1332        const Time tm(info.getTimestamp(), info.getTimestampMillisecs()*1000);
1333
1334        stringstream out;
1335        out << "<font size'-1' color='navy'>[" << Time::fmt("%H:%M:%S.%f") << tm << "]</font>   <B>" << info.getName() << "</B> - ";
1336
1337        bool iserr = true;
1338        if (!conv)
1339        {
1340            out << "Compilation of format string '" << fmt << "' failed!";
1341        }
1342        else
1343        {
1344            try
1345            {
1346                const string dat = conv.GetString(info.getData(), info.getSize());
1347                out << dat;
1348                iserr = false;
1349            }
1350            catch (const runtime_error &e)
1351            {
1352                out << "Conversion to string failed!<pre>" << e.what() << "</pre>";
1353            }
1354        }
1355
1356        // srand(hash<string>()(string(info.getName())));
1357        // int bg = rand()&0xffffff;
1358
1359        int bg = hash<string>()(string(info.getName()));
1360
1361        // allow only light colors
1362        bg = ~(bg&0x1f1f1f)&0xffffff;
1363
1364        if (iserr)
1365            bg = 0xffffff;
1366
1367        stringstream bgcol;
1368        bgcol << hex << setfill('0') << setw(6) << bg;
1369
1370        const string col = iserr ? "red" : "black";
1371        const string str = "<table width='100%' bgcolor=#"+bgcol.str()+"><tr><td><font color='"+col+"'>"+out.str()+"</font></td></tr></table>";
1372
1373        QApplication::postEvent(this,
1374                                new FunctionEvent(boost::bind(&FactGui::handleDimService, this, str)));
1375    }
1376
1377    void PostInfoHandler(void (FactGui::*handler)(const DimData&))
1378    {
1379        QApplication::postEvent(this,
1380                                new FunctionEvent(boost::bind(handler, this, DimData(getInfo()))));
1381    }
1382
1383    void infoHandler()
1384    {
1385        // Initialize the time-stamp (what a weird workaround...)
1386        if (getInfo())
1387            getInfo()->getTimestamp();
1388
1389        if (getInfo()==&fDimDNS)
1390            return PostInfoHandler(&FactGui::handleDimDNS);
1391
1392        cout << "HandleDimInfo " << getInfo()->getName() << endl;
1393
1394        if (getInfo()==&fDimLoggerStats)
1395            return PostInfoHandler(&FactGui::handleLoggerStats);
1396
1397        if (getInfo()==&fDimLoggerFilenameNight)
1398            return PostInfoHandler(&FactGui::handleLoggerFilenameNight);
1399
1400        if (getInfo()==&fDimLoggerNumSubs)
1401            return PostInfoHandler(&FactGui::handleLoggerNumSubs);
1402
1403        if (getInfo()==&fDimLoggerFilenameRun)
1404            return PostInfoHandler(&FactGui::handleLoggerFilenameRun);
1405
1406        if (getInfo()==&fDimFtmTriggerCounter)
1407            return PostInfoHandler(&FactGui::handleFtmTriggerCounter);
1408
1409        if (getInfo()==&fDimFtmCounter)
1410            return PostInfoHandler(&FactGui::handleFtmCounter);
1411
1412        if (getInfo()==&fDimFtmDynamicData)
1413            return PostInfoHandler(&FactGui::handleFtmDynamicData);
1414
1415        if (getInfo()==&fDimFtmPassport)
1416            return PostInfoHandler(&FactGui::handleFtmPassport);
1417
1418        if (getInfo()==&fDimFtmFtuList)
1419            return PostInfoHandler(&FactGui::handleFtmFtuList);
1420
1421        if (getInfo()==&fDimFtmStaticData)
1422            return PostInfoHandler(&FactGui::handleFtmStaticData);
1423
1424        if (getInfo()==&fDimFtmError)
1425            return PostInfoHandler(&FactGui::handleFtmError);
1426
1427        for (map<string,DimInfo*>::iterator i=fServices.begin(); i!=fServices.end(); i++)
1428            if (i->second==getInfo())
1429            {
1430                infoHandlerService(*i->second);
1431                return;
1432            }
1433
1434        DimNetwork::infoHandler();
1435    }
1436
1437
1438    // ======================================================================
1439
1440    bool event(QEvent *evt)
1441    {
1442        if (dynamic_cast<FunctionEvent*>(evt))
1443            return static_cast<FunctionEvent*>(evt)->Exec();
1444
1445        if (dynamic_cast<CheckBoxEvent*>(evt))
1446        {
1447            const QStandardItem &item = static_cast<CheckBoxEvent*>(evt)->item;
1448            const QStandardItem *par  = item.parent();
1449            if (par)
1450            {
1451                const QString server  = par->text();
1452                const QString service = item.text();
1453
1454                const string s = (server+'/'+service).toStdString();
1455
1456                if (item.checkState()==Qt::Checked)
1457                    SubscribeService(s);
1458                else
1459                    UnsubscribeService(s);
1460            }
1461        }
1462
1463        return MainWindow::event(evt); // unrecognized
1464    }
1465
1466    void on_fDimCmdSend_clicked()
1467    {
1468        const QString server    = fDimCmdServers->currentIndex().data().toString();
1469        const QString command   = fDimCmdCommands->currentIndex().data().toString();
1470        const QString arguments = fDimCmdLineEdit->displayText();
1471
1472        // FIXME: Sending a command exactly when the info Handler changes
1473        //        the list it might lead to confusion.
1474        try
1475        {
1476            SendDimCommand(server.toStdString(), command.toStdString()+" "+arguments.toStdString());
1477            fTextEdit->append("<font color='green'>Command '"+server+'/'+command+"' successfully emitted.</font>");
1478            fDimCmdLineEdit->clear();
1479        }
1480        catch (const runtime_error &e)
1481        {
1482            stringstream txt;
1483            txt << e.what();
1484
1485            string buffer;
1486            while (getline(txt, buffer, '\n'))
1487                fTextEdit->append(("<font color='red'><pre>"+buffer+"</pre></font>").c_str());
1488        }
1489    }
1490    void ChoosePatch(Camera &cam, int idx)
1491    {
1492        cam.Reset();
1493
1494        fThresholdIdx->setValue(idx);
1495        fThresholdVal->setValue(fFtmStaticData.fThreshold[idx<0?0:idx]);
1496
1497        if (idx<0)
1498            return;
1499
1500        for (unsigned int i=0; i<fPatch.size(); i++)
1501            if (fPatch[i]==idx)
1502                cam.SetBold(i);
1503    }
1504
1505    void ChoosePixel(Camera &cam, int idx)
1506    {
1507        cam.SetWhite(idx);
1508        ChoosePatch(cam, fPatch[idx]);
1509    }
1510
1511#ifdef HAS_ROOT
1512    void slot_RootEventProcessed(TObject *obj, unsigned int evt, TCanvas *)
1513    {
1514        // kMousePressEvent       // TCanvas processed QEvent mousePressEvent
1515        // kMouseMoveEvent        // TCanvas processed QEvent mouseMoveEvent
1516        // kMouseReleaseEvent     // TCanvas processed QEvent mouseReleaseEvent
1517        // kMouseDoubleClickEvent // TCanvas processed QEvent mouseDoubleClickEvent
1518        // kKeyPressEvent         // TCanvas processed QEvent keyPressEvent
1519        // kEnterEvent            // TCanvas processed QEvent enterEvent
1520        // kLeaveEvent            // TCanvas processed QEvent leaveEvent
1521        if (dynamic_cast<TCanvas*>(obj))
1522            return;
1523
1524        TQtWidget *tipped = static_cast<TQtWidget*>(sender());
1525
1526        if (evt==11/*kMouseReleaseEvent*/)
1527        {
1528            if (dynamic_cast<Camera*>(obj))
1529            {
1530                const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1531                const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1532
1533                Camera *cam = static_cast<Camera*>(obj);
1534                const int idx = cam->GetIdx(xx, yy);
1535
1536                ChoosePixel(*cam, idx);
1537            }
1538            return;
1539        }
1540
1541        if (evt==61/*kMouseDoubleClickEvent*/)
1542        {
1543            if (dynamic_cast<Camera*>(obj))
1544            {
1545                const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1546                const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1547
1548                Camera *cam = static_cast<Camera*>(obj);
1549                const int idx = cam->GetIdx(xx, yy);
1550
1551                cam->Toggle(idx);
1552            }
1553            return;
1554        }
1555
1556        // Find the object which will get picked by the GetObjectInfo
1557        // due to buffer overflows in many root-versions
1558        // in TH1 and TProfile we have to work around and implement
1559        // our own GetObjectInfo which make everything a bit more
1560        // complicated.
1561#if ROOT_VERSION_CODE > ROOT_VERSION(5,22,00)
1562        const char *objectInfo =
1563            obj->GetObjectInfo(tipped->GetEventX(),tipped->GetEventY());
1564#else
1565        const char *objectInfo = dynamic_cast<TH1*>(obj) ?
1566            "" : obj->GetObjectInfo(tipped->GetEventX(),tipped->GetEventY());
1567#endif
1568
1569        QString tipText;
1570        tipText += obj->GetName();
1571        tipText += " [";
1572        tipText += obj->ClassName();
1573        tipText += "]: ";
1574        tipText += objectInfo;
1575
1576        if (dynamic_cast<Camera*>(obj))
1577        {
1578            const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1579            const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1580
1581            Camera *cam = static_cast<Camera*>(obj);
1582            int idx = fPatch[cam->GetIdx(xx, yy)];
1583
1584            tipText+="  Patch=";
1585            tipText+=QString::number(idx);
1586        }
1587
1588
1589        fStatusBar->showMessage(tipText, 3000);
1590
1591        gSystem->ProcessEvents();
1592        //QWhatsThis::display(tipText)
1593    }
1594
1595    void slot_RootUpdate()
1596    {
1597        gSystem->ProcessEvents();
1598        QTimer::singleShot(0, this, SLOT(slot_RootUpdate()));
1599    }
1600
1601    void on_fThresholdIdx_valueChanged(int idx)
1602    {
1603        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1604        ChoosePatch(*cam, idx);
1605    }
1606#endif
1607
1608    TGraph fGraphFtmTemp[4];
1609
1610    map<int, int> fPatch;
1611
1612public:
1613    FactGui() :
1614        fFtuStatus(40),
1615        fDimDNS("DIS_DNS/VERSION_NUMBER", 1, int(0), this),
1616
1617        fDimLoggerStats        ("DATA_LOGGER/STATS", (void*)NULL, 0, this),
1618        fDimLoggerFilenameNight("DATA_LOGGER/FILENAME_NIGHTLY", const_cast<char*>(""), 0, this),
1619        fDimLoggerFilenameRun  ("DATA_LOGGER/FILENAME_RUN",     const_cast<char*>(""), 0, this),
1620        fDimLoggerNumSubs      ("DATA_LOGGER/NUM_SUBS",         const_cast<char*>(""), 0, this),
1621
1622        fDimFtmPassport      ("FTM_CONTROL/PASSPORT",        (void*)NULL, 0, this),
1623        fDimFtmTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", (void*)NULL, 0, this),
1624        fDimFtmError         ("FTM_CONTROL/ERROR",           (void*)NULL, 0, this),
1625        fDimFtmFtuList       ("FTM_CONTROL/FTU_LIST",        (void*)NULL, 0, this),
1626        fDimFtmStaticData    ("FTM_CONTROL/STATIC_DATA",     (void*)NULL, 0, this),
1627        fDimFtmDynamicData   ("FTM_CONTROL/DYNAMIC_DATA",    (void*)NULL, 0, this),
1628        fDimFtmCounter       ("FTM_CONTROL/COUNTER",         (void*)NULL, 0, this)
1629    {
1630        fTriggerWidget->setEnabled(false);
1631        fFtuWidget->setEnabled(false);
1632        fRatesWidget->setEnabled(false);
1633        fLoggerWidget->setEnabled(false);
1634
1635        fChatSend->setEnabled(false);
1636        fChatMessage->setEnabled(false);
1637
1638        DimClient::sendCommand("CHAT/MSG", "GUI online.");
1639        // + MessageDimRX
1640
1641        // --------------------------------------------------------------------------
1642
1643        ifstream fin("fact-trigger-all.txt");
1644
1645        int l = 0;
1646
1647        string buf;
1648        while (getline(fin, buf, '\n'))
1649        {
1650            buf = Tools::Trim(buf);
1651            if (buf[0]=='#')
1652                continue;
1653
1654            stringstream str(buf);
1655            for (int i=0; i<9; i++)
1656            {
1657                int n;
1658                str >> n;
1659
1660                fPatch[n] = l;
1661            }
1662            l++;
1663        }
1664
1665        // --------------------------------------------------------------------------
1666#ifdef HAS_ROOT
1667        TCanvas *c = fFtmTempCanv->GetCanvas();
1668        c->SetBit(TCanvas::kNoContextMenu);
1669        c->SetBorderMode(0);
1670        c->SetFrameBorderMode(0);
1671        c->SetFillColor(kWhite);
1672        c->SetRightMargin(0.03);
1673        c->SetTopMargin(0.03);
1674        c->cd();
1675
1676        TH1F h("MyFrame", "", 1000, 0, 1);//Time().RootTime()-1./24/60/60, Time().RootTime());
1677        h.SetDirectory(0);
1678        h.SetBit(TH1::kCanRebin);
1679        h.SetStats(kFALSE);
1680        h.SetMinimum(-20);
1681        h.SetMaximum(100);
1682        h.SetXTitle("Time");
1683        h.SetYTitle("Temperature / °C");
1684        h.GetXaxis()->CenterTitle();
1685        h.GetYaxis()->CenterTitle();
1686//        h.GetXaxis()->SetTitleSize(1.2);
1687//        h.GetYaxis()->SetTitleSize(1.2);
1688        h.DrawCopy();
1689
1690        fGraphFtmTemp[0].SetMarkerStyle(kFullDotSmall);
1691        fGraphFtmTemp[1].SetMarkerStyle(kFullDotSmall);
1692        fGraphFtmTemp[2].SetMarkerStyle(kFullDotSmall);
1693        fGraphFtmTemp[3].SetMarkerStyle(kFullDotSmall);
1694
1695        fGraphFtmTemp[1].SetLineColor(kBlue);
1696        fGraphFtmTemp[2].SetLineColor(kRed);
1697        fGraphFtmTemp[3].SetLineColor(kGreen);
1698
1699        fGraphFtmTemp[1].SetMarkerColor(kBlue);
1700        fGraphFtmTemp[2].SetMarkerColor(kRed);
1701        fGraphFtmTemp[3].SetMarkerColor(kGreen);
1702
1703        fGraphFtmTemp[0].Draw("LP");
1704        fGraphFtmTemp[1].Draw("LP");
1705        fGraphFtmTemp[2].Draw("LP");
1706        fGraphFtmTemp[3].Draw("LP");
1707
1708        // --------------------------------------------------------------------------
1709
1710        c = fRatesCanv->GetCanvas();
1711        c->SetBit(TCanvas::kNoContextMenu);
1712        c->SetBorderMode(0);
1713        c->SetFrameBorderMode(0);
1714        c->SetFillColor(kWhite);
1715        c->cd();
1716
1717        Camera *cam = new Camera;
1718        cam->SetBit(kCanDelete);
1719        cam->Draw();
1720
1721        ChoosePixel(*cam, 1);
1722
1723//        QTimer::singleShot(0, this, SLOT(slot_RootUpdate()));
1724
1725        //widget->setMouseTracking(true);
1726        //widget->EnableSignalEvents(kMouseMoveEvent);
1727
1728        fFtmTempCanv->setMouseTracking(true);
1729        fFtmTempCanv->EnableSignalEvents(kMouseMoveEvent);
1730
1731        fRatesCanv->setMouseTracking(true);
1732        fRatesCanv->EnableSignalEvents(kMouseMoveEvent|kMouseReleaseEvent|kMouseDoubleClickEvent);
1733
1734        connect(fRatesCanv,   SIGNAL(     RootEventProcessed(TObject*, unsigned int, TCanvas*)),
1735                this,         SLOT  (slot_RootEventProcessed(TObject*, unsigned int, TCanvas*)));
1736        connect(fFtmTempCanv, SIGNAL(     RootEventProcessed(TObject*, unsigned int, TCanvas*)),
1737                this,         SLOT  (slot_RootEventProcessed(TObject*, unsigned int, TCanvas*)));
1738#endif
1739    }
1740
1741    ~FactGui()
1742    {
1743        UnsubscribeAllServers();
1744    }
1745};
1746
1747#endif
Note: See TracBrowser for help on using the repository browser.