source: Evidence/Edd/Edd.cc@ 168

Last change on this file since 168 was 168, checked in by ogrimm, 16 years ago
Conversion to string can now handle arrays and structures
File size: 27.5 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
11February 2010, 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
22
23class Edd_DIM *Handler;
24
25
26// History chooser function (opens plot for numeric data, TextHist for all other)
27QWidget *OpenHistory(char *Service, int Index) {
28
29 char *Name, *Format;
30 DimBrowser Browser;
31
32 Browser.getServices(Service);
33 if (Browser.getNextService(Name, Format) != DimSERVICE) return NULL;
34
35 if (strlen(Format) == 1 && *Format != 'C') return new Edd_Plot(Service, Index);
36 else return new Edd_TextHist(Service);
37}
38
39
40//////////////////////////////////////////
41// Text display for arbitary DIM service//
42//////////////////////////////////////////
43
44// Constructor
45Edd_Indicator::Edd_Indicator(QString Name, int Index, QWidget *P):
46 QLineEdit(P), ServiceName(Name), Index(Index) {
47
48 // Widget properties
49 setReadOnly(true);
50 setMaximumWidth(100);
51 ShowAsTime = false;
52
53 // Connect to DIM handler
54 if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QByteArray, QString)), SLOT(Update(DimInfo*, int, QByteArray, QString))) == false) {
55 printf("Failed connection for %s\n", Name.toAscii().data());
56 }
57
58 // Context menu
59 Menu = new QMenu(this);
60 Menu->addAction("Open new history", this, SLOT(MenuOpenHistory()));
61 Menu->addAction("Copy service", this, SLOT(MenuCopyService()));
62 Menu->addAction("Copy data", this, SLOT(MenuCopyData()));
63
64 // Subscribe to service
65 Handler->Subscribe(Name);
66}
67
68// Destructor
69Edd_Indicator::~Edd_Indicator() {
70
71 Handler->Unsubscribe(ServiceName);
72}
73
74// Update widget
75void Edd_Indicator::Update(DimInfo *Info, int Time, QByteArray Array, QString Text) {
76
77 if (ServiceName != Info->getName()) return;
78
79 QPalette Pal = palette();
80
81 // Check if service available
82 if (Time == -1) {
83 setText("n/a");
84 setStatusTip(QString("%1: unavailable").arg(Info->getName()));
85 Pal.setColor(QPalette::Base, Qt::lightGray);
86 }
87 else {
88 // Backgound colour determined by last byte
89 switch (Array[Array.size()]) {
90 case 0: Pal.setColor(QPalette::Base, Qt::white); break;
91 case 1: Pal.setColor(QPalette::Base, Qt::yellow); break;
92 case 2: Pal.setColor(QPalette::Base, Qt::red); break;
93 case 3: Pal.setColor(QPalette::Base, Qt::red); break;
94 default: break;
95 }
96
97 if (toupper(*(Info->getFormat()) != 'C')) Text = Text.section(' ', Index, Index);
98
99 if (!ShowAsTime) setText(Text);
100 else setText(QDateTime::fromTime_t(Text.toInt()).toString());
101 setCursorPosition(0);
102
103 // Update status tip
104 setStatusTip(QString("%1: Last update %2 Format '%3' Index %4").arg(Info->getName()).arg( QDateTime::fromTime_t(Time).toString()).arg(Info->getFormat()).arg(Index));
105 }
106
107 setPalette(Pal);
108}
109
110// Open plot if mouse release within widget
111void Edd_Indicator::mouseReleaseEvent(QMouseEvent *Event) {
112
113 if (Event->button()!=Qt::LeftButton || !contentsRect().contains(Event->pos())) return;
114
115 // Check if last history plot still open, then raise
116 foreach (QWidget *Widget, QApplication::allWidgets()) {
117 if (Widget == LastPlot) {
118 Widget->activateWindow();
119 Widget->raise();
120 return;
121 }
122 }
123
124 // If not, open new plot
125 Edd_Indicator::MenuOpenHistory();
126}
127
128// Handling of mouse press event: Register start position for drag
129void Edd_Indicator::mousePressEvent(QMouseEvent *Event) {
130
131 if (Event->button() == Qt::LeftButton) dragStart = Event->pos();
132}
133
134// Handling of dragging (Drag and MimeData will be deleted by Qt)
135void Edd_Indicator::mouseMoveEvent(QMouseEvent *Event) {
136
137 if ((Event->buttons() & Qt::LeftButton) == 0) return;
138 if ((Event->pos()-dragStart).manhattanLength() < QApplication::startDragDistance()) return;
139
140 QDrag *Drag = new QDrag(this);
141 QMimeData *MimeData = new QMimeData;
142 MimeData->setText(ServiceName);
143 Drag->setMimeData(MimeData);
144 Drag->exec();
145}
146
147//
148// Opening context menu
149//
150void Edd_Indicator::contextMenuEvent(QContextMenuEvent *Event) {
151
152 Menu->exec(Event->globalPos());
153}
154
155// Menu: Open history plot
156void Edd_Indicator::MenuOpenHistory() {
157
158 LastPlot = OpenHistory(ServiceName.toAscii().data(), Index);
159 if (LastPlot != NULL) LastPlot->show();
160}
161
162// Menu: Copy service name
163void Edd_Indicator::MenuCopyService() {
164
165 QApplication::clipboard()->setText(ServiceName);
166}
167
168// Menu: Copy data
169void Edd_Indicator::MenuCopyData() {
170
171 QApplication::clipboard()->setText(text());
172}
173
174//////////////////////////////////
175// History plot for DIM service //
176//////////////////////////////////
177
178//
179// Constructor
180//
181Edd_Plot::Edd_Plot(QString DIMService, int Index, QWidget *P):
182 QwtPlot(P), EvidenceHistory() {
183
184 Mutex = new QMutex(QMutex::Recursive);
185
186 // Widget properties
187 setAcceptDrops(true);
188 setAttribute(Qt::WA_DeleteOnClose);
189 setAutoReplot(false);
190 setCanvasBackground(QColor(Qt::yellow));
191 setAxisScaleDraw(QwtPlot::xBottom, new TimeScale());
192
193 Zoomer = new QwtPlotZoomer(QwtPlot::xBottom,QwtPlot::yLeft,canvas());
194 connect(Zoomer, SIGNAL(zoomed(const QwtDoubleRect &)), this, SLOT(HandleZoom(const QwtDoubleRect &)));
195 Panner = new QwtPlotPanner(canvas());
196 Panner->setMouseButton(Qt::LeftButton, Qt::ShiftModifier);
197 Grid = new QwtPlotGrid;
198 Grid->setMajPen(QPen(Qt::gray, 0, Qt::DotLine));
199 Grid->attach(this);
200 Legend = new QwtLegend();
201 Legend->setItemMode(QwtLegend::ClickableItem);
202 insertLegend(Legend, QwtPlot::TopLegend);
203
204 connect(this, SIGNAL(legendClicked (QwtPlotItem *)), SLOT(LegendClicked(QwtPlotItem *)));
205
206 // Connect to DIM handler
207 if (connect(Handler, SIGNAL(YEP(DimInfo *, int, QByteArray, QString)), SLOT(Update(DimInfo *, int, QByteArray, QString))) == false) {
208 printf("Failed connection for %s\n", DIMService.toAscii().data());
209 }
210
211 // Context menu
212 Menu = new QMenu(this);
213 YLogAction = Menu->addAction("y scale log", this, SLOT(UpdatePlot()));
214 YLogAction->setCheckable(true);
215 NormAction = Menu->addAction("Normalize", this, SLOT(UpdatePlot()));
216 NormAction->setCheckable(true);
217 StyleAction = Menu->addAction("Draw dots", this, SLOT(UpdatePlot()));
218 StyleAction->setCheckable(true);
219 Menu->addAction("Zoom out", this, SLOT(MenuZoomOut()));
220 Menu->addAction("Single trace", this, SLOT(MenuSingleTrace()));
221 Menu->addSeparator();
222 Menu->addAction("Save as ASCII", this, SLOT(MenuSaveASCII()));
223 Menu->addAction("Save plot", this, SLOT(MenuSave()));
224 Menu->addAction("Print plot", this, SLOT(MenuPrint()));
225 Menu->addSeparator();
226 Menu->addAction("Paste service", this, SLOT(MenuPasteService()));
227
228 // DIM client
229 if (!DIMService.isEmpty()) AddService(DIMService, Index);
230}
231
232//
233// Destructor (items with parent widget are automatically deleted)
234//
235Edd_Plot::~Edd_Plot() {
236
237 for (int i=0; i<Items.size(); i++) {
238 Handler->Unsubscribe(Items[i].Name);
239 delete Items[i].Signal;
240 }
241 delete Grid;
242 delete Mutex;
243}
244
245//
246// Add history service to plot
247//
248void Edd_Plot::AddService(QString Name, int Index) {
249return;
250 // Lock before accessing Items list
251 QMutexLocker Locker(Mutex);
252
253 // Check if already subscribed to service
254 for (int i=0; i<Items.size(); i++) {
255 if (Name == Items[i].Name && Index == Items[i].Index) {
256 QMessageBox::warning(this, "Edd Message",Name+" (index "+QString::number(Index)+") already present",QMessageBox::Ok);
257 return;
258 }
259 }
260
261 // Generate new curve and subscribe to service
262 struct PlotItem New;
263
264 New.Name = Name;
265 New.Signal = new QwtPlotCurve;
266 New.Signal->attach(this);
267 New.Signal->setTitle(Name+"("+QString::number(Index)+")");
268 New.Signal->setPen(QColor(LineColors[Items.size() % (sizeof(LineColors)/sizeof(Qt::GlobalColor))]));
269 New.SizeLimit = 5000;
270 New.Index = Index;
271
272 Items.append(New);
273 Handler->Subscribe(Name);
274}
275
276// Update widget (must happen in GUI thread)
277void Edd_Plot::Update(DimInfo *Info, int Time, QByteArray, QString Text) {
278
279 // Check if service available
280 if (Time == -1) {
281 setStatusTip(QString("%1: unavailable").arg(Info->getName()));
282 return;
283 }
284
285 // Lock before accessing Items list
286 QMutexLocker Locker(Mutex);
287
288 // Determine which plot item this call belongs to
289 int ItemNo;
290 for (ItemNo=0; ItemNo<Items.size(); ItemNo++) if (Items[ItemNo].Name == Info->getName()) {
291
292 // If size limit reached, clear buffer
293 if (Items[ItemNo].x.size() > Items[ItemNo].SizeLimit) {
294 Items[ItemNo].x.clear();
295 Items[ItemNo].y.clear();
296 }
297
298 // If buffer empty, request new history buffer
299 if (Items[ItemNo].x.isEmpty()) {
300 int Time, Size;
301 void *Data;
302
303 if (GetHistory(Items[ItemNo].Name.toAscii().data())) {
304 double Smallest = DBL_MAX, Largest = DBL_MIN;
305 double Number=0;
306 while (Next(Time, Size, Data)) {
307 switch (toupper(*(Info->getFormat()))) {
308 case 'I':
309 case 'L': Number = *((int *) Data + Items[ItemNo].Index); break;
310 case 'S': Number = *((short *) Data + Items[ItemNo].Index); break;
311 case 'F': Number = *((float *) Data + Items[ItemNo].Index); break;
312 case 'D': Number = *((double *) Data + Items[ItemNo].Index); break;
313 case 'X': Number = *((long long *) Data + Items[ItemNo].Index); break;
314 default: break;
315 }
316
317 Items[ItemNo].x.append(Time);
318 Items[ItemNo].y.append(Number);
319
320 if (Largest < Items[ItemNo].y.last()) Largest = Items[ItemNo].y.last();
321 if (Smallest > Items[ItemNo].y.last()) Smallest = Items[ItemNo].y.last();
322 }
323
324 Items[ItemNo].Smallest = Smallest;
325 Items[ItemNo].Largest = Largest;
326
327 // Local buffer always at least twice as large as history
328 if (Items[ItemNo].SizeLimit < 2*Items[ItemNo].x.size()) {
329 Items[ItemNo].SizeLimit = 2*Items[ItemNo].x.size();
330 }
331 }
332 }
333
334 // Append data
335 Text = Text.section(' ', Items[ItemNo].Index, Items[ItemNo].Index);
336
337 Items[ItemNo].x.append(Time);
338 Items[ItemNo].y.append(atof(Text.toAscii().data()));
339
340 // Update largest and smallest value
341 if (Items[ItemNo].y.last() > Items[ItemNo].Largest) Items[ItemNo].Largest = Items[ItemNo].y.last();
342 if (Items[ItemNo].y.last() < Items[ItemNo].Smallest) Items[ItemNo].Smallest = Items[ItemNo].y.last();
343
344 // Update status tip
345 QDateTime Timex = QDateTime::fromTime_t(Time);
346 setStatusTip(QString("%1: Last update %2 Format '%3'").arg(Info->getName(), Timex.toString()).arg(Info->getFormat()));
347 }
348
349 UpdatePlot();
350}
351
352//
353// Update all curves in plot
354//
355void Edd_Plot::UpdatePlot() {
356
357 static QwtSymbol Symbol, Sym1;
358 Symbol.setStyle(QwtSymbol::Ellipse);
359 Symbol.setSize(4);
360
361 if (!YLogAction->isChecked()) {
362 setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
363 }
364 else setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine);
365
366 // Lock before accessing Items list
367 QMutexLocker Locker(Mutex);
368
369 for (int ItemNo=0; ItemNo<Items.size(); ItemNo++) {
370
371 if (StyleAction->isChecked()) Items[ItemNo].Signal->setSymbol(Symbol);
372 else Items[ItemNo].Signal->setSymbol(Sym1);
373
374 int DataPoints = Items[ItemNo].x.size();
375 if (DataPoints == 0) continue;
376
377 // Normalize y scale if requested
378 double *y = new double [DataPoints];
379 for (int i=0; i<DataPoints; i++) {
380 y[i] = Items[ItemNo].y[i];
381
382 if (NormAction->isChecked()) {
383 if (Items[ItemNo].Smallest != Items[ItemNo].Largest) {
384 y[i] = (y[i] - Items[ItemNo].Smallest)/(Items[ItemNo].Largest-Items[ItemNo].Smallest);
385 }
386 else y[i] = 1;
387 }
388 }
389
390 // Plot data
391 Items[ItemNo].Signal->setData(Items[ItemNo].x.data(), y, DataPoints);
392 Items[ItemNo].Signal->show();
393 Zoomer->setZoomBase(Items[ItemNo].Signal->boundingRect());
394
395 delete[] y;
396 }
397 replot();
398}
399
400//
401// Reset graph axes to autoscale when fully unzoomed
402//
403void Edd_Plot::HandleZoom(const QwtDoubleRect &) {
404
405 if(Zoomer->zoomRectIndex() == 0) {
406 setAxisAutoScale(QwtPlot::xBottom);
407 setAxisAutoScale(QwtPlot::yLeft);
408 }
409}
410
411//
412// Drag and drop methods
413//
414
415void Edd_Plot::dragEnterEvent(QDragEnterEvent *Event) {
416
417 if (Event->mimeData()->hasFormat("text/plain")) Event->acceptProposedAction();
418}
419
420void Edd_Plot::dropEvent(QDropEvent *Event) {
421
422 AddService(Event->mimeData()->text().toAscii().data());
423}
424
425// Opening context menu
426void Edd_Plot::contextMenuEvent(QContextMenuEvent *Event) {
427
428 Menu->exec(Event->globalPos());
429}
430
431// Drag&Drop method
432void Edd_Plot::LegendClicked(QwtPlotItem *Item) {
433
434 QDrag *Drag = new QDrag(this);
435 QMimeData *MimeData = new QMimeData;
436 MimeData->setText(Item->title().text().remove(".hist"));
437 Drag->setMimeData(MimeData);
438 Drag->exec();
439}
440
441
442// Zoom completely out
443void Edd_Plot::MenuZoomOut() {
444
445 Zoomer->zoom(0);
446 UpdatePlot();
447}
448
449// Remove all items except last
450void Edd_Plot::MenuSingleTrace() {
451
452 // Lock before accessing Items list
453 QMutexLocker Locker(Mutex);
454
455 while (Items.size() > 1) {
456 Handler->Unsubscribe(Items.last().Name);
457 delete Items.last().Signal;
458 Items.takeLast();
459 }
460 UpdatePlot();
461}
462
463// Save data of plot as test
464void Edd_Plot::MenuSaveASCII() {
465 QString Filename = QFileDialog::getSaveFileName(this,
466 "Filename", ".", "Text files (*.txt *.ascii *.asc);;All files (*)");
467 if (Filename.length() <= 0) return;
468
469 QFile File(Filename);
470 if (!File.open(QFile::WriteOnly | QIODevice::Text | QFile::Truncate)) {
471 QMessageBox::warning(this, "Edd Message","Could not open file for writing.",QMessageBox::Ok);
472 return;
473 }
474
475 // Lock before accessing Items list
476 QMutexLocker Locker(Mutex);
477 QTextStream Stream(&File);
478
479 // Write x and y data for all signals to file
480 for (int ItemNo=0; ItemNo<Items.size(); ItemNo++) {
481 Stream << QString("# ") + Items[ItemNo].Name + ".hist" << endl;
482 for (int i=0; i<Items[ItemNo].Signal->dataSize(); i++) {
483 Stream << (int) Items[ItemNo].x.at(i) << " " << Items[ItemNo].Signal->y(i) << endl;
484 }
485 }
486}
487
488// Print plot
489void Edd_Plot::MenuPrint() {
490
491 QPrinter *Printer = new QPrinter;
492 QPrintDialog *PrintDialog = new QPrintDialog(Printer, this);
493 if (PrintDialog->exec() == QDialog::Accepted) {
494 QPainter Painter(Printer);
495 QPixmap Pixmap = QPixmap::grabWidget(this);
496 Painter.drawPixmap(0, 0, Pixmap);
497 }
498 delete Printer; delete PrintDialog;
499}
500
501// Save plot as image
502void Edd_Plot::MenuSave() {
503
504 QString Filename = QFileDialog::getSaveFileName(this,
505 "Filename of image", "/home/ogrimm/ddd", "Image files (*.bmp *.jpg *.png *.ppm *.tiff *.xbm *.xpm);;All files (*)");
506 if (Filename.length()>0) {
507 QPixmap Pixmap = QPixmap::grabWidget(this);
508 if(!Pixmap.save(Filename)) {
509 QMessageBox::warning(this, "Edd Message","Could not write image file.",QMessageBox::Ok);
510 remove(Filename.toAscii().data());
511 }
512 }
513}
514
515// Add new service by pasting name
516void Edd_Plot::MenuPasteService() {
517
518 AddService(QApplication::clipboard()->text().toAscii().data());
519}
520
521
522///////////////////////////////////////
523// History text box for DIM service //
524//////////////////////////////////////
525
526//
527// Constructor
528//
529Edd_TextHist::Edd_TextHist(QString Name, QWidget *P):
530 QTextEdit(P), EvidenceHistory(), Name(Name) {
531
532 // Widget properties
533 setReadOnly(true);
534 setAttribute(Qt::WA_DeleteOnClose);
535 setAutoFillBackground(true);
536 document()->setMaximumBlockCount(1000);
537
538 // Connect to DIM handler
539 if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QByteArray, QString)), SLOT(Update(DimInfo*, int, QByteArray, QString))) == false) {
540 printf("Failed connection for %s\n", Name.toAscii().data());
541 }
542
543 // Get history for this service
544 int Time, Size;
545 void *Data;
546
547 if (GetHistory(Name.toAscii().data())) {
548 while (Next(Time, Size, Data)) {
549 moveCursor (QTextCursor::Start);
550 insertPlainText(QString("(")+QDateTime::fromTime_t(Time).toString()+") ");
551 insertPlainText(QString((char *) Data) + "\n");
552 }
553 }
554
555 // DIM client
556 Handler->Subscribe(Name);
557}
558
559// Destructor
560Edd_TextHist::~Edd_TextHist() {
561
562 Handler->Unsubscribe(Name);
563}
564
565
566// Update widget (must happen in GUI thread)
567void Edd_TextHist::Update(DimInfo *Info, int Time, QByteArray, QString Text) {
568
569 if (Name != Info->getName()) return;
570
571 // Check if service available
572 if (Time == -1) {
573 setStatusTip(QString("%1: unavailable").arg(Info->getName()));
574 return;
575 }
576
577 QDateTime Timex = QDateTime::fromTime_t(Time);
578
579 moveCursor(QTextCursor::Start);
580 insertPlainText(QString("(")+Timex.toString()+QString(") "));
581 insertPlainText(Text + "\n");
582
583 // Update status tip
584 setStatusTip(QString("%1: Last update %2 Format '%3'").arg(Info->getName(), Timex.toString()).arg(Info->getFormat()));
585}
586
587
588//////////////////
589// Text display //
590//////////////////
591
592// Constructor
593Edd_Textout::Edd_Textout(QString Name, QWidget *P): QTextEdit(P), Name(Name) {
594
595 // Widget properties
596 setReadOnly(true);
597 setAutoFillBackground(true);
598 document()->setMaximumBlockCount(1000);
599 Accumulate = true;
600
601 // Connect to DIM handler
602 if (connect(Handler, SIGNAL(YEP(DimInfo*, int, QByteArray, QString)), SLOT(Update(DimInfo*, int, QByteArray, QString))) == false) {
603 printf("Failed connection for %s\n", Name.toAscii().data());
604 }
605
606 // Subscribe to service
607 Handler->Subscribe(Name);
608}
609
610// Destructor
611Edd_Textout::~Edd_Textout() {
612
613 Handler->Unsubscribe(Name);
614}
615
616// Handling of DIM service update
617void Edd_Textout::Update(DimInfo *Info, int Time, QByteArray, QString Text) {
618
619 if (Name != Info->getName()) return;
620
621 QPalette Pal = palette();
622
623 // Check if service available
624 if (Time == -1) {
625 setStatusTip(QString("%1: unavailable").arg(Info->getName()));
626 Pal.setColor(QPalette::Base, Qt::lightGray);
627 }
628 else {
629 Pal.setColor(QPalette::Base, Qt::white);
630
631 // Clear display in case text should not accumulate
632 if (Accumulate == false) clear();
633
634 // Add if service contains only a string
635 if (strcmp(Info->getFormat(), "C") == 0) insertPlainText(Text);
636
637 // Update status tip
638 setStatusTip(QString("%1: Last update %2 Format '%3'").arg(Info->getName(), QDateTime::fromTime_t(Time).toString()).arg(Info->getFormat()));
639 }
640 setPalette(Pal);
641}
642
643
644/////////////////////////////
645// Interface to Dim system //
646/////////////////////////////
647Edd_DIM::Edd_DIM() {
648
649 Mutex = new QMutex(QMutex::Recursive);
650
651 // Connect to DIM handler
652 if (connect(this, SIGNAL(YEP(DimInfo*, int, QByteArray, QString)), SLOT(Update(DimInfo*, int, QByteArray, QString))) == false) {
653 printf("Failed connection in Edd_DIM()\n");
654 }
655}
656
657Edd_DIM::~Edd_DIM() {
658
659 delete Mutex;
660}
661
662// Subscribe to DIM service
663void Edd_DIM::Subscribe(QString Name) {
664
665 // Lock before accessing list
666 QMutexLocker Locker(Mutex);
667
668 // Check if already subscribed to service, then increase usage count and emit last service data
669 for (int i=0; i<ServiceList.size(); i++) if (ServiceList[i].Name == Name) {
670 ServiceList[i].Count++;
671 YEP(ServiceList[i].DIMService, ServiceList[i].TimeStamp, ServiceList[i].ByteArray, ServiceList[i].Text);
672 return;
673 }
674
675 // Create new entry in service list
676 struct Item New;
677 New.Name = Name;
678 New.DIMService = new DimStampedInfo(Name.toAscii().data(), INT_MAX, NO_LINK, this);
679 New.Count = 1;
680 ServiceList.append(New);
681
682 return;
683}
684
685// Unsubsribe from DIM service
686void Edd_DIM::Unsubscribe(QString Name) {
687
688 // Lock before accessing list
689 QMutexLocker Locker(Mutex);
690
691 for (int i=0; i<ServiceList.size(); i++) if (ServiceList[i].Name == Name) {
692 ServiceList[i].Count--;
693 if (ServiceList[i].Count == 0) {
694 delete ServiceList[i].DIMService;
695 ServiceList.removeAt(i);
696 return;
697 }
698 }
699}
700
701// Store service information for usage by Subscribe()
702void Edd_DIM::Update(DimInfo *Info, int Time, QByteArray Data, QString Text) {
703
704 // Lock before accessing list
705 QMutexLocker Locker(Mutex);
706
707 for (int i=0; i<ServiceList.size(); i++) if (ServiceList[i].Name == Info->getName()) {
708 ServiceList[i].TimeStamp = Time;
709 ServiceList[i].ByteArray = Data;
710 ServiceList[i].Text = Text;
711 }
712}
713
714// Handling of DIM service update
715void Edd_DIM::infoHandler() {
716
717 if (!EvidenceServer::ServiceOK(getInfo())) YEP(getInfo(), -1);
718 else {
719 char *Txt = EvidenceServer::ToString(getInfo());
720 YEP(getInfo(), getInfo()->getTimestamp(), QByteArray((char *) getInfo()->getData(), getInfo()->getSize()), QString(Txt));
721 free(Txt);
722 }
723}
724
725
726//
727// Main GUI (all widgets have ultimately Central as parent)
728//
729GUI::GUI() {
730
731 Handler = new Edd_DIM();
732
733 // Set features of main window
734 Central = new QWidget(this);
735 setCentralWidget(Central);
736 setStatusBar(new QStatusBar(this));
737 setGeometry(100, 100, 800, 650);
738 setWindowTitle("Edd - Evidence Data Display");
739
740 Edd_Indicator *Value;
741 Edd_Plot *Graph;
742 Edd_Textout *Textout;
743 QString Text;
744
745 // TextBox for value
746 //Value = new Edd_Indicator((char *) "SQM/NSB", Central);
747 //Graph = new Edd_Plot((char *) "SQM/NSB", Central);
748 //Graph->AddService("BIAS/VOLT/ID00/00-000");
749
750
751 // Clock (updated every second)
752 //Clock = new QwtAnalogClock(Central);
753 //Clock->scaleDraw()->setPenWidth(3);
754 //Clock->setLineWidth(6);
755 //Clock->setFrameShadow(QwtDial::Sunken);
756 //Clock->setGeometry(0,0,10,10);
757 //Clock->setTime();
758
759 //QTimer *Timer = new QTimer(Clock);
760 //Timer->connect(Timer, SIGNAL(timeout()), Clock, SLOT(setCurrentTime()));
761 //Timer->start(1000);
762
763 MainWidget = new QWidget();
764 MainLayout = new QGridLayout(MainWidget);
765
766 Value = new Edd_Indicator("Alarm/Status");
767 Value->setMaximumWidth(200);
768 MainLayout->addWidget(Value, 0, 0, 1, 2);
769
770 Value = new Edd_Indicator("Alarm/MasterAlarm");
771 MainLayout->addWidget(Value, 0, 1, 1, 1);
772
773 Textout = new Edd_Textout("Alarm/Summary");
774 Textout->Accumulate = false;
775 Textout->setMaximumWidth(200);
776 Textout->setMaximumHeight(150);
777 MainLayout->addWidget(Textout, 1, 0, 1, 2);
778
779 Value = new Edd_Indicator("DColl/Status");
780 Value->setMaximumWidth(200);
781 MainLayout->addWidget(Value, 3, 0, 1, 2);
782
783 Value = new Edd_Indicator("DColl/DataSizekB");
784 MainLayout->addWidget(Value, 4, 0, 1, 1);
785
786 Value = new Edd_Indicator("DColl/LogSizekB");
787 MainLayout->addWidget(Value, 4, 1, 1, 1);
788
789 Value = new Edd_Indicator("DColl/CurrentFile");
790 Value->setMaximumWidth(400);
791 MainLayout->addWidget(Value, 5, 0, 1, 3);
792
793 Value = new Edd_Indicator("Config/Status");
794 Value->setMaximumWidth(200);
795 MainLayout->addWidget(Value, 6, 0, 1, 2);
796
797 Value = new Edd_Indicator("Config/ModifyTime");
798 Value->setMaximumWidth(200);
799 Value->ShowAsTime = true;
800 MainLayout->addWidget(Value, 7, 0, 1, 1);
801
802 QPushButton *Button = new QPushButton();
803 Button->setText("Start DIM browser");
804 connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser()));
805 MainLayout->addWidget(Button, 7, 1, 1, 1);
806
807 // Layout of all widgets
808 //MainLayout->addWidget(Value, 0, 0, 1, 1);
809 //MainLayout->addWidget(Clock, 0, 1, 1, 1);
810 //MainLayout->addWidget(Graph, 1, 0, 1, 2);
811 //MainLayout->setColumnStretch(1, 10);
812
813 //MainLayout->addWidget(Clock, 0, 1, 1, 1);
814 //MainLayout->addWidget(Graph1, 2, 0, 1, 2);
815
816 // Feedback page
817 FeedbackWidget = new QWidget();
818 FeedbackLayout = new QGridLayout(FeedbackWidget);
819 Graph = new Edd_Plot();
820 for (int i=0; i<36; i++) {
821 //Text = Text.sprintf("Feedback/Average/ID%.2d/%.2d-%.3d",i/16, (i%16)/8, i%8);
822 Text = Text.sprintf("Feedback/AverageTest/ID%.2d",i/16);
823 Value = new Edd_Indicator(Text, i%16);
824 FeedbackLayout->addWidget(Value, i%9+1, 0+i/9, 1, 1);
825 //Graph->AddService(Text);
826 }
827 FeedbackLayout->addWidget(Graph, 0, 4, 11, 3);
828
829 //Graph = new Edd_Plot();
830 //for (int i=0; i<36; i++) {
831 //Text = Text.sprintf("Feedback/Sigma/ID%.2d/%.2d-%.3d",i/16, (i%16)/8, i%8);
832 //Graph->AddService(Text);
833 //}
834 //FeedbackLayout->addWidget(Graph, 10, 0, 10, 3);
835
836 Value = new Edd_Indicator("Feedback/Status");
837 Value->setMaximumWidth(200);
838 FeedbackLayout->addWidget(Value, 0, 0, 1, 3);
839 Value = new Edd_Indicator("Feedback/Count");
840 FeedbackLayout->addWidget(Value, 0, 3, 1, 1);
841
842 // Bias voltage page
843 BiasWidget = new QWidget();
844 BiasLayout = new QGridLayout(BiasWidget);
845 Graph = new Edd_Plot();
846 for (int i=0; i<18; i++) {
847 Value = new Edd_Indicator("Bias/VOLT/ID00", i);
848 BiasLayout->addWidget(Value, i%9+1, 0+i/9, 1, 1);
849 //Graph->AddService(Text, i);
850
851 Value = new Edd_Indicator("Bias/VOLT/ID00", i+32);
852 BiasLayout->addWidget(Value, i%9+1, 2+i/9, 1, 1);
853 //Graph->AddService(Text,i+32);
854 }
855
856 BiasLayout->addWidget(Graph, 0, 4, 12, 3);
857 Value = new Edd_Indicator("Bias/Status");
858 Value->setMaximumWidth(200);
859 BiasLayout->addWidget(Value, 0, 0, 1, 3);
860
861 Textout = new Edd_Textout("Bias/Textout");
862 Textout->setFixedWidth(400);
863 BiasLayout->addWidget(Textout, 10, 0, 4, 4);
864
865 // Environment page
866 EnvironmentWidget = new QWidget();
867 EnvironmentLayout = new QGridLayout(EnvironmentWidget);
868 Value = new Edd_Indicator("ARDUINO/Status");
869 Value->setMaximumWidth(200);
870 EnvironmentLayout->addWidget(Value, 0, 0, 1, 3);
871
872 Graph = new Edd_Plot();
873 for (int i=0; i<10; i++) {
874 Value = new Edd_Indicator("ARDUINO/Data", i);
875 EnvironmentLayout->addWidget(Value, i%5+1, i/5, 1, 1);
876 Graph->AddService("ARDUINO/Data", i);
877 }
878 EnvironmentLayout->addWidget(Graph, 0, 3, 7, 4);
879
880 Value = new Edd_Indicator("SQM/NSB");
881 EnvironmentLayout->addWidget(Value, 6, 0, 1, 1);
882
883 // Tab widget
884 TabWidget = new QTabWidget(Central);
885 TabWidget->addTab(BiasWidget, "&Bias");
886 TabWidget->addTab(FeedbackWidget, "&Feedback");
887 TabWidget->addTab(EnvironmentWidget, "&Environment");
888 TabWidget->addTab(MainWidget, "Evidence");
889
890 // Menu bar
891 QMenu* Menu = menuBar()->addMenu("&Menu");
892 Menu->addAction("New history plot", this, SLOT(MenuNewHistory()));
893 Menu->addSeparator();
894 Menu->addAction("About", this, SLOT(MenuAbout()));
895 Menu->addSeparator();
896 QAction* QuitAction = Menu->addAction("Quit", qApp, SLOT(quit()));
897 QuitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
898
899 // Show main window
900 show();
901}
902
903GUI::~GUI() {
904 delete Central;
905}
906
907
908void GUI::MenuAbout() {
909 QString Rev(SVN_REVISION);
910 Rev.remove(0,1).chop(2);
911
912 QMessageBox::about(this, "About Edd","Evidence Data Display\n\n"
913 "Written by Oliver Grimm, IPP, ETH Zurich\n"
914 "This version compiled "__DATE__" ("+Rev+")\n\n"
915 "Graphical user interface implemented with Qt and Qwt.\n"
916 "Evidence control system based on DIM (http://dim.web.cern.ch).\n\n"
917 "Comments to oliver.grimm@phys.ethz.ch.");
918}
919
920// Open request for new history plot
921void GUI::MenuNewHistory() {
922
923 QStringList List;
924 char *Name, *Format;
925 int Type;
926 bool OK;
927
928 // Find all services that are not history services and sort
929 getServices("*");
930 while ((Type = getNextService(Name, Format)) != 0) {
931 if (Type==DimSERVICE && strstr(Name, ".hist")==NULL) List.append(Name);
932 }
933 List.sort();
934
935 // Open dialog and open history window
936 QString Result = QInputDialog::getItem(this, "Edd Request",
937 "Enter DIM service name", List, 0, true, &OK);
938 if (OK && !Result.isEmpty()) {
939 Result = Result.trimmed();
940 if (Result.endsWith(".hist")) Result.chop(5);
941 QWidget *Hist = OpenHistory(Result.toAscii().data(), 0);
942 if (Hist != NULL) Hist->show();
943 }
944}
945
946// Start DIM Browser
947void GUI::StartDIMBrowser() {
948
949 QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/");
950}
951
952
953//---------------------------------------------------------------------
954//************************ All functions ****************************
955//-------------------------------------------------------------------
956
957// Quit application when clicking close button on window
958void GUI::closeEvent(QCloseEvent *) {
959 qApp->quit();
960}
961
962
963//---------------------------------------------------------------------
964//**************************** Main program ***************************
965//---------------------------------------------------------------------
966
967int main(int argc, char *argv[]) {
968
969 QApplication app(argc, argv);
970 GUI MainWindow;
971
972 return app.exec();
973}
Note: See TracBrowser for help on using the repository browser.