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

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