source: Evidence/Edd/Edd.cc@ 151

Last change on this file since 151 was 151, checked in by ogrimm, 12 years ago
DColl publishes also current data file name
File size: 22.4 KB
Line 
1
2/* ============================================================
3
4Edd - Evidence Data Display
5
6Qt-based graphical user interface for the Evidence contron system
7
8Edd_Indicator changes its background colour in case it display
9a DIM status service
10
11December 2009, Oliver Grimm
12
13============================================================ */
14
15#include "Edd.h"
16
17Qt::GlobalColor LineColors[] = {Qt::black, Qt::blue, Qt::red, Qt::green, Qt::white,
18 Qt::darkRed, Qt::darkGreen, Qt::darkBlue, Qt::cyan,
19 Qt::darkCyan, Qt::magenta, Qt::darkMagenta,
20 Qt::gray, Qt::darkGray, Qt::lightGray};
21
22class GUI *Handler;
23
24//////////////////////////////////////////
25// Text display for arbitary DIM service//
26//////////////////////////////////////////
27
28// Constructor
29Edd_Indicator::Edd_Indicator(QString DIMService, QWidget *P): QLineEdit(P) {
30
31 // Widget properties
32 setReadOnly(true);
33 setMaximumWidth(100);
34 ShowAsTime = false;
35
36 // Connect to DIM handler
37 if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QString, QByteArray, QString)), SLOT(Update(DimInfo*, int, QString, QByteArray, QString))) == false) {
38 printf("Failed connection for %s\n", DIMService.toAscii().data());
39 }
40
41 // Context menu
42 Menu = new QMenu(this);
43 Menu->addAction("Open history", this, SLOT(MenuOpenHistory()));
44 Menu->addAction("Copy service", this, SLOT(MenuCopyService()));
45
46 // DIM client
47 Data = new DimStampedInfo(DIMService.toAscii().data(), INT_MAX, (char *) NO_LINK, Handler);
48}
49
50// Destructor
51Edd_Indicator::~Edd_Indicator() {
52 delete Data;
53}
54
55// Update widget
56void Edd_Indicator::Update(DimInfo *Info, int Time, QString Format, QByteArray Data, QString Text) {
57
58 if (Info != this->Data) return;
59
60 QPalette Pal = palette();
61
62 // Check if service available
63 if (Time == -1) {
64 setText("n/a");
65 setStatusTip(QString("%1: unavailable").arg(Info->getName()));
66 Pal.setColor(QPalette::Base, Qt::lightGray);
67 }
68 else {
69 // If this is a status indicator, adapt background colour
70 if (Data.size() == Text.size()+2) {
71 switch (Data[Text.size() + 2]) {
72 case 0: Pal.setColor(QPalette::Base, Qt::white); break;
73 case 1: Pal.setColor(QPalette::Base, Qt::cyan); break;
74 case 2: Pal.setColor(QPalette::Base, Qt::red); break;
75 case 3: Pal.setColor(QPalette::Base, Qt::red); break;
76 default: break;
77 }
78 }
79 else Pal.setColor(QPalette::Base, Qt::white);
80
81 if (!ShowAsTime) setText(Text);
82 else setText(QDateTime::fromTime_t(Text.toInt()).toString());
83
84 // Update status tip
85 setStatusTip(QString("%1: Last update %2 Format '%3'").arg(Info->getName(), QDateTime::fromTime_t(Time).toString()).arg(Format));
86 }
87
88 setPalette(Pal);
89}
90
91// Open plot if mouse release within widget
92void Edd_Indicator::mouseReleaseEvent(QMouseEvent *Event) {
93
94 if (Event->button()!=Qt::LeftButton || !contentsRect().contains(Event->pos())) return;
95
96 // Check if last history plot still open, then raise
97 foreach (QWidget *Widget, QApplication::allWidgets()) {
98 if (Widget == LastPlot) {
99 Widget->activateWindow();
100 Widget->raise();
101 return;
102 }
103 }
104
105 // If not, open new plot
106 Edd_Indicator::MenuOpenHistory();
107}
108
109// Handling of mouse press event: Register start position for drag
110void Edd_Indicator::mousePressEvent(QMouseEvent *Event) {
111
112 if (Event->button() == Qt::LeftButton) dragStart = Event->pos();
113}
114
115// Handling of dragging (Drag and MimeData will be deleted by Qt)
116void Edd_Indicator::mouseMoveEvent(QMouseEvent *Event) {
117
118 if ((Event->buttons() & Qt::LeftButton) == 0) return;
119 if ((Event->pos()-dragStart).manhattanLength() < QApplication::startDragDistance()) return;
120
121 QDrag *Drag = new QDrag(this);
122 QMimeData *MimeData = new QMimeData;
123 MimeData->setText(QString(Data->getName()));
124 Drag->setMimeData(MimeData);
125 Drag->exec();
126}
127
128//
129// Opening context menu
130//
131void Edd_Indicator::contextMenuEvent(QContextMenuEvent *Event) {
132
133 Menu->exec(Event->globalPos());
134}
135
136// Open history plot
137void Edd_Indicator::MenuOpenHistory() {
138
139 LastPlot = new Edd_Plot(Data->getName());
140 LastPlot->show();
141}
142
143// Copy service name
144void Edd_Indicator::MenuCopyService() {
145
146 QApplication::clipboard()->setText(QString(Data->getName()));
147}
148
149//////////////////////////////////
150// History plot for DIM service //
151//////////////////////////////////
152
153//
154// Constructor
155//
156Edd_Plot::Edd_Plot(QString DIMService, QWidget *P): QwtPlot(P) {
157
158 setAcceptDrops(true);
159 setAttribute(Qt::WA_DeleteOnClose);
160
161 // Graph properties
162 setAutoReplot(false);
163 QwtText XAxisTitle("Time (RJD-55200)");
164 XAxisTitle.setFont(QFont("Helvetica", 10));
165 setAxisTitle(QwtPlot::xBottom, XAxisTitle);
166 setCanvasBackground(QColor(Qt::yellow));
167
168 Zoomer = new QwtPlotZoomer(QwtPlot::xBottom,QwtPlot::yLeft,canvas());
169 connect(Zoomer, SIGNAL(zoomed(const QwtDoubleRect &)), this, SLOT(HandleZoom(const QwtDoubleRect &)));
170 Panner = new QwtPlotPanner(canvas());
171 Panner->setMouseButton(Qt::LeftButton, Qt::ShiftModifier);
172 Grid = new QwtPlotGrid;
173 Grid->setMajPen(QPen(Qt::gray, 0, Qt::DotLine));
174 Grid->attach(this);
175 Legend = new QwtLegend();
176 insertLegend(Legend, QwtPlot::TopLegend);
177
178 // Connect to DIM handler
179 if (connect(Handler, SIGNAL(YEP(DimInfo *, int, QString, QByteArray, QString)), SLOT(Update(DimInfo *, int, QString, QByteArray, QString))) == false) {
180 printf("Failed connection for %s\n", DIMService.toAscii().data());
181 }
182
183 // Context menu
184 Menu = new QMenu(this);
185 YLogAction = Menu->addAction("y scale log", this, SLOT(UpdatePlot()));
186 YLogAction->setCheckable(true);
187 NormAction = Menu->addAction("Normalize", this, SLOT(UpdatePlot()));
188 NormAction->setCheckable(true);
189 StyleAction = Menu->addAction("Draw dots", this, SLOT(UpdatePlot()));
190 StyleAction->setCheckable(true);
191 Menu->addAction("Zoom out", this, SLOT(MenuZoomOut()));
192 Menu->addAction("Single trace", this, SLOT(MenuSingleTrace()));
193 Menu->addSeparator();
194 Menu->addAction("Save as ASCII", this, SLOT(MenuSaveASCII()));
195 Menu->addAction("Save plot", this, SLOT(MenuSave()));
196 Menu->addAction("Print plot", this, SLOT(MenuPrint()));
197 Menu->addSeparator();
198 Menu->addAction("Paste service", this, SLOT(MenuPasteService()));
199
200 // DIM client
201 if (!DIMService.isEmpty()) AddService(DIMService);
202}
203
204//
205// Destructor (items with parent widget are automatically deleted)
206//
207Edd_Plot::~Edd_Plot() {
208
209 for (int i=0; i<Items.size(); i++) {
210 delete Items[i].Data;
211 delete Items[i].LiveData;
212 delete Items[i].Signal;
213 delete[] Items[i].x;
214 delete[] Items[i].y;
215 }
216 delete Grid;
217}
218
219//
220// Add history service to plot
221//
222void Edd_Plot::AddService(QString Name) {
223
224 QString HistName = Name+".hist";
225
226 // Lock before accessing Items list
227 QMutexLocker Locker(&Mutex);
228
229 // Check if already subsribed to service
230 for (int i=0; i<Items.size(); i++) {
231 if (HistName == Items[i].Data->getName()) {
232 QMessageBox::warning(this, "Edd Message",HistName+" already present",QMessageBox::Ok);
233 return;
234 }
235 }
236
237 // Generate new curve and subscribe to service
238 struct PlotItem New;
239 New.Signal = new QwtPlotCurve;
240 New.Signal->attach(this);
241 New.Signal->setTitle(HistName);
242 New.Signal->setPen(QColor(LineColors[Items.size() % (sizeof(LineColors)/sizeof(Qt::GlobalColor))]));
243 New.x = NULL;
244 New.y = NULL;
245 New.Count = 0;
246 New.Data = new DimStampedInfo(HistName.toAscii().data(), (char *) NO_LINK, Handler);
247 New.LiveData = new DimStampedInfo(Name.toAscii().data(), (char *) NO_LINK, Handler);
248
249 Items.append(New);
250}
251
252// Update widget (must happen in GUI thread)
253void Edd_Plot::Update(DimInfo *Info, int Time, QString Format, QByteArray Data, QString Text) {
254
255 // Check if service available
256 if (Time == -1) {
257 setStatusTip(QString("%1: unavailable").arg(Info->getName()));
258 }
259
260 // Lock before accessing Items list
261 QMutexLocker Locker(&Mutex);
262
263 // Determine which plot item this call belongs to
264 int ItemNo;
265 for (ItemNo=0; ItemNo<Items.size(); ItemNo++) if (Info == Items[ItemNo].Data) {
266 // This is a history service
267 EvidenceHistoryItem *Curr = (EvidenceHistoryItem *) Data.data();
268 int Count=0, DataPoints = Data.size()/sizeof(struct EvidenceHistoryItem);
269
270 delete[] Items[ItemNo].x;
271 delete[] Items[ItemNo].y;
272 Items[ItemNo].x = new int [DataPoints];
273 Items[ItemNo].y = new double [DataPoints];
274
275 // Find oldest item
276 int Oldest;
277 for (Oldest=1; Oldest<DataPoints; Oldest++) {
278 if (Curr[Oldest].Seconds < Curr[Oldest-1].Seconds) break;
279 }
280
281 // Plot data starting with oldest value
282 for (int i=0; i<DataPoints; i++) {
283 Items[ItemNo].x[Count] = Curr[(i+Oldest)%DataPoints].Seconds;
284 Items[ItemNo].y[Count] = Curr[(i+Oldest)%DataPoints].Value;
285 if (Items[ItemNo].x[Count] != 0) Count++;
286 }
287
288 // Find smallest and largest item
289 double Smallest = DBL_MAX, Largest = DBL_MIN;
290 for (int i=0; i<Count; i++) {
291 if (Largest < Items[ItemNo].y[i]) Largest = Items[ItemNo].y[i];
292 if (Smallest > Items[ItemNo].y[i]) Smallest = Items[ItemNo].y[i];
293 }
294 Items[ItemNo].Smallest = Smallest;
295 Items[ItemNo].Largest = Largest;
296 Items[ItemNo].Count = Count;
297
298 // Clear local history
299 Items[ItemNo].Live.clear();
300
301 // Update status tip
302 QDateTime Timex = QDateTime::fromTime_t(Time);
303 StatusTip = QString("%1: Last update %2 Format '%3'").arg(Info->getName(), Timex.toString()).arg(Format);
304
305 } else if (Info == Items[ItemNo].LiveData) {
306 // This is a live service
307
308 // Limit size of list
309 if (Items[ItemNo].Live.size() > 1000) Items[ItemNo].Live.removeFirst();
310
311 // Append data
312 struct EvidenceHistoryItem Data;
313 Data.Seconds = Time;
314 Data.Value = atof(Text.toAscii().data());
315 Items[ItemNo].Live.append(Data);
316
317 // Update largest and smallest value
318 if (Data.Value > Items[ItemNo].Largest) Items[ItemNo].Largest = Data.Value;
319 if (Data.Value < Items[ItemNo].Smallest) Items[ItemNo].Smallest = Data.Value;
320 }
321
322 Locker.unlock();
323
324 UpdatePlot();
325}
326
327//
328// Update all curves in plot
329//
330void Edd_Plot::UpdatePlot() {
331
332 static QwtSymbol Symbol, Sym1;
333 Symbol.setStyle(QwtSymbol::Ellipse);
334 Symbol.setSize(4);
335
336 if (!YLogAction->isChecked()) {
337 setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
338 }
339 else setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine);
340
341 // Lock before accessing Items list
342 QMutexLocker Locker(&Mutex);
343
344 setStatusTip(StatusTip);
345
346 for (int ItemNo=0; ItemNo<Items.size(); ItemNo++) {
347
348 if (StyleAction->isChecked()) Items[ItemNo].Signal->setSymbol(Symbol);
349 else Items[ItemNo].Signal->setSymbol(Sym1);
350
351 int DataPoints = Items[ItemNo].Count + Items[ItemNo].Live.size();
352
353 if (DataPoints == 0) continue;
354
355 double *x = new double [DataPoints];
356 double *y = new double [DataPoints];
357
358 // Adapt time scale and normalize y scale if requested
359 for (int i=0; i<DataPoints; i++) {
360 if (i < Items[ItemNo].Count) {
361 x[i] = Items[ItemNo].x[i] / 86400.0 + 40587.5 - 55200;
362 y[i] = Items[ItemNo].y[i];
363 }
364 else {
365 x[i]= Items[ItemNo].Live[i-Items[ItemNo].Count].Seconds / 86400.0 + 40587.5 - 55200;
366 y[i] = Items[ItemNo].Live[i-Items[ItemNo].Count].Value;
367 }
368
369 if (NormAction->isChecked()) {
370 if (Items[ItemNo].Smallest != Items[ItemNo].Largest) y[i] = (y[i] - Items[ItemNo].Smallest)/(Items[ItemNo].Largest-Items[ItemNo].Smallest);
371 else y[i] = 1;
372 }
373 }
374
375 // Plot datas
376 Items[ItemNo].Signal->setData(x, y, DataPoints);
377 Items[ItemNo].Signal->show();
378 Zoomer->setZoomBase(Items[ItemNo].Signal->boundingRect());
379
380 delete[] x;
381 delete[] y;
382 }
383 replot();
384}
385
386//
387// Reset graph axes to autoscale when fully unzoomed
388//
389void Edd_Plot::HandleZoom(const QwtDoubleRect &) {
390
391 if(Zoomer->zoomRectIndex() == 0) {
392 setAxisAutoScale(QwtPlot::xBottom);
393 setAxisAutoScale(QwtPlot::yLeft);
394 }
395}
396
397//
398// Drag and drop methods
399//
400
401void Edd_Plot::dragEnterEvent(QDragEnterEvent *Event) {
402
403 if (Event->mimeData()->hasFormat("text/plain")) Event->acceptProposedAction();
404}
405
406void Edd_Plot::dropEvent(QDropEvent *Event) {
407
408 AddService(Event->mimeData()->text().toAscii().data());
409}
410
411//
412// Opening context menu
413//
414void Edd_Plot::contextMenuEvent(QContextMenuEvent *Event) {
415
416 Menu->exec(Event->globalPos());
417}
418
419void Edd_Plot::MenuZoomOut() {
420
421 Zoomer->zoom(0);
422 UpdatePlot();
423}
424
425// Remove all items except last
426void Edd_Plot::MenuSingleTrace() {
427
428 // Lock before accessing Items list
429 QMutexLocker Locker(&Mutex);
430
431 while (Items.size() > 1) {
432 delete Items.last().Data;
433 delete Items.last().LiveData;
434 delete Items.last().Signal;
435 delete[] Items.last().x;
436 delete[] Items.last().y;
437 Items.takeLast();
438 }
439
440 Locker.unlock();
441 UpdatePlot();
442}
443
444// Save data of plot as test
445void Edd_Plot::MenuSaveASCII() {
446 QString Filename = QFileDialog::getSaveFileName(this,
447 "Filename", ".", "Text files (*.txt *.ascii *.asc);;All files (*)");
448 if (Filename.length() <= 0) return;
449
450 QFile File(Filename);
451 if (!File.open(QFile::WriteOnly | QIODevice::Text | QFile::Truncate)) {
452 QMessageBox::warning(this, "Edd Message","Could not open file for writing.",QMessageBox::Ok);
453 return;
454 }
455
456 // Lock before accessing Items list
457 QMutexLocker Locker(&Mutex);
458 QTextStream Stream(&File);
459
460 // Write x and y data for all signals to file
461 for (int ItemNo=0; ItemNo<Items.size(); ItemNo++) {
462 Stream << QString("# ")+Items[ItemNo].Data->getName() << endl;
463 for (int i=0; i<Items[ItemNo].Signal->dataSize(); i++) {
464 Stream << (int) Items[ItemNo].x[i] << " " << Items[ItemNo].Signal->y(i) << endl;
465 }
466 }
467}
468
469// Print plot
470void Edd_Plot::MenuPrint() {
471
472 QPrinter *Printer = new QPrinter;
473 QPrintDialog *PrintDialog = new QPrintDialog(Printer, this);
474 if (PrintDialog->exec() == QDialog::Accepted) {
475 QPainter Painter(Printer);
476 QPixmap Pixmap = QPixmap::grabWidget(this);
477 Painter.drawPixmap(0, 0, Pixmap);
478 }
479 delete Printer; delete PrintDialog;
480}
481
482// Save plot as image
483void Edd_Plot::MenuSave() {
484
485 QString Filename = QFileDialog::getSaveFileName(this,
486 "Filename of image", "/home/ogrimm/ddd", "Image files (*.bmp *.jpg *.png *.ppm *.tiff *.xbm *.xpm);;All files (*)");
487 if (Filename.length()>0) {
488 QPixmap Pixmap = QPixmap::grabWidget(this);
489 if(!Pixmap.save(Filename)) {
490 QMessageBox::warning(this, "Edd Message","Could not write image file.",QMessageBox::Ok);
491 remove(Filename.toAscii().data());
492 }
493 }
494}
495
496// Add new service by pasting name
497void Edd_Plot::MenuPasteService() {
498
499 AddService(QApplication::clipboard()->text().toAscii().data());
500}
501
502
503//////////////////
504// Text display //
505//////////////////
506
507// Constructor
508Edd_Textout::Edd_Textout(QString DIMService, QWidget *P): QTextEdit(P) {
509
510 // Widget properties
511 setReadOnly(true);
512 setAutoFillBackground(true);
513 document()->setMaximumBlockCount(1000);
514 Accumulate = true;
515
516 // Connect to DIM handler
517 if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QString, QByteArray, QString)), SLOT(Update(DimInfo*, int, QString, QByteArray, QString))) == false) {
518 printf("Failed connection for %s\n", DIMService.toAscii().data());
519 }
520
521 // DIM client
522 Data = new DimStampedInfo(DIMService.toAscii().data(), INT_MAX, (char *) NO_LINK, Handler);
523}
524
525// Destructor
526Edd_Textout::~Edd_Textout() {
527
528 delete Data;
529}
530
531// Handling of DIM service update
532void Edd_Textout::Update(DimInfo *Info, int Time, QString Format, QByteArray, QString Text) {
533
534 if (Info != this->Data) return;
535
536 QPalette Pal = palette();
537
538 // Check if service available
539 if (Time == -1) {
540 setStatusTip(QString("%1: unavailable").arg(Info->getName()));
541 Pal.setColor(QPalette::Base, Qt::lightGray);
542 }
543 else {
544 Pal.setColor(QPalette::Base, Qt::white);
545
546 // Clear display in case text should not accumulate
547 if (Accumulate == false) clear();
548
549 // Add if service contains only a string
550 if (Format == "C") insertPlainText(Text);
551
552 // Update status tip
553 setStatusTip(QString("%1: Last update %2 Format '%3'").arg(Info->getName(), QDateTime::fromTime_t(Time).toString()).arg(Format));
554 }
555 setPalette(Pal);
556}
557
558
559//
560// Main GUI (all widgets have ultimately Central as parent)
561//
562GUI::GUI() {
563
564 Handler = this;
565
566 // Set features of main window
567 Central = new QWidget(this);
568 setCentralWidget(Central);
569 setStatusBar(new QStatusBar(this));
570 setGeometry(100, 100, 800, 650);
571 setWindowTitle("Edd - Evidence Data Display");
572
573 Edd_Indicator *Value;
574 Edd_Plot *Graph;
575 Edd_Textout *Textout;
576 QString Text;
577
578 // TextBox for value
579 //Value = new Edd_Indicator((char *) "SQM/NSB", Central);
580 //Graph = new Edd_Plot((char *) "SQM/NSB", Central);
581 //Graph->AddService("BIAS/VOLT/ID00/00-000");
582
583
584 // Clock (updated every second)
585 //Clock = new QwtAnalogClock(Central);
586 //Clock->scaleDraw()->setPenWidth(3);
587 //Clock->setLineWidth(6);
588 //Clock->setFrameShadow(QwtDial::Sunken);
589 //Clock->setGeometry(0,0,10,10);
590 //Clock->setTime();
591
592 //QTimer *Timer = new QTimer(Clock);
593 //Timer->connect(Timer, SIGNAL(timeout()), Clock, SLOT(setCurrentTime()));
594 //Timer->start(1000);
595
596 MainWidget = new QWidget();
597 MainLayout = new QGridLayout(MainWidget);
598
599 Value = new Edd_Indicator("Alarm/Status");
600 Value->setMaximumWidth(200);
601 MainLayout->addWidget(Value, 0, 0, 1, 2);
602
603 Value = new Edd_Indicator("Alarm/MasterAlarm");
604 MainLayout->addWidget(Value, 0, 1, 1, 1);
605
606 Textout = new Edd_Textout("Alarm/Summary");
607 Textout->Accumulate = false;
608 Textout->setMaximumWidth(200);
609 Textout->setMaximumHeight(150);
610 MainLayout->addWidget(Textout, 1, 0, 1, 2);
611
612 Value = new Edd_Indicator("DColl/Status");
613 Value->setMaximumWidth(200);
614 MainLayout->addWidget(Value, 3, 0, 1, 2);
615
616 Value = new Edd_Indicator("DColl/DataSizekB");
617 MainLayout->addWidget(Value, 4, 0, 1, 1);
618
619 Value = new Edd_Indicator("DColl/LogSizekB");
620 MainLayout->addWidget(Value, 4, 1, 1, 1);
621
622 Value = new Edd_Indicator("DColl/CurrentFile");
623 Value->setMaximumWidth(400);
624 MainLayout->addWidget(Value, 5, 0, 1, 3);
625
626 Value = new Edd_Indicator("Config/Status");
627 Value->setMaximumWidth(200);
628 MainLayout->addWidget(Value, 6, 0, 1, 2);
629
630 Value = new Edd_Indicator("Config/ModifyTime");
631 Value->setMaximumWidth(200);
632 Value->ShowAsTime = true;
633 MainLayout->addWidget(Value, 7, 0, 1, 1);
634
635
636 // Layout of all widgets
637 //MainLayout->addWidget(Value, 0, 0, 1, 1);
638 //MainLayout->addWidget(Clock, 0, 1, 1, 1);
639 //MainLayout->addWidget(Graph, 1, 0, 1, 2);
640 //MainLayout->setColumnStretch(1, 10);
641
642 //MainLayout->addWidget(Clock, 0, 1, 1, 1);
643 //MainLayout->addWidget(Graph1, 2, 0, 1, 2);
644
645 // Bias voltage page
646 BiasWidget = new QWidget();
647 BiasLayout = new QGridLayout(BiasWidget);
648 Graph = new Edd_Plot();
649 for (int i=0; i<18; i++) {
650 Text = Text.sprintf("BIAS/VOLT/ID00/00-%.3d",i);
651 Value = new Edd_Indicator(Text);
652 BiasLayout->addWidget(Value, i%9+1, 0+i/9, 1, 1);
653 Graph->AddService(Text);
654
655 Text = Text.sprintf("BIAS/VOLT/ID00/01-%.3d",i);
656 Value = new Edd_Indicator(Text);
657 BiasLayout->addWidget(Value, i%9+1, 2+i/9, 1, 1);
658 Graph->AddService(Text);
659 }
660
661 BiasLayout->addWidget(Graph, 0, 4, 12, 3);
662 Value = new Edd_Indicator("BIAS/Status");
663 Value->setMaximumWidth(200);
664 BiasLayout->addWidget(Value, 0, 0, 1, 3);
665
666 Textout = new Edd_Textout("BIAS/Textout");
667 Textout->setFixedWidth(400);
668 BiasLayout->addWidget(Textout, 10, 0, 4, 4);
669
670 // Environment page
671 EnvironmentWidget = new QWidget();
672 EnvironmentLayout = new QGridLayout(EnvironmentWidget);
673 Value = new Edd_Indicator("ARDUINO/Status");
674 Value->setMaximumWidth(200);
675 EnvironmentLayout->addWidget(Value, 0, 0, 1, 3);
676
677 Graph = new Edd_Plot();
678 for (int i=0; i<10; i++) {
679 Text = Text.sprintf("ARDUINO/VAL%.2d", i);
680 Value = new Edd_Indicator(Text);
681 EnvironmentLayout->addWidget(Value, i%5+1, i/5, 1, 1);
682 Graph->AddService(Text);
683 }
684 EnvironmentLayout->addWidget(Graph, 0, 3, 7, 4);
685
686 Value = new Edd_Indicator("SQM/NSB");
687 EnvironmentLayout->addWidget(Value, 6, 0, 1, 1);
688
689 // Tab widget
690 TabWidget = new QTabWidget(Central);
691 TabWidget->addTab(MainWidget, "&Main");
692 TabWidget->addTab(BiasWidget, "&Bias");
693 TabWidget->addTab(EnvironmentWidget, "&Environment");
694
695 // Menu bar
696 QMenu* Menu = menuBar()->addMenu("&Menu");
697 Menu->addAction("New history plot", this, SLOT(MenuNewHistory()));
698 Menu->addSeparator();
699 Menu->addAction("About", this, SLOT(MenuAbout()));
700 Menu->addSeparator();
701 QAction* QuitAction = Menu->addAction("Quit", qApp, SLOT(quit()));
702 QuitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
703
704 // Show main window
705 show();
706}
707
708GUI::~GUI() {
709 delete Central;
710}
711
712
713void GUI::MenuAbout() {
714 QString Rev(SVN_REVISION);
715 Rev.remove(0,1).chop(2);
716
717 QMessageBox::about(this, "About Edd","Evidence Data Display\n\n"
718 "Written by Oliver Grimm, IPP, ETH Zurich\n"
719 "This version compiled "__DATE__" ("+Rev+")\n\n"
720 "Graphical user interface implemented with Qt and Qwt.\n"
721 "Evidence control system based on DIM (http://dim.web.cern.ch).\n\n"
722 "Comments to oliver.grimm@phys.ethz.ch.");
723}
724
725// Open request for new history plot
726void GUI::MenuNewHistory() {
727
728 QStringList List;
729 char *Name, *Format;
730 int Type;
731 bool OK;
732
733 // Find all services that are not history services and sort
734 getServices("*");
735 while ((Type = getNextService(Name, Format)) != 0) {
736 if (Type==DimSERVICE && strstr(Name, ".hist")==NULL) List.append(Name);
737 }
738 List.sort();
739
740 // Open dialog and open history window
741 QString Result = QInputDialog::getItem(this, "Edd Request",
742 "Enter DIM service name", List, 0, true, &OK);
743 if (OK && !Result.isEmpty()) {
744 Result = Result.trimmed();
745 if (Result.endsWith(".hist")) Result.chop(5);
746 Edd_Plot *Plot = new Edd_Plot(Result);
747 Plot->show();
748 }
749}
750
751// Handling of DIM service update
752void GUI::infoHandler() {
753
754 // Check if service available
755 if (getInfo()->getSize() == strlen(NO_LINK)+1 && strcmp(getInfo()->getString(), NO_LINK) == 0) {
756 YEP(getInfo(), -1);
757 }
758 else {
759 char *Txt = EvidenceServer::ToString(getInfo());
760
761 YEP(getInfo(), getInfo()->getTimestamp(), getInfo()->getFormat(), QByteArray((char *) getInfo()->getData(), getInfo()->getSize()), QString(Txt));
762 free(Txt);
763 }
764}
765
766//---------------------------------------------------------------------
767//************************ All functions ****************************
768//-------------------------------------------------------------------
769
770// Quit application when clicking close button on window
771void GUI::closeEvent(QCloseEvent *) {
772 qApp->quit();
773}
774
775
776//---------------------------------------------------------------------
777//**************************** Main program ***************************
778//---------------------------------------------------------------------
779
780int main(int argc, char *argv[]) {
781
782 QApplication app(argc, argv);
783 GUI MainWindow;
784
785 return app.exec();
786}
Note: See TracBrowser for help on using the repository browser.