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

Last change on this file since 10547 was 10547, checked in by tbretz, 9 years ago
Implemented a status LED for the FTUs
File size: 52.6 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();
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
198            const int col = (fData[cnt]-min)/scale*(fPalette.size()-1);
199
200            if (fEnable[cnt])
201                fill.SetFillColor(gStyle->GetColorPalette(col));
202            else
203                fill.SetFillColor(kWhite);
204
205            fill.Modify();
206
207            Paint(*p);
208        }
209
210        line.SetLineWidth(2);
211        line.Modify();
212
213        cnt = 0;
214        for (Positions::iterator p=fGeom.begin(); p!=fGeom.end(); p++, cnt++)
215        {
216            if (!fBold[cnt])
217                continue;
218
219            const int col = (fData[cnt]-min)/scale*(fPalette.size()-1);
220
221            if (fEnable[cnt])
222                fill.SetFillColor(gStyle->GetColorPalette(col));
223            else
224                fill.SetFillColor(kWhite);
225            fill.Modify();
226
227            Paint(*p);
228        }
229
230        TMarker m(0,0,kStar);
231        m.DrawMarker(0, 0);
232
233        if (fWhite<0)
234            return;
235
236        const Position &p = fGeom[fWhite];
237
238        line.SetLineColor(kWhite);
239        line.Modify();
240
241        const int col = (fData[fWhite]-min)/scale*(fPalette.size()-1);
242
243        if (fEnable[fWhite])
244            fill.SetFillColor(gStyle->GetColorPalette(col));
245        else
246            fill.SetFillColor(kWhite);
247        fill.Modify();
248
249        Paint(p);
250    }
251
252    int GetIdx(float px, float py) const
253    {
254        static const double sqrt3 = sqrt(3);
255
256        int idx = 0;
257        for (Positions::const_iterator p=fGeom.begin(); p!=fGeom.end(); p++, idx++)
258        {
259            const Double_t dy = py - p->second;
260            if (fabs(dy)>0.5)
261                continue;
262
263            const Double_t dx = px - p->first;
264
265            if  (TMath::Abs(dy + dx*sqrt3) > 1)
266                continue;
267
268            if  (TMath::Abs(dy - dx*sqrt3) > 1)
269                continue;
270
271            return idx;
272        }
273        return -1;
274    }
275
276    char* GetObjectInfo(Int_t px, Int_t py) const
277    {
278        static stringstream stream;
279        static string       str;
280
281        const float x = gPad->PadtoX(gPad->AbsPixeltoX(px));
282        const float y = gPad->PadtoY(gPad->AbsPixeltoY(py));
283
284        const int idx = GetIdx(x, y);
285
286        stream.seekp(0);
287        if (idx>=0)
288            stream << "Pixel=" << idx << "   Data=" << fData[idx] << '\0';
289
290        str = stream.str();
291        return const_cast<char*>(str.c_str());
292    }
293
294    Int_t DistancetoPrimitive(Int_t px, Int_t py)
295    {
296        const float x = gPad->PadtoX(gPad->AbsPixeltoX(px));
297        const float y = gPad->PadtoY(gPad->AbsPixeltoY(py));
298
299        return GetIdx(x, y)>=0 ? 0 : 99999;
300    }
301
302    void SetData(const valarray<double> &data)
303    {
304        fData = data;
305    }
306};
307
308// #########################################################################
309
310
311class FactGui : public MainWindow, public DimNetwork
312{
313private:
314    class FunctionEvent : public QEvent
315    {
316    public:
317        boost::function<void(const QEvent &)> fFunction;
318
319        FunctionEvent(const boost::function<void(const QEvent &)> &f)
320            : QEvent((QEvent::Type)QEvent::registerEventType()),
321            fFunction(f) { }
322
323        bool Exec() { fFunction(*this); return true; }
324    };
325
326    vector<bool> fFtuDisabled;
327
328    DimStampedInfo fDimDNS;
329
330    DimStampedInfo fDimLoggerStats;
331    DimStampedInfo fDimLoggerFilenameNight;
332    DimStampedInfo fDimLoggerFilenameRun;
333    DimStampedInfo fDimLoggerNumSubs;
334
335    DimStampedInfo fDimFtmPassport;
336    DimStampedInfo fDimFtmTriggerCounter;
337    DimStampedInfo fDimFtmError;
338    DimStampedInfo fDimFtmFtuList;
339    DimStampedInfo fDimFtmStaticData;
340    DimStampedInfo fDimFtmDynamicData;
341
342    vector<DimInfo*> fDim;
343    map<string, DimInfo*> fServices;
344
345    // ===================== Services and Commands ==========================
346
347    QStandardItem *AddServiceItem(const std::string &server, const std::string &service, bool iscmd)
348    {
349        QListView *servers     = iscmd ? fDimCmdServers     : fDimSvcServers;
350        QListView *services    = iscmd ? fDimCmdCommands    : fDimSvcServices;
351        QListView *description = iscmd ? fDimCmdDescription : fDimSvcDescription;
352
353        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
354        if (!m)
355        {
356            m = new QStandardItemModel(this);
357            servers->setModel(m);
358            services->setModel(m);
359            description->setModel(m);
360        }
361
362        QList<QStandardItem*> l = m->findItems(server.c_str());
363
364        if (l.size()>1)
365        {
366            cout << "hae" << endl;
367            return 0;
368        }
369
370        QStandardItem *col = l.size()==0 ? NULL : l[0];
371
372        if (!col)
373        {
374            col = new QStandardItem(server.c_str());
375            m->appendRow(col);
376
377            if (!services->rootIndex().isValid())
378            {
379                services->setRootIndex(col->index());
380                servers->setCurrentIndex(col->index());
381            }
382        }
383
384        QStandardItem *item = 0;
385        for (int i=0; i<col->rowCount(); i++)
386        {
387            QStandardItem *coli = col->child(i);
388            if (coli->text().toStdString()==service)
389                return coli;
390        }
391
392        item = new QStandardItem(service.c_str());
393        col->appendRow(item);
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            time(inf->getTimestamp(), inf->getTimestampMillisecs()*1000),
627            qos(inf->getQuality()),
628            name(inf->getName()),
629            format(inf->getFormat()),
630            data(inf->getString(), inf->getString()+inf->getSize()),
631            info(inf)
632        {
633        }
634
635        template<typename T>
636                T get() const { return *reinterpret_cast<const T*>(data.data()); }
637
638            vector<char> vec(int b) const { return vector<char>(data.begin()+b, data.end()); }
639            string str(unsigned int b) const { return b>=data.size()?string():string(data.data()+b, data.size()-b); }
640            const char *c_str() const { return (char*)data.data(); }
641
642            vector<boost::any> any() const
643            {
644                const Converter conv(format);
645                conv.Print();
646                return conv.GetAny(data.data(), data.size());
647            }
648            int size() const { return data.size(); }
649            const void *ptr() const { return data.data(); }
650    };
651
652    // ======================= DNS ==========================================
653
654    void handleDimDNS(int version)
655    {
656        ostringstream str;
657        str << "V" << version/100 << 'r' << version%100;
658
659        if (version==0)
660            fStatusDNSLed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
661        else
662            fStatusDNSLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
663
664        fStatusDNSLabel->setText(version==0?"Offline":str.str().c_str());
665        fStatusDNSLabel->setToolTip(version==0?"No connection to DIM DNS.":"Connection to DIM DNS established.");
666    }
667
668
669    // ======================= Logger =======================================
670
671    void handleLoggerStats(const DimData &d)
672    {
673        const bool connected = d.size()!=0;
674
675        fLoggerET->setEnabled(connected);
676        fLoggerRate->setEnabled(connected);
677        fLoggerWritten->setEnabled(connected);
678        fLoggerFreeSpace->setEnabled(connected);
679        fLoggerSpaceLeft->setEnabled(connected);
680
681        if (!connected)
682            return;
683
684        const uint64_t *vals = reinterpret_cast<const uint64_t*>(d.ptr());
685
686        const size_t written = vals[0];
687        const size_t space   = vals[1];
688        const size_t rate    = vals[2];
689
690        cout << written << " " << space << " " << rate << endl;
691
692        fLoggerFreeSpace->setSuffix(" MB");
693        fLoggerFreeSpace->setDecimals(0);
694        fLoggerFreeSpace->setValue(space*1e-6);
695
696        if (space>   1000000)  // > 1GB
697        {
698            fLoggerFreeSpace->setSuffix(" GB");
699            fLoggerFreeSpace->setDecimals(2);
700            fLoggerFreeSpace->setValue(space*1e-9);
701        }
702        if (space>=  3000000)  // >= 3GB
703        {
704            fLoggerFreeSpace->setSuffix(" GB");
705            fLoggerFreeSpace->setDecimals(1);
706            fLoggerFreeSpace->setValue(space*1e-9);
707        }
708        if (space>=100000000)  // >= 100GB
709        {
710            fLoggerFreeSpace->setSuffix(" GB");
711            fLoggerFreeSpace->setDecimals(0);
712            fLoggerFreeSpace->setValue(space*1e-9);
713        }
714
715        fLoggerET->setTime(QTime().addSecs(rate>0?space/rate:0));
716        fLoggerRate->setValue(rate*1e-3); // kB/s
717        fLoggerWritten->setValue(written*1e-6);
718
719        fLoggerRate->setSuffix(" kB/s");
720        fLoggerRate->setDecimals(2);
721        fLoggerRate->setValue(rate*1e-3);
722        if (rate>   2000)  // > 2kB/s
723        {
724            fLoggerRate->setSuffix(" kB/s");
725            fLoggerRate->setDecimals(1);
726            fLoggerRate->setValue(rate*1e-3);
727        }
728        if (rate>=100000)  // >100kB/s
729        {
730            fLoggerRate->setSuffix(" kB/s");
731            fLoggerRate->setDecimals(0);
732            fLoggerRate->setValue(rate*1e-3);
733        }
734        if (rate>=1000000)  // >100kB/s
735        {
736            fLoggerRate->setSuffix(" MB/s");
737            fLoggerRate->setDecimals(2);
738            fLoggerRate->setValue(rate*1e-6);
739        }
740        if (rate>=10000000)  // >1MB/s
741        {
742            fLoggerRate->setSuffix(" MB/s");
743            fLoggerRate->setDecimals(1);
744            fLoggerRate->setValue(rate*1e-6);
745        }
746        if (rate>=100000000)  // >10MB/s
747        {
748            fLoggerRate->setSuffix(" MB/s");
749            fLoggerRate->setDecimals(0);
750            fLoggerRate->setValue(rate*1e-6);
751        }
752
753        if (space/10000000>static_cast<size_t>(fLoggerSpaceLeft->maximum()))
754            fLoggerSpaceLeft->setValue(fLoggerSpaceLeft->maximum());  // MB
755        else
756            fLoggerSpaceLeft->setValue(space/10000000);  // MB
757    }
758
759    void handleLoggerFilenameNight(const DimData &d)
760    {
761        const bool connected = d.size()!=0;
762
763        fLoggerFilenameNight->setEnabled(connected);
764        if (connected)
765            fLoggerFilenameNight->setText(d.c_str()+4);
766
767        const uint32_t files = d.get<uint32_t>();
768
769        if (files&1)
770            fLoggerLedLog->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
771        else
772            fLoggerLedLog->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
773
774        if (files&2)
775            fLoggerLedRep->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
776        else
777            fLoggerLedRep->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
778
779        if (files&4)
780            fLoggerLedFits->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
781        else
782            fLoggerLedFits->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
783    }
784
785    void handleLoggerFilenameRun(const DimData &d)
786    {
787        const bool connected = d.size()!=0;
788
789        fLoggerFilenameRun->setEnabled(connected);
790        if (connected)
791            fLoggerFilenameRun->setText(d.c_str()+4);
792
793        const uint32_t files = d.get<uint32_t>();
794
795        if (files&1)
796            fLoggerLedLog->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
797        else
798            fLoggerLedLog->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
799
800        if (files&2)
801            fLoggerLedRep->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
802        else
803            fLoggerLedRep->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
804
805        if (files&4)
806            fLoggerLedFits->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
807        else
808            fLoggerLedFits->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
809    }
810
811    void handleLoggerNumSubs(const DimData &d)
812    {
813        const bool connected = d.size()!=0;
814
815        fLoggerSubscriptions->setEnabled(connected);
816        fLoggerOpenFiles->setEnabled(connected);
817        if (!connected)
818            return;
819
820        const uint32_t *vals = reinterpret_cast<const uint32_t*>(d.ptr());
821
822        fLoggerSubscriptions->setValue(vals[0]);
823        fLoggerOpenFiles->setValue(vals[1]);
824    }
825
826    // ===================== FTM ============================================
827
828    void handleFtmTriggerCounter(const DimData &d)
829    {
830        if (d.size()==0)
831            return;
832
833        if (d.size()!=sizeof(FTM::DimTriggerCounter))
834        {
835            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimTriggerCounter) << endl;
836            return;
837        }
838
839        const FTM::DimTriggerCounter &sdata = *reinterpret_cast<const FTM::DimTriggerCounter*>(d.ptr());
840
841        fFtmTime->setText(QString::number(sdata.fTimeStamp));
842        fTriggerCounter->setText(QString::number(sdata.fTriggerCounter));
843    }
844
845    void handleFtmDynamicData(const DimData &d)
846    {
847        if (d.size()==0)
848            return;
849
850        if (d.size()!=sizeof(FTM::DimDynamicData))
851        {
852            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimDynamicData) << endl;
853            return;
854        }
855
856        const FTM::DimDynamicData &sdata = *reinterpret_cast<const FTM::DimDynamicData*>(d.ptr());
857
858        fFtmTime->setText(QString::number(sdata.fTimeStamp));
859        fOnTime->setText(QString::number(sdata.fOnTimeCounter));
860
861        fFtmTemp0->setValue(sdata.fTempSensor[0]*0.1);
862        fFtmTemp1->setValue(sdata.fTempSensor[1]*0.1);
863        fFtmTemp2->setValue(sdata.fTempSensor[2]*0.1);
864        fFtmTemp3->setValue(sdata.fTempSensor[3]*0.1);
865
866
867        // ----------------------------------------------
868#ifdef HAS_ROOT
869        TCanvas *c = fFtmTempCanv->GetCanvas();
870
871        static int cntr = 0;
872        double_t tm = cntr++;//Time().RootTime();
873
874        TH1 *h = (TH1*)c->FindObject("MyFrame");
875        h->FindBin(tm);
876
877        fGraphFtmTemp[0].SetPoint(fGraphFtmTemp[0].GetN(), tm, sdata.fTempSensor[0]*0.1);
878        fGraphFtmTemp[1].SetPoint(fGraphFtmTemp[1].GetN(), tm, sdata.fTempSensor[1]*0.1);
879        fGraphFtmTemp[2].SetPoint(fGraphFtmTemp[2].GetN(), tm, sdata.fTempSensor[2]*0.1);
880        fGraphFtmTemp[3].SetPoint(fGraphFtmTemp[3].GetN(), tm, sdata.fTempSensor[3]*0.1);
881
882        c->Modified();
883        c->Update();
884
885        // ----------------------------------------------
886
887        valarray<double> dat(0., 1438);
888
889        for (int i=0; i<1438; i++)
890            dat[i] = sdata.fRatePatch[fPatch[i]];
891
892        c = fRatesCanv->GetCanvas();
893        Camera *cam = (Camera*)c->FindObject("Camera");
894
895        cam->SetData(dat);
896
897        c->Modified();
898        c->Update();
899#endif
900    }
901
902    FTM::DimStaticData fFtmStaticData;
903
904    int fFtuStatus;
905
906
907    void SetFtuLed(int idx, int counter)
908    {
909        if (counter<0)
910            fFtuLED[idx]->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
911
912        if (counter==0)
913        {
914            fFtuLED[idx]->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
915            fStatusFTULed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
916            fStatusFTULabel->setToolTip("At least one FTU didn't answer!");
917            fStatusFTULabel->setText("ERROR");
918            fFtuStatus = 0;
919        }
920        if (counter==1)
921        {
922            fFtuLED[idx]->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
923            if (fFtuStatus<0)
924            {
925                fStatusFTULed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
926                fStatusFTULabel->setToolTip("Communication with FTU is smooth.");
927                fStatusFTULabel->setText("Ok");
928                fFtuStatus = 1;
929            }
930        }
931
932        if (counter>1)
933        {
934            fFtuLED[idx]->setIcon(QIcon(":/Resources/icons/orange circle 1.png"));
935            if (fFtuStatus!=0)
936            {
937                fStatusFTULed->setIcon(QIcon(":/Resources/icons/orange circle 1.png"));
938                fStatusFTULabel->setText("Warning");
939                fStatusFTULabel->setToolTip("At least one FTU didn't answer immediately");
940                fFtuStatus = 2;
941            }
942        }
943
944    }
945
946
947    void handleFtmStaticData(const DimData &d)
948    {
949        if (d.size()==0)
950            return;
951
952        if (d.size()!=sizeof(FTM::DimStaticData))
953        {
954            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimStaticData) << endl;
955            return;
956        }
957
958        const FTM::DimStaticData &sdata = *reinterpret_cast<const FTM::DimStaticData*>(d.ptr());
959
960        fTriggerInterval->setValue(sdata.fTriggerInterval);
961        fPhysicsCoincidence->setValue(sdata.fCoincidencePhysics);
962        fCalibCoincidence->setValue(sdata.fCoincidenceCalib);
963        fPhysicsWindow->setValue(sdata.fWindowPhysics);
964        fCalibWindow->setValue(sdata.fWindowCalib);
965
966        fTriggerDelay->setValue(sdata.fDelayTrigger);
967        fTimeMarkerDelay->setValue(sdata.fDelayTimeMarker);
968        fDeadTime->setValue(sdata.fDeadTime);
969
970        fClockCondR0->setValue(sdata.fClockConditioner[0]);
971        fClockCondR1->setValue(sdata.fClockConditioner[1]);
972        fClockCondR8->setValue(sdata.fClockConditioner[2]);
973        fClockCondR9->setValue(sdata.fClockConditioner[3]);
974        fClockCondR11->setValue(sdata.fClockConditioner[4]);
975        fClockCondR13->setValue(sdata.fClockConditioner[5]);
976        fClockCondR14->setValue(sdata.fClockConditioner[6]);
977        fClockCondR15->setValue(sdata.fClockConditioner[7]);
978
979        fTriggerSeqPed->setValue(sdata.fTriggerSeqPed);
980        fTriggerSeqLP1->setValue(sdata.fTriggerSeqLP1);
981        fTriggerSeqLP2->setValue(sdata.fTriggerSeqLP2);
982
983        fEnableTrigger->setChecked(sdata.HasTrigger());
984        fEnableLP1->setChecked(sdata.HasLP1());
985        fEnableLP2->setChecked(sdata.HasLP2());
986        fEnableVeto->setChecked(sdata.HasVeto());
987        fEnablePedestal->setChecked(sdata.HasPedestal());
988        fEnableExt1->setChecked(sdata.HasExt1());
989        fEnableExt2->setChecked(sdata.HasExt2());
990        fEnableTimeMarker->setChecked(sdata.HasTimeMarker());
991
992        bool active = false;
993        for (int i=0; i<40; i++)
994        {
995            if (!sdata.IsActive(i))
996            {
997                SetFtuLed(i, -1);
998                fFtuDisabled[i] = true;
999            }
1000            else
1001            {
1002                active = true;
1003                if (fFtuDisabled[i])
1004                {
1005                    SetFtuLed(i, 1);
1006                    fFtuDisabled[i] = false;
1007                }
1008            }
1009        }
1010
1011        if (!active)
1012            DisableStatusLedFtu();
1013
1014#ifdef HAS_ROOT
1015        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1016        for (int i=0; i<1438; i++)
1017            cam->SetEnable(i, sdata.IsEnabled(i));
1018#endif
1019
1020        const int patch1 = fThresholdIdx->value();
1021        fThresholdVal->setValue(sdata.fThreshold[patch1<0?0:patch1]);
1022
1023        fPrescalingVal->setValue(sdata.fPrescaling[0]);
1024
1025        fFtmStaticData = sdata;
1026    }
1027
1028    void handleFtmPassport(const DimData &d)
1029    {
1030        if (d.size()==0)
1031            return;
1032
1033        if (d.size()!=sizeof(FTM::DimPassport))
1034        {
1035            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimPassport) << endl;
1036            return;
1037        }
1038
1039        const FTM::DimPassport &sdata = *reinterpret_cast<const FTM::DimPassport*>(d.ptr());
1040
1041        stringstream str1, str2;
1042        str1 << hex << "0x" << setfill('0') << setw(16) << sdata.fBoardId;
1043        str2 << sdata.fFirmwareId;
1044
1045        fFtmBoardId->setText(str1.str().c_str());
1046        fFtmFirmwareId->setText(str2.str().c_str());
1047    }
1048
1049    void DisableStatusLedFtu()
1050    {
1051        fFtuStatus = -1;
1052        fStatusFTULed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1053        fStatusFTULabel->setText("All disabled");
1054        fStatusFTULabel->setToolTip("All FTUs are disabled");
1055    }
1056
1057    void handleFtmFtuList(const DimData &d)
1058    {
1059        if (d.size()==0)
1060            return;
1061
1062        if (d.size()!=sizeof(FTM::DimFtuList))
1063        {
1064            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimFtuList) << endl;
1065            return;
1066        }
1067
1068        fPing->setChecked(false);
1069
1070        const FTM::DimFtuList &sdata = *reinterpret_cast<const FTM::DimFtuList*>(d.ptr());
1071
1072        stringstream str;
1073        str << "<table width='100%'>" << setfill('0');
1074        str << "<tr><th>Num</th><th></th><th>Addr</th><th></th><th>DNA</th></tr>";
1075        for (int i=0; i<40; i++)
1076        {
1077            str << "<tr>";
1078            str << "<td align='center'>"   << dec << i << hex << "</td>";
1079            str << "<td align='center'>:</td>";
1080            str << "<td align='center'>0x" << setw(2)  << (int)sdata.fAddr[i] << "</td>";
1081            str << "<td align='center'>:</td>";
1082            str << "<td align='center'>0x" << setw(16) << sdata.fDNA[i] << "</td>";
1083            str << "</tr>";
1084        }
1085        str << "</table>";
1086
1087        fFtuDNA->setText(str.str().c_str());
1088
1089        fFtuAnswersTotal->setValue(sdata.fNumBoards);
1090        fFtuAnswersCrate0->setValue(sdata.fNumBoardsCrate[0]);
1091        fFtuAnswersCrate1->setValue(sdata.fNumBoardsCrate[1]);
1092        fFtuAnswersCrate2->setValue(sdata.fNumBoardsCrate[2]);
1093        fFtuAnswersCrate3->setValue(sdata.fNumBoardsCrate[3]);
1094
1095        DisableStatusLedFtu();
1096
1097        for (int i=0; i<40; i++)
1098        {
1099            const bool active = sdata.IsActive(i);
1100
1101            SetFtuLed(i, active ? sdata.fPing[i] : -1);
1102            fFtuDisabled[i] = !active;
1103        }
1104    }
1105
1106    void handleFtmError(const DimData &d)
1107    {
1108        if (d.size()==0)
1109            return;
1110
1111        const FTM::DimError &sdata = *reinterpret_cast<const FTM::DimError*>(d.ptr());
1112
1113        SetFtuLed(sdata.fError.fDestAddress , sdata.fError.fNumCalls);
1114
1115        // Write to special window!
1116        Out() << "Error:" << endl;
1117        Out() << sdata.fError << endl;
1118    }
1119
1120    // ====================== MessageImp ====================================
1121
1122    bool fChatOnline;
1123
1124    void handleStateChanged(const Time &/*time*/, const std::string &server,
1125                            const State &s)
1126    {
1127        // FIXME: Prefix tooltip with time
1128        if (server=="FTM_CONTROL")
1129        {
1130            fStatusFTMLabel->setText(s.name.c_str());
1131            fStatusFTMLabel->setToolTip(s.comment.c_str());
1132
1133            bool enable = false;
1134
1135            if (s.index<FTM::kDisconnected) // No Dim connection
1136                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1137            if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
1138                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
1139            if (s.index==FTM::kConnected || s.index==FTM::kIdle) // Dim connection / FTM connected
1140            {
1141                fStatusFTMLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1142                enable = true;
1143            }
1144
1145            fTriggerWidget->setEnabled(enable);
1146            fFtuWidget->setEnabled(enable);
1147            fRatesWidget->setEnabled(enable);
1148
1149            if (!enable)
1150            {
1151                fFtuStatus = -1;
1152                fStatusFTULed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1153                fStatusFTULabel->setText("Offline");
1154                fStatusFTULabel->setToolTip("FTM is not online.");
1155            }
1156    }
1157
1158        if (server=="FAD_CONTROL")
1159        {
1160            fStatusFADLabel->setText(s.name.c_str());
1161            fStatusFADLabel->setToolTip(s.comment.c_str());
1162
1163            if (s.index<FTM::kDisconnected) // No Dim connection
1164                fStatusFADLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1165            if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
1166                fStatusFADLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
1167            if (s.index==FTM::kConnected) // Dim connection / FTM connected
1168                fStatusFADLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1169        }
1170
1171        if (server=="DATA_LOGGER")
1172        {
1173            fStatusLoggerLabel->setText(s.name.c_str());
1174            fStatusLoggerLabel->setToolTip(s.comment.c_str());
1175
1176            bool enable = true;
1177
1178            if (s.index<=30)   // Ready/Waiting
1179                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
1180            if (s.index<-1)     // Offline
1181            {
1182                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1183                enable = false;
1184            }
1185            if (s.index>=0x100) // Error
1186                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
1187            if (s.index==40)   // Logging
1188                fStatusLoggerLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1189
1190            fLoggerWidget->setEnabled(enable);
1191        }
1192
1193        if (server=="CHAT")
1194        {
1195            fStatusChatLabel->setText(s.name.c_str());
1196
1197            fChatOnline = s.index==0;
1198
1199            if (fChatOnline) // Dim connection / FTM connected
1200                fStatusChatLed->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
1201            else
1202                fStatusChatLed->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
1203
1204            fChatSend->setEnabled(fChatOnline);
1205            fChatMessage->setEnabled(fChatOnline);
1206        }
1207    }
1208
1209    void handleStateOffline(const string &server)
1210    {
1211        handleStateChanged(Time(), server, State(-2, "Offline", "No connection via DIM."));
1212    }
1213
1214    void on_fTabWidget_currentChanged(int which)
1215    {
1216        if (fTabWidget->tabText(which)=="Chat")
1217            fTabWidget->setTabIcon(which, QIcon());
1218    }
1219
1220    void handleWrite(const Time &time, const string &text, int qos)
1221    {
1222        stringstream out;
1223
1224        if (text.substr(0, 6)=="CHAT: ")
1225        {
1226            out << "<font size='-1' color='navy'>[<B>";
1227            out << Time::fmt("%H:%M:%S") << time << "</B>]</FONT>  ";
1228            out << text.substr(6);
1229            fChatText->append(out.str().c_str());
1230
1231            if (fTabWidget->tabText(fTabWidget->currentIndex())=="Chat")
1232                return;
1233
1234            static int num = 0;
1235            if (num++<2)
1236                return;
1237
1238            for (int i=0; i<fTabWidget->count(); i++)
1239                if (fTabWidget->tabText(i)=="Chat")
1240                {
1241                    fTabWidget->setTabIcon(i, QIcon(":/Resources/icons/warning 3.png"));
1242                    break;
1243                }
1244
1245            return;
1246        }
1247
1248
1249        out << "<font color='";
1250
1251        switch (qos)
1252        {
1253        case kMessage: out << "black";   break;
1254        case kInfo:    out << "green";   break;
1255        case kWarn:    out << "#FF6600"; break;
1256        case kError:   out << "maroon";  break;
1257        case kFatal:   out << "maroon";  break;
1258        case kDebug:   out << "navy";    break;
1259        default:       out << "navy";    break;
1260        }
1261        out << "'>" << time.GetAsStr() << " - " << text << "</font>";
1262
1263        fLogText->append(out.str().c_str());
1264
1265        if (qos>=kWarn)
1266            fTextEdit->append(out.str().c_str());
1267    }
1268
1269    void IndicateStateChange(const Time &time, const std::string &server)
1270    {
1271        const State s = GetState(server, GetCurrentState(server));
1272
1273        QApplication::postEvent(this,
1274           new FunctionEvent(boost::bind(&FactGui::handleStateChanged, this, time, server, s)));
1275    }
1276
1277    int Write(const Time &time, const string &txt, int qos)
1278    {
1279        QApplication::postEvent(this,
1280           new FunctionEvent(boost::bind(&FactGui::handleWrite, this, time, txt, qos)));
1281
1282        return 0;
1283    }
1284
1285    // ====================== Dim infoHandler================================
1286
1287    void handleDimInfo(const DimData &d)
1288    {
1289        if (d.info==&fDimDNS)
1290            return handleDimDNS(d.get<unsigned int>());
1291
1292        cout << "HandleDimInfo " << d.name << endl;
1293
1294        if (d.info==&fDimLoggerStats)
1295            return handleLoggerStats(d);
1296
1297        if (d.info==&fDimLoggerFilenameNight)
1298            return handleLoggerFilenameNight(d);
1299
1300        if (d.info==&fDimLoggerNumSubs)
1301            return handleLoggerNumSubs(d);
1302
1303        if (d.info==&fDimLoggerFilenameRun)
1304            return handleLoggerFilenameRun(d);
1305
1306        if (d.info==&fDimFtmTriggerCounter)
1307            return handleFtmTriggerCounter(d);
1308
1309        if (d.info==&fDimFtmDynamicData)
1310            return handleFtmDynamicData(d);
1311
1312        if (d.info==&fDimFtmPassport)
1313            return handleFtmPassport(d);
1314
1315        if (d.info==&fDimFtmFtuList)
1316            return handleFtmFtuList(d);
1317
1318        if (d.info==&fDimFtmStaticData)
1319            return handleFtmStaticData(d);
1320
1321        if (d.info==&fDimFtmError)
1322            return handleFtmError(d);
1323    }
1324
1325    void handleDimService(const string &txt)
1326    {
1327        fDimSvcText->append(txt.c_str());
1328    }
1329
1330
1331    void infoHandlerService(DimInfo &info)
1332    {
1333        const string fmt = string(info.getFormat()).empty() ? "C" : info.getFormat();
1334
1335        stringstream dummy;
1336        const Converter conv(dummy, fmt, false);
1337
1338        const Time tm(info.getTimestamp(), info.getTimestampMillisecs()*1000);
1339
1340        stringstream out;
1341        out << "<font size'-1' color='navy'>[" << Time::fmt("%H:%M:%S.%f") << tm << "]</font>   <B>" << info.getName() << "</B> - ";
1342
1343        bool iserr = true;
1344        if (!conv)
1345        {
1346            out << "Compilation of format string '" << fmt << "' failed!";
1347        }
1348        else
1349        {
1350            try
1351            {
1352                const string dat = conv.GetString(info.getData(), info.getSize());
1353                out << dat;
1354                iserr = false;
1355            }
1356            catch (const runtime_error &e)
1357            {
1358                out << "Conversion to string failed!<pre>" << e.what() << "</pre>";
1359            }
1360        }
1361
1362        // srand(hash<string>()(string(info.getName())));
1363        // int bg = rand()&0xffffff;
1364
1365        int bg = hash<string>()(string(info.getName()));
1366
1367        // allow only light colors
1368        bg = ~(bg&0x1f1f1f)&0xffffff;
1369
1370        if (iserr)
1371            bg = 0xffffff;
1372
1373        stringstream bgcol;
1374        bgcol << hex << setfill('0') << setw(6) << bg;
1375
1376        const string col = iserr ? "red" : "black";
1377        const string str = "<table width='100%' bgcolor=#"+bgcol.str()+"><tr><td><font color='"+col+"'>"+out.str()+"</font></td></tr></table>";
1378
1379        QApplication::postEvent(this,
1380                                new FunctionEvent(boost::bind(&FactGui::handleDimService, this, str)));
1381    }
1382
1383    void infoHandler()
1384    {
1385        // Initialize the time-stamp (what a weird workaround...)
1386        getInfo()->getTimestamp();
1387
1388        if (std::find(fDim.begin(), fDim.end(), getInfo())!=fDim.end())
1389        {
1390            QApplication::postEvent(this,
1391                                    new FunctionEvent(boost::bind(&FactGui::handleDimInfo, this, DimData(getInfo()))));
1392            return;
1393        }
1394
1395        for (map<string,DimInfo*>::iterator i=fServices.begin(); i!=fServices.end(); i++)
1396            if (i->second==getInfo())
1397            {
1398                infoHandlerService(*i->second);
1399                return;
1400            }
1401
1402        DimNetwork::infoHandler();
1403    }
1404
1405
1406    // ======================================================================
1407
1408    bool event(QEvent *evt)
1409    {
1410        if (dynamic_cast<FunctionEvent*>(evt))
1411            return static_cast<FunctionEvent*>(evt)->Exec();
1412
1413        if (dynamic_cast<CheckBoxEvent*>(evt))
1414        {
1415            const QStandardItem &item = static_cast<CheckBoxEvent*>(evt)->item;
1416            const QStandardItem *par  = item.parent();
1417            if (par)
1418            {
1419                const QString server  = par->text();
1420                const QString service = item.text();
1421
1422                const string s = (server+'/'+service).toStdString();
1423
1424                if (item.checkState()==Qt::Checked)
1425                    SubscribeService(s);
1426                else
1427                    UnsubscribeService(s);
1428            }
1429        }
1430
1431        return MainWindow::event(evt); // unrecognized
1432    }
1433
1434    void on_fDimCmdSend_clicked()
1435    {
1436        const QString server    = fDimCmdServers->currentIndex().data().toString();
1437        const QString command   = fDimCmdCommands->currentIndex().data().toString();
1438        const QString arguments = fDimCmdLineEdit->displayText();
1439
1440        // FIXME: Sending a command exactly when the info Handler changes
1441        //        the list it might lead to confusion.
1442        try
1443        {
1444            SendDimCommand(server.toStdString(), command.toStdString()+" "+arguments.toStdString());
1445            fTextEdit->append("<font color='green'>Command '"+server+'/'+command+"' successfully emitted.</font>");
1446            fDimCmdLineEdit->clear();
1447        }
1448        catch (const runtime_error &e)
1449        {
1450            stringstream txt;
1451            txt << e.what();
1452
1453            string buffer;
1454            while (getline(txt, buffer, '\n'))
1455                fTextEdit->append(("<font color='red'><pre>"+buffer+"</pre></font>").c_str());
1456        }
1457    }
1458    void ChoosePatch(Camera &cam, int idx)
1459    {
1460        cam.Reset();
1461
1462        fThresholdIdx->setValue(idx);
1463        fThresholdVal->setValue(fFtmStaticData.fThreshold[idx<0?0:idx]);
1464
1465        if (idx<0)
1466            return;
1467
1468        for (unsigned int i=0; i<fPatch.size(); i++)
1469            if (fPatch[i]==idx)
1470                cam.SetBold(i);
1471    }
1472
1473    void ChoosePixel(Camera &cam, int idx)
1474    {
1475        cam.SetWhite(idx);
1476        ChoosePatch(cam, fPatch[idx]);
1477    }
1478
1479#ifdef HAS_ROOT
1480    void slot_RootEventProcessed(TObject *obj, unsigned int evt, TCanvas *)
1481    {
1482        // kMousePressEvent       // TCanvas processed QEvent mousePressEvent
1483        // kMouseMoveEvent        // TCanvas processed QEvent mouseMoveEvent
1484        // kMouseReleaseEvent     // TCanvas processed QEvent mouseReleaseEvent
1485        // kMouseDoubleClickEvent // TCanvas processed QEvent mouseDoubleClickEvent
1486        // kKeyPressEvent         // TCanvas processed QEvent keyPressEvent
1487        // kEnterEvent            // TCanvas processed QEvent enterEvent
1488        // kLeaveEvent            // TCanvas processed QEvent leaveEvent
1489        if (dynamic_cast<TCanvas*>(obj))
1490            return;
1491
1492        TQtWidget *tipped = static_cast<TQtWidget*>(sender());
1493
1494        if (evt==11/*kMouseReleaseEvent*/)
1495        {
1496            if (dynamic_cast<Camera*>(obj))
1497            {
1498                const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1499                const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1500
1501                Camera *cam = static_cast<Camera*>(obj);
1502                const int idx = cam->GetIdx(xx, yy);
1503
1504                ChoosePixel(*cam, idx);
1505            }
1506            return;
1507        }
1508
1509        if (evt==61/*kMouseDoubleClickEvent*/)
1510        {
1511            if (dynamic_cast<Camera*>(obj))
1512            {
1513                const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1514                const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1515
1516                Camera *cam = static_cast<Camera*>(obj);
1517                const int idx = cam->GetIdx(xx, yy);
1518
1519                cam->Toggle(idx);
1520            }
1521            return;
1522        }
1523
1524        // Find the object which will get picked by the GetObjectInfo
1525        // due to buffer overflows in many root-versions
1526        // in TH1 and TProfile we have to work around and implement
1527        // our own GetObjectInfo which make everything a bit more
1528        // complicated.
1529#if ROOT_VERSION_CODE > ROOT_VERSION(5,22,00)
1530        const char *objectInfo =
1531            obj->GetObjectInfo(tipped->GetEventX(),tipped->GetEventY());
1532#else
1533        const char *objectInfo = dynamic_cast<TH1*>(obj) ?
1534            "" : obj->GetObjectInfo(tipped->GetEventX(),tipped->GetEventY());
1535#endif
1536
1537        QString tipText;
1538        tipText += obj->GetName();
1539        tipText += " [";
1540        tipText += obj->ClassName();
1541        tipText += "]: ";
1542        tipText += objectInfo;
1543
1544        if (dynamic_cast<Camera*>(obj))
1545        {
1546            const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1547            const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1548
1549            Camera *cam = static_cast<Camera*>(obj);
1550            int idx = fPatch[cam->GetIdx(xx, yy)];
1551
1552            tipText+="  Patch=";
1553            tipText+=QString::number(idx);
1554        }
1555
1556
1557        fStatusBar->showMessage(tipText, 3000);
1558
1559        gSystem->ProcessEvents();
1560        //QWhatsThis::display(tipText)
1561    }
1562
1563    void slot_RootUpdate()
1564    {
1565        gSystem->ProcessEvents();
1566        QTimer::singleShot(0, this, SLOT(slot_RootUpdate()));
1567    }
1568
1569    void on_fThresholdIdx_valueChanged(int idx)
1570    {
1571        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1572        ChoosePatch(*cam, idx);
1573    }
1574#endif
1575
1576    TGraph fGraphFtmTemp[4];
1577
1578    map<int, int> fPatch;
1579
1580public:
1581    FactGui() :
1582        fFtuDisabled(40),
1583        fDimDNS("DIS_DNS/VERSION_NUMBER", 1, int(0), this),
1584
1585        fDimLoggerStats        ("DATA_LOGGER/STATS", (void*)NULL, 0, this),
1586        fDimLoggerFilenameNight("DATA_LOGGER/FILENAME_NIGHTLY", const_cast<char*>(""), 0, this),
1587        fDimLoggerFilenameRun  ("DATA_LOGGER/FILENAME_RUN",     const_cast<char*>(""), 0, this),
1588        fDimLoggerNumSubs      ("DATA_LOGGER/NUM_SUBS",         const_cast<char*>(""), 0, this),
1589
1590        fDimFtmPassport      ("FTM_CONTROL/PASSPORT",        (void*)NULL, 0, this),
1591        fDimFtmTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", (void*)NULL, 0, this),
1592        fDimFtmError         ("FTM_CONTROL/ERROR",           (void*)NULL, 0, this),
1593        fDimFtmFtuList       ("FTM_CONTROL/FTU_LIST",        (void*)NULL, 0, this),
1594        fDimFtmStaticData    ("FTM_CONTROL/STATIC_DATA",     (void*)NULL, 0, this),
1595        fDimFtmDynamicData   ("FTM_CONTROL/DYNAMIC_DATA",    (void*)NULL, 0, this)
1596    {
1597        fTriggerWidget->setEnabled(false);
1598        fFtuWidget->setEnabled(false);
1599        fRatesWidget->setEnabled(false);
1600        fLoggerWidget->setEnabled(false);
1601
1602        fChatSend->setEnabled(false);
1603        fChatMessage->setEnabled(false);
1604
1605        DimClient::sendCommand("CHAT/MSG", "GUI online.");
1606        // + MessageDimRX
1607
1608        fDim.push_back(&fDimFtmDynamicData);
1609        fDim.push_back(&fDimFtmTriggerCounter);
1610        fDim.push_back(&fDimFtmStaticData);
1611        fDim.push_back(&fDimFtmFtuList);
1612        fDim.push_back(&fDimFtmPassport);
1613        fDim.push_back(&fDimFtmError);
1614        fDim.push_back(&fDimLoggerStats);
1615        fDim.push_back(&fDimLoggerFilenameNight);
1616        fDim.push_back(&fDimLoggerFilenameRun);
1617        fDim.push_back(&fDimLoggerNumSubs);
1618        fDim.push_back(&fDimDNS);
1619
1620        // --------------------------------------------------------------------------
1621
1622        ifstream fin("fact-trigger-all.txt");
1623
1624        int l = 0;
1625
1626        string buf;
1627        while (getline(fin, buf, '\n'))
1628        {
1629            buf = Tools::Trim(buf);
1630            if (buf[0]=='#')
1631                continue;
1632
1633            stringstream str(buf);
1634            for (int i=0; i<9; i++)
1635            {
1636                int n;
1637                str >> n;
1638
1639                fPatch[n] = l;
1640            }
1641            l++;
1642        }
1643
1644        // --------------------------------------------------------------------------
1645#ifdef HAS_ROOT
1646        TCanvas *c = fFtmTempCanv->GetCanvas();
1647        c->SetBit(TCanvas::kNoContextMenu);
1648        c->SetBorderMode(0);
1649        c->SetFrameBorderMode(0);
1650        c->SetFillColor(kWhite);
1651        c->SetRightMargin(0.03);
1652        c->SetTopMargin(0.03);
1653        c->cd();
1654
1655        TH1F h("MyFrame", "", 1000, 0, 1);//Time().RootTime()-1./24/60/60, Time().RootTime());
1656        h.SetDirectory(0);
1657        h.SetBit(TH1::kCanRebin);
1658        h.SetStats(kFALSE);
1659        h.SetMinimum(-20);
1660        h.SetMaximum(100);
1661        h.SetXTitle("Time");
1662        h.SetYTitle("Temperature / °C");
1663        h.GetXaxis()->CenterTitle();
1664        h.GetYaxis()->CenterTitle();
1665//        h.GetXaxis()->SetTitleSize(1.2);
1666//        h.GetYaxis()->SetTitleSize(1.2);
1667        h.DrawCopy();
1668
1669        fGraphFtmTemp[0].SetMarkerStyle(kFullDotSmall);
1670        fGraphFtmTemp[1].SetMarkerStyle(kFullDotSmall);
1671        fGraphFtmTemp[2].SetMarkerStyle(kFullDotSmall);
1672        fGraphFtmTemp[3].SetMarkerStyle(kFullDotSmall);
1673
1674        fGraphFtmTemp[1].SetLineColor(kBlue);
1675        fGraphFtmTemp[2].SetLineColor(kRed);
1676        fGraphFtmTemp[3].SetLineColor(kGreen);
1677
1678        fGraphFtmTemp[1].SetMarkerColor(kBlue);
1679        fGraphFtmTemp[2].SetMarkerColor(kRed);
1680        fGraphFtmTemp[3].SetMarkerColor(kGreen);
1681
1682        fGraphFtmTemp[0].Draw("LP");
1683        fGraphFtmTemp[1].Draw("LP");
1684        fGraphFtmTemp[2].Draw("LP");
1685        fGraphFtmTemp[3].Draw("LP");
1686
1687        // --------------------------------------------------------------------------
1688
1689        c = fRatesCanv->GetCanvas();
1690        c->SetBit(TCanvas::kNoContextMenu);
1691        c->SetBorderMode(0);
1692        c->SetFrameBorderMode(0);
1693        c->SetFillColor(kWhite);
1694        c->cd();
1695
1696        Camera *cam = new Camera;
1697        cam->SetBit(kCanDelete);
1698        cam->Draw();
1699
1700        ChoosePixel(*cam, 1);
1701
1702//        QTimer::singleShot(0, this, SLOT(slot_RootUpdate()));
1703
1704        //widget->setMouseTracking(true);
1705        //widget->EnableSignalEvents(kMouseMoveEvent);
1706
1707        fFtmTempCanv->setMouseTracking(true);
1708        fFtmTempCanv->EnableSignalEvents(kMouseMoveEvent);
1709
1710        fRatesCanv->setMouseTracking(true);
1711        fRatesCanv->EnableSignalEvents(kMouseMoveEvent|kMouseReleaseEvent|kMouseDoubleClickEvent);
1712
1713        connect(fRatesCanv,   SIGNAL(     RootEventProcessed(TObject*, unsigned int, TCanvas*)),
1714                this,         SLOT  (slot_RootEventProcessed(TObject*, unsigned int, TCanvas*)));
1715        connect(fFtmTempCanv, SIGNAL(     RootEventProcessed(TObject*, unsigned int, TCanvas*)),
1716                this,         SLOT  (slot_RootEventProcessed(TObject*, unsigned int, TCanvas*)));
1717#endif
1718    }
1719
1720    ~FactGui()
1721    {
1722        UnsubscribeAllServers();
1723    }
1724};
1725
1726#endif
Note: See TracBrowser for help on using the repository browser.