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

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