Changeset 208 for Evidence/Edd


Ignore:
Timestamp:
05/18/10 15:39:48 (15 years ago)
Author:
ogrimm
Message:
Added event scope
Location:
Evidence/Edd
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • Evidence/Edd/Edd.cc

    r204 r208  
    3737}
    3838
     39// Set status tip (returns true if service was available)
     40bool SetStatus(QWidget *W, QString Name, int Time, QString Format, int Index) {
     41
     42  QString Status;
     43
     44  if (Index != -1) Name = Name + "(" + QString::number(Index) + ")";
     45
     46  if (Time == -1) Status = QString("%1:  unavailable").arg(Name);
     47  else Status = QString("%1:  Last update %2   Format '%3'").arg(Name).arg(QDateTime::fromTime_t(Time).toString()).arg(Format);
     48
     49  W->setStatusTip(Status);
     50  if (W->parent() == NULL) W->setToolTip(Status);
     51 
     52  return(Time != -1);
     53}
     54
    3955
    4056//////////////////////////////////////////
     
    4561EddLineDisplay::EddLineDisplay(QString Name, int Index, QWidget *P):
    4662        QLineEdit(P), ServiceName(Name), Index(Index) {
    47  
     63
    4864 LastPlot = NULL;
    4965 
     
    5268  setMaximumWidth(100);
    5369  ShowAsTime = false;
     70  setFrame(false);
    5471 
    5572  // Connect to DIM handler
     
    8299
    83100  // Check if service available
    84   if (Time == -1) {
     101  if (!SetStatus(this, Name, Time, Format, Index)) {
    85102    setText("n/a");
    86         setStatusTip(QString("%1:  unavailable").arg(ServiceName));
    87103    Pal.setColor(QPalette::Base, Qt::lightGray);
    88104  }
     
    102118        else setText(QDateTime::fromTime_t(Text.toInt()).toString());
    103119        setCursorPosition(0);
    104 
    105     // Update status tip
    106     setStatusTip(QString("%1 (%4):  Last update %2   Format '%3'").arg(ServiceName).arg( QDateTime::fromTime_t(Time).toString()).arg(Format).arg(Index));
    107120  }
    108121 
     
    183196//////////////////////////////////
    184197
    185 //
    186198// Constructor
    187 //
    188 EddPlot::EddPlot(QString DIMService, int Index, QWidget *P):
    189         QwtPlot(P) {
    190 
    191   Mutex = new QMutex(QMutex::Recursive);
    192  
     199EddPlot::EddPlot(QString DIMService, int Index, QWidget *P): EddBasePlot(P) {
     200
    193201  // Widget properties
    194202  setAcceptDrops(true);
     203  setAxisScaleDraw(QwtPlot::xBottom, new EddTimeScale);
     204       
     205  // Update time range on plot when axis change (update() results in paintEvent())
     206  connect(axisWidget(QwtPlot::xBottom), SIGNAL(scaleDivChanged()), SLOT(update()));
     207
     208  legend()->setItemMode(QwtLegend::ClickableItem);
     209  connect(this, SIGNAL(legendClicked (QwtPlotItem *)), SLOT(LegendClicked(QwtPlotItem *)));
     210 
     211  // Connect to DIM handler
     212  if (connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) {
     213    printf("Failed connection for %s\n", DIMService.toAscii().data());
     214  }
     215
     216  // Additonal context menu items
     217  QAction* Action = Menu->addAction("Paste service", this, SLOT(MenuPasteService()));
     218  Menu->removeAction(Action);
     219  Menu->insertAction(Menu->actions().value(1), Action);
     220 
     221  // Maximum number if points in curve (will be increased in Update())
     222  SizeLimit = 0;
     223
     224  // DIM client
     225  if (!DIMService.isEmpty()) AddService(DIMService, Index);
     226}
     227
     228// Destructor (items with parent widget are automatically deleted)
     229EddPlot::~EddPlot() {
     230
     231  while (!List.isEmpty()) DeleteCurve(List.last().Signal);
     232}
     233
     234// Add history service to plot
     235void EddPlot::AddService(QString Name, int Index) {
     236
     237  // Check if curve already present on plot
     238  for (int i=0; i<List.size(); i++) {
     239    if (Name == List[i].Name && Index == List[i].Index) {
     240      QMessageBox::warning(this, "Edd Message",Name+" ("+QString::number(Index)+") already present",QMessageBox::Ok);
     241      return;
     242    }
     243  } 
     244 
     245  // Generate new curve and subscribe to service
     246  struct ItemDetails N;
     247
     248  N.Name = Name;
     249  N.Signal = NewCurve(Name+"("+QString::number(Index)+")");
     250  N.Index = Index;
     251  List.append(N);
     252
     253  Handler->Subscribe(Name);
     254}
     255
     256// Update widget (must happen in GUI thread)
     257void EddPlot::Update(QString Name, int Time, QByteArray, QString Format, QString Text) {
     258
     259  // Determine which plot item this call belongs to
     260  int ItemNo;
     261  for (ItemNo=0; ItemNo<List.size(); ItemNo++) if (List[ItemNo].Name == Name) {
     262
     263        // Service available?
     264        if (!SetStatus(this, Name, Time, Format)) return;
     265 
     266        // If size limit reached, clear buffer
     267    if (List[ItemNo].Signal->dataSize() > SizeLimit) List[ItemNo].Signal->setData(QPolygonF());
     268
     269        // If buffer empty, request new history buffer
     270    if (List[ItemNo].Signal->dataSize() == 0) {
     271          int Time, Size;
     272          void *Data;
     273
     274          class EvidenceHistory *HistClass = Handler->GetHistory(List[ItemNo].Name);
     275         
     276          if (HistClass->GetHistory()) {
     277                double Number=0;
     278                while (HistClass->Next(Time, Size, Data)) {
     279                  switch (Format[0].toUpper().toAscii()) {
     280                case 'I':
     281                        case 'L':  Number = *((int *) Data + List[ItemNo].Index);   break;
     282                case 'S':  Number = *((short *) Data + List[ItemNo].Index);   break;
     283                case 'F':  Number = *((float *) Data + List[ItemNo].Index);   break;
     284                case 'D':  Number = *((double *) Data + List[ItemNo].Index);   break;
     285                case 'X':  Number = *((long long *) Data + List[ItemNo].Index);   break;
     286                default: break;
     287                  }
     288                  AddPoint(ItemNo, Time, Number);
     289                }
     290
     291                // Local buffer at least twice as large as longest history
     292                if (SizeLimit < 2*List[ItemNo].Signal->dataSize()) SizeLimit = 2*List[ItemNo].Signal->dataSize();
     293          }
     294        }
     295
     296    // Append data
     297        QString Txt = Text;
     298        Txt = Txt.section(' ', List[ItemNo].Index, List[ItemNo].Index);
     299    AddPoint(ItemNo, Time, atof(Txt.toAscii().data()));
     300  }
     301
     302  UpdatePlot();
     303}
     304
     305
     306// Add text indicating time range to plot
     307void EddPlot::paintEvent(QPaintEvent *) {
     308
     309  QString Text;
     310  QFont Font;
     311  QPainter Painter(this);
     312 
     313  Text = QDateTime::fromTime_t((int) axisScaleDiv(QwtPlot::xBottom)->lowerBound()).toString("d-MMM-yyyy hh:mm:ss") + " to " + QDateTime::fromTime_t((int) axisScaleDiv(QwtPlot::xBottom)->upperBound()).toString("d-MMM-yyyy hh:mm:ss");
     314
     315  Font.setPointSize(6); 
     316  Painter.setFont(Font);
     317  Painter.drawText(0, height(), Text);
     318}
     319
     320// Drag and drop methods
     321void EddPlot::dragEnterEvent(QDragEnterEvent *Event) {
     322   
     323  if (Event->mimeData()->hasFormat("Edd/Service")) Event->acceptProposedAction();
     324}
     325
     326void EddPlot::dropEvent(QDropEvent *Event) {
     327
     328  QByteArray D(Event->mimeData()->data("Edd/Service"));
     329  AddService(D.left(D.lastIndexOf(' ')), D.right(D.size()-D.lastIndexOf(' ')).toInt());
     330}
     331
     332void EddPlot::LegendClicked(QwtPlotItem *Item) {
     333
     334  QString D(Item->title().text());
     335  D.replace('(',' ').chop(1);
     336 
     337  QDrag *Drag = new QDrag(this);
     338  QMimeData *MimeData = new QMimeData;
     339  QByteArray Data;
     340  MimeData->setData("Edd/Service", Data.append(D));
     341  Drag->setMimeData(MimeData);
     342  Drag->exec();
     343}
     344
     345// Add new service by pasting name
     346void EddPlot::MenuPasteService() {
     347
     348  const QMimeData *D = QApplication::clipboard()->mimeData();
     349  if (!D->hasFormat("Edd/Service")) return;
     350 
     351  QByteArray E(D->data("Edd/Service"));
     352  AddService(E.left(E.lastIndexOf(' ')), E.right(E.size()-E.lastIndexOf(' ')).toInt());
     353}
     354
     355// Remove list entry
     356void EddPlot::DeleteCurve(QwtPlotCurve *Curve) {
     357
     358  for (int i=0; i<List.size(); i++) if (List[i].Signal == Curve) {
     359    Handler->Unsubscribe(List[i].Name);
     360    List.removeAt(i);
     361  }
     362}
     363
     364
     365//////////////////
     366// General plot //
     367//////////////////
     368
     369// Constructor (all slots called in GUI thread, therefore no mutex necessary)
     370EddBasePlot::EddBasePlot(QWidget *P): QwtPlot(P) {
     371
     372  // Widget properties
    195373  setAttribute(Qt::WA_DeleteOnClose);
    196374  setAutoReplot(false);
    197375  setCanvasBackground(EddPlotBackgroundColor);
    198   setAxisScaleDraw(QwtPlot::xBottom, new EddTimeScale);
    199376  setMargin(15);
    200377
    201   // Update additional information (e.g. time range) on widget when axis change
    202   connect(axisWidget(QwtPlot::xBottom), SIGNAL(scaleDivChanged()), SLOT(update()));
    203 
    204   Picker = new QwtPicker(QwtPicker::CornerToCorner|QwtPicker::RectSelection, QwtPicker::RectRubberBand, QwtPicker::AlwaysOff, this);
    205   connect(Picker, SIGNAL(selected(const QwtPolygon &)), SLOT(MouseSelection(const QwtPolygon &)));
    206 
     378  // Plot navigation
    207379  Zoomer = new QwtPlotZoomer(QwtPlot::xBottom,QwtPlot::yLeft,canvas());
    208380  connect(Zoomer, SIGNAL(zoomed(const QwtDoubleRect &)), this, SLOT(HandleZoom(const QwtDoubleRect &)));
     
    216388  Panner->setMouseButton(Qt::LeftButton, Qt::ShiftModifier);
    217389
     390  Picker = new QwtPicker(QwtPicker::CornerToCorner|QwtPicker::RectSelection, QwtPicker::RectRubberBand, QwtPicker::AlwaysOff, this);
     391  connect(Picker, SIGNAL(selected(const QwtPolygon &)), SLOT(MouseSelection(const QwtPolygon &)));
     392
     393  // Grid and legend
    218394  Grid = new QwtPlotGrid;
    219395  Grid->setMajPen(QPen(Qt::gray, 0, Qt::DotLine));
    220396  Grid->attach(this);
    221 
    222   Legend = new QwtLegend();
    223   Legend->setItemMode(QwtLegend::ClickableItem);
    224   insertLegend(Legend, QwtPlot::TopLegend, 0.3);
    225   connect(this, SIGNAL(legendClicked (QwtPlotItem *)), SLOT(LegendClicked(QwtPlotItem *)));
    226  
    227   // Connect to DIM handler
    228   if (connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) {
    229     printf("Failed connection for %s\n", DIMService.toAscii().data());
    230   }
     397 
     398  insertLegend(new QwtLegend(), QwtPlot::TopLegend, 0.3);
    231399
    232400  // Context menu
     
    247415  Menu->addAction("Save plot", this, SLOT(MenuSave()));
    248416  Menu->addAction("Print plot", this, SLOT(MenuPrint()));
    249   Menu->addSeparator();
    250   Menu->addAction("Paste service", this, SLOT(MenuPasteService()));
    251417  Menu->addAction("Plot help", this, SLOT(MenuPlotHelp()));
    252 
    253   // DIM client
    254   if (!DIMService.isEmpty()) AddService(DIMService, Index);
    255 }
    256 
    257 //
     418}
     419
    258420// Destructor (items with parent widget are automatically deleted)
    259 //
    260 EddPlot::~EddPlot() {
    261 
    262   for (int i=0; i<Items.size(); i++) {
    263     Handler->Unsubscribe(Items[i].Name);
    264     delete Items[i].Signal;
    265   }
    266 
     421EddBasePlot::~EddBasePlot() {
     422
     423  for (int i=0; i<Items.size(); i++) delete Items[i].Signal;
    267424  delete Grid;
    268   delete Mutex;
    269 }
    270 
    271 //
    272 // Add history service to plot
    273 //
    274 void EddPlot::AddService(QString Name, int Index) {
    275 
    276   // Lock before accessing Items list
    277   QMutexLocker Locker(Mutex);
    278 
    279   // Check if already subscribed to service
    280   for (int i=0; i<Items.size(); i++) {
    281     if (Name == Items[i].Name && Index == Items[i].Index) {
    282       QMessageBox::warning(this, "Edd Message",Name+" ("+QString::number(Index)+") already present",QMessageBox::Ok);
    283       return;
    284     }
    285   } 
    286  
    287   // Generate new curve and subscribe to service
    288   struct PlotItem New;
    289 
    290   New.Name = Name;
    291   New.Signal = new QwtPlotCurve;
    292   New.Signal->attach(this);
    293   New.Signal->setTitle(Name+"("+QString::number(Index)+")");
    294   New.Signal->setPen(QColor(LineColors[Items.size() % (sizeof(LineColors)/sizeof(Qt::GlobalColor))]));
    295   New.SizeLimit = 5000;
    296   New.Index = Index;
    297 
    298   Items.append(New);
    299   Handler->Subscribe(Name);
    300 }
    301 
    302 // Update widget (must happen in GUI thread)
    303 void EddPlot::Update(QString Name, int Time, QByteArray, QString Format, QString Text) {
    304 
    305   // Lock before accessing Items list
    306   QMutexLocker Locker(Mutex);
    307 
    308   // Determine which plot item this call belongs to
    309   int ItemNo;
    310   for (ItemNo=0; ItemNo<Items.size(); ItemNo++) if (Items[ItemNo].Name == Name) {
    311 
    312         // Check if service available
    313         if (Time == -1) {
    314           setStatusTip(QString("%1:  unavailable").arg(Name));
    315           return;
    316         }
    317  
    318         // If size limit reached, clear buffer
    319     if (Items[ItemNo].x.size() > Items[ItemNo].SizeLimit) {
    320           Items[ItemNo].x.clear();
    321           Items[ItemNo].y.clear();
    322     }
    323 
    324         // If buffer empty, request new history buffer
    325     if (Items[ItemNo].x.isEmpty()) {
    326           int Time, Size;
    327           void *Data;
    328 
    329           class EvidenceHistory *HistClass = Handler->GetHistory(Items[ItemNo].Name);
    330          
    331           if (HistClass->GetHistory()) {
    332         double Smallest = DBL_MAX, Largest = DBL_MIN;
    333                 double Number=0;
    334                 while (HistClass->Next(Time, Size, Data)) {
    335                   switch (Format[0].toUpper().toAscii()) {
    336                 case 'I':
    337                         case 'L':  Number = *((int *) Data + Items[ItemNo].Index);   break;
    338                 case 'S':  Number = *((short *) Data + Items[ItemNo].Index);   break;
    339                 case 'F':  Number = *((float *) Data + Items[ItemNo].Index);   break;
    340                 case 'D':  Number = *((double *) Data + Items[ItemNo].Index);   break;
    341                 case 'X':  Number = *((long long *) Data + Items[ItemNo].Index);   break;
    342                 default: break;
    343                   }
    344                   Items[ItemNo].x.append(Time);
    345                   Items[ItemNo].y.append(Number);
    346                  
    347           if (Largest < Items[ItemNo].y.last()) Largest = Items[ItemNo].y.last();
    348           if (Smallest > Items[ItemNo].y.last()) Smallest = Items[ItemNo].y.last();
    349                 }
    350 
    351         Items[ItemNo].Smallest = Smallest;
    352         Items[ItemNo].Largest = Largest;
    353 
    354                 // Local buffer always at least twice as large as history
    355                 if (Items[ItemNo].SizeLimit < 2*Items[ItemNo].x.size()) {
    356                   Items[ItemNo].SizeLimit = 2*Items[ItemNo].x.size();
    357                 }               
    358           }
    359         }
    360 
    361     // Append data
    362         QString Txt = Text;
    363         Txt = Txt.section(' ', Items[ItemNo].Index, Items[ItemNo].Index);
    364     Items[ItemNo].x.append(Time);
    365     Items[ItemNo].y.append(atof(Txt.toAscii().data()));
    366 
    367     // Update largest and smallest value   
    368     if (Items[ItemNo].y.last() > Items[ItemNo].Largest) Items[ItemNo].Largest = Items[ItemNo].y.last();
    369     if (Items[ItemNo].y.last() < Items[ItemNo].Smallest) Items[ItemNo].Smallest = Items[ItemNo].y.last();   
    370 
    371     // Update status tip
    372     QDateTime Timex = QDateTime::fromTime_t(Time);
    373     setStatusTip(QString("%1:  Last update %2   Format '%3'").arg(Name).arg(Timex.toString()).arg(Format));
    374   }
    375 
    376   UpdatePlot();
    377 }
    378 
    379 //
     425}
     426
    380427// Update all curves in plot
    381 //
    382 void EddPlot::UpdatePlot() {
     428void EddBasePlot::UpdatePlot() {
    383429
    384430  double Lower = axisScaleDiv(QwtPlot::xBottom)->lowerBound();
     
    394440  }
    395441  else setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine);
    396 
    397   // Lock before accessing Items list
    398   QMutexLocker Locker(Mutex);
    399442
    400443  for (int ItemNo=0; ItemNo<Items.size(); ItemNo++) {
     
    447490}
    448491
    449 // Add text indicating time range to plot
    450 void EddPlot::paintEvent(QPaintEvent *) {
    451 
    452   QString Text;
    453   QFont Font;
    454   QPainter Painter(this);
    455  
    456   Text = QDateTime::fromTime_t((int) axisScaleDiv(QwtPlot::xBottom)->lowerBound()).toString("d-MMM-yyyy hh:mm:ss") + " to " + QDateTime::fromTime_t((int) axisScaleDiv(QwtPlot::xBottom)->upperBound()).toString("d-MMM-yyyy hh:mm:ss");
    457 
    458   Font.setPointSize(6); 
    459   Painter.setFont(Font);
    460   Painter.drawText(0, height(),Text);
     492// Append curve to plot
     493QwtPlotCurve *EddBasePlot::NewCurve(QwtText Title) {
     494
     495  struct PlotItem N;
     496
     497  N.Signal = new QwtPlotCurve;
     498  N.Signal->attach(this);
     499  N.Signal->setTitle(Title);
     500  N.Signal->setPen(QColor(LineColors[Items.size() % (sizeof(LineColors)/sizeof(Qt::GlobalColor))]));
     501  N.Largest = DBL_MIN;
     502  N.Smallest = DBL_MAX; 
     503  Items.append(N);
     504 
     505  return N.Signal;
     506}
     507
     508// Clear curve data
     509void EddBasePlot::ClearCurve(unsigned int Item) {
     510
     511  if (Item >= (unsigned int) Items.size()) return;
     512 
     513  Items[Item].x.clear();
     514  Items[Item].y.clear();
     515}
     516
     517// Append data point
     518void EddBasePlot::AddPoint(unsigned int Item, double x, double y) {
     519
     520  if (Item >= (unsigned int) Items.size()) return;
     521 
     522  Items[Item].x.append(x);
     523  Items[Item].y.append(y);
     524
     525  if (y > Items[Item].Largest) Items[Item].Largest = y;
     526  if (y < Items[Item].Smallest) Items[Item].Smallest = y;   
    461527}
    462528
    463529// Rescale plot in case selection has been made outside the canvas
    464 void EddPlot::MouseSelection(const QPolygon &P) {
     530void EddBasePlot::MouseSelection(const QPolygon &P) {
    465531 
    466532  QwtDoubleInterval xPlot, xMouse, yPlot, yMouse;
     
    520586}
    521587
    522 
    523 //
    524588// Reset graph axes to autoscale when fully unzoomed
    525 //
    526 void EddPlot::HandleZoom(const QwtDoubleRect &) {
     589void EddBasePlot::HandleZoom(const QwtDoubleRect &) {
    527590
    528591  if(Zoomer->zoomRectIndex() == 0) {
     
    531594  }
    532595}
    533 
    534 //
    535 // Drag and drop methods
    536 //
    537 
    538 void EddPlot::dragEnterEvent(QDragEnterEvent *Event) {
    539    
    540   if (Event->mimeData()->hasFormat("Edd/Service")) Event->acceptProposedAction();
    541 }
    542 
    543 void EddPlot::dropEvent(QDropEvent *Event) {
    544 
    545   QByteArray D(Event->mimeData()->data("Edd/Service"));
    546   AddService(D.left(D.lastIndexOf(' ')), D.right(D.size()-D.lastIndexOf(' ')).toInt());
    547 }
    548596   
    549597// Opening context menu
    550 void EddPlot::contextMenuEvent(QContextMenuEvent *Event) {
     598void EddBasePlot::contextMenuEvent(QContextMenuEvent *Event) {
    551599
    552600  Menu->exec(Event->globalPos());
    553601}
    554602
    555 // Drag&Drop method
    556 void EddPlot::LegendClicked(QwtPlotItem *Item) {
    557 
    558 
    559   QString D(Item->title().text());
    560   D.replace('(',' ').chop(1);
    561  
    562   QDrag *Drag = new QDrag(this);
    563   QMimeData *MimeData = new QMimeData;
    564   QByteArray Data;
    565   MimeData->setData("Edd/Service", Data.append(D));
    566   Drag->setMimeData(MimeData);
    567   Drag->exec();
    568 }
    569 
    570 
    571603// Zoom completely out
    572 void EddPlot::MenuZoomOut() {
     604void EddBasePlot::MenuZoomOut() {
    573605
    574606  Zoomer->zoom(0);
     
    576608}
    577609
    578 // Remove all items except last
    579 void EddPlot::MenuSingleTrace() {
    580 
    581   // Lock before accessing Items list
    582   QMutexLocker Locker(Mutex);
     610// Remove all items except one
     611void EddBasePlot::MenuSingleTrace() {
    583612
    584613  while (Items.size() > 1) { 
    585     Handler->Unsubscribe(Items.last().Name);
     614        DeleteCurve(Items.last().Signal);
    586615    delete Items.last().Signal;
    587616    Items.takeLast();
     
    591620
    592621// Save data of plot as test
    593 void EddPlot::MenuSaveASCII() {
     622void EddBasePlot::MenuSaveASCII() {
    594623  QString Filename = QFileDialog::getSaveFileName(this,
    595624     "Filename", ".", "Text files (*.txt *.ascii *.asc);;All files (*)");
     
    601630    return;
    602631  }
    603  
    604   // Lock before accessing Items list
    605   QMutexLocker Locker(Mutex);
     632
     633   // Write x and y data for all signals to file
    606634  QTextStream Stream(&File);
    607635
    608    // Write x and y data for all signals to file
    609636  for (int ItemNo=0; ItemNo<Items.size(); ItemNo++) {
    610     Stream << QString("# ") + Items[ItemNo].Name + ".hist" << endl;
     637    Stream << QString("# ") + Items[ItemNo].Signal->title().text() + ".hist" << endl;
    611638    for (int i=0; i<Items[ItemNo].Signal->dataSize(); i++) {
    612639      Stream << (int) Items[ItemNo].x.at(i) << " " << Items[ItemNo].Signal->y(i) << endl;
     
    616643
    617644// Print plot
    618 void EddPlot::MenuPrint() {
     645void EddBasePlot::MenuPrint() {
    619646
    620647  QPrinter *Printer = new QPrinter;
     
    629656
    630657// Save plot as image
    631 void EddPlot::MenuSave() {
     658void EddBasePlot::MenuSave() {
    632659
    633660  QString Filename = QFileDialog::getSaveFileName(this,
     
    642669}
    643670
    644 // Add new service by pasting name
    645 void EddPlot::MenuPasteService() {
    646 
    647   const QMimeData *D = QApplication::clipboard()->mimeData();
    648   if (!D->hasFormat("Edd/Service")) return;
    649  
    650   QByteArray E(D->data("Edd/Service"));
    651   AddService(E.left(E.lastIndexOf(' ')), E.right(E.size()-E.lastIndexOf(' ')).toInt());
    652 }
    653 
    654671// Help text
    655 void EddPlot::MenuPlotHelp() {
     672void EddBasePlot::MenuPlotHelp() {
    656673
    657674  QMessageBox::about(this, "Edd - Plot navigation",
     
    667684}
    668685
    669 
    670686//////////////////////////////////////
    671687// History text box for DIM service //
    672688//////////////////////////////////////
    673689
    674 //
    675690// Constructor
    676 //
    677691EddText::EddText(QString Name, bool Pure, QWidget *P):
    678692        QTextEdit(P), Name(Name), Pure(Pure) {
     
    724738
    725739  // Check if service available
    726   if (Time == -1) {
    727         setStatusTip(QString("%1:  unavailable").arg(Name));
     740  if (!SetStatus(this, Name, Time, Format)) {
    728741    Pal.setColor(QPalette::Base, Qt::lightGray);
    729742        setPalette(Pal);
     
    744757  }
    745758  else  if (Format == "C") insertPlainText(Text);
    746 
    747   // Update status tip
    748   setStatusTip(QString("%1:  Last update %2  Format '%3'").arg(Name).arg(Timex.toString()).arg(Format));
    749759}
    750760
     
    883893}
    884894
    885 
     895//
     896//
     897// ====== FACT specific part ======
     898//
     899//
     900
     901////////////////////////
     902// Event oscilloscope //
     903////////////////////////
     904
     905// Constructor
     906EventScope::EventScope(QWidget *P): EddBasePlot(P), PixelMap("../../config/PixelMap.txt", false) {
     907
     908  Name = "Feedback/EventData";
     909
     910  Tmpfile = tmpfile();
     911  if(Tmpfile == NULL) {
     912    QMessageBox::warning(this, "Edd Message", "Could not open temporary file.", QMessageBox::Ok);
     913  }
     914
     915  // Open file with RawDataCTX
     916  RD = new RawDataCTX(true);
     917  ErrCode = CTX_NOTOPEN;
     918
     919  // Context menu
     920  PhysPipeAction = new QAction("Plot physical pipeline", this);
     921  PhysPipeAction->setCheckable(true);
     922  connect(PhysPipeAction, SIGNAL(triggered()), SLOT(PlotTraces()));
     923  Menu->insertAction(StripAction, PhysPipeAction);
     924  Menu->removeAction(StripAction);
     925
     926  // Initial trace
     927  AddTrace(0,0,0);
     928
     929  // Connect to DIM handler
     930  if (connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) {
     931    printf("Failed connection for %s\n", Name.toAscii().data());
     932  }
     933  Handler->Subscribe(Name);
     934}
     935
     936// Destructor (items with parent widget are automatically deleted)
     937EventScope::~EventScope() {
     938
     939  Handler->Unsubscribe(Name);
     940  while (!List.isEmpty()) DeleteCurve(List.last().Signal);
     941  delete RD;
     942  if (Tmpfile != NULL) fclose(Tmpfile);
     943
     944
     945// Add trace
     946void EventScope::AddTrace(int Board, int Chip, int Channel) {
     947
     948  struct ItemDetails N;
     949 
     950  N.Signal = NewCurve(QString::number(Board)+","+QString::number(Chip)+","+ QString::number(Channel)+ " (" + DRS_to_Pixel(Board, Chip, Channel).c_str() + ")");
     951  N.Board = Board;
     952  N.Chip = Chip;
     953  N.Channel = Channel;
     954  N.Trigger = new QwtPlotMarker();
     955  N.Trigger->setSymbol(QwtSymbol(QwtSymbol::Diamond, QBrush(N.Signal->pen().color()), N.Signal->pen(), QSize(10,10)));
     956  N.Trigger->attach(this);
     957
     958  if (List.isEmpty()) {
     959    QPen Pen = N.Signal->pen();
     960        Pen.setWidth(2);
     961        N.Signal->setPen(Pen);
     962  }
     963  List.append(N);
     964   
     965  PlotTraces();
     966}
     967
     968// Update last trace (to reflect current setting of spin boxes in DAQ page)
     969void EventScope::UpdateFirst(int Board, int Chip, int Channel) {
     970
     971  if (List.isEmpty()) return;
     972 
     973  List.first().Signal->setTitle(QString::number(Board)+","+QString::number(Chip)+","+ QString::number(Channel) + " (" + DRS_to_Pixel(Board, Chip, Channel).c_str() + ")");
     974  List.first().Board = Board;
     975  List.first().Chip = Chip;
     976  List.first().Channel = Channel;
     977   
     978  PlotTraces();
     979}
     980 
     981// Update event buffer
     982void EventScope::Update(QString Name, int Time, QByteArray Data, QString Format, QString) {
     983
     984  if (Name != this->Name) return;
     985
     986  // Check if service available
     987  if (!SetStatus(this, Name, Time, Format)) return;
     988  if (Data.size() < (int) sizeof(RunHeader)) return;
     989 
     990  // Open tempory file and write event data to this file
     991  QTemporaryFile File;
     992  if (!File.open()) {
     993        QMessageBox::warning(this, "Edd Message","Could not open temporary file.",QMessageBox::Ok);
     994        return;
     995  }
     996  if (File.write(Data) == -1) {
     997        QMessageBox::warning(this, "Edd Message","Could not write data to temporary file.",QMessageBox::Ok);
     998        return;
     999  }
     1000
     1001  // Prepare temporary file for run header 
     1002  ftruncate(fileno(Tmpfile), 0);
     1003  rewind(Tmpfile);
     1004
     1005  // Open file with RawDataCTX
     1006  switch (ErrCode = RD->OpenDataFile(File.fileName().toAscii().data(), Tmpfile)) {
     1007    case CTX_FOPEN:             QMessageBox::warning(this, "Edd Message","Could not open file.",QMessageBox::Ok);
     1008                                                return;
     1009    case CTX_RHEADER:   QMessageBox::warning(this, "Edd Message","Could not read run header.",QMessageBox::Ok);
     1010                                        return;
     1011    case CTX_BSTRUCT:   QMessageBox::warning(this, "Edd Message","Could not read board structures.",QMessageBox::Ok);
     1012                                                return;
     1013        default: break;
     1014  }
     1015
     1016  // Emit signal containing run header
     1017  rewind(Tmpfile);
     1018  QTextStream Stream(Tmpfile);
     1019  emit(RunHeaderChanged(Stream.readAll()));
     1020
     1021  // Prepare temporary file for event header 
     1022  ftruncate(fileno(Tmpfile), 0);
     1023  rewind(Tmpfile);
     1024
     1025  if (RD->ReadEvent(0, Tmpfile) != CTX_OK) {
     1026    QMessageBox::warning(this, "Edd Warning","Could not read event.",QMessageBox::Ok);
     1027    return;
     1028  }
     1029
     1030  // Emit signal containing run header
     1031  rewind(Tmpfile);
     1032  emit(EventHeaderChanged(Stream.readAll()));
     1033
     1034  PlotTraces();
     1035}
     1036
     1037// Update curves
     1038void EventScope::PlotTraces() {
     1039
     1040  double x,y;
     1041  unsigned int Cell, Trig;
     1042 
     1043  // Only process if valid data in RawDataCTX class
     1044  if (ErrCode != CTX_OK) return;
     1045 
     1046  // Set x axis title
     1047  if (PhysPipeAction->isChecked()) setAxisTitle(QwtPlot::xBottom, "Time from start of pipeline (ns)");
     1048  else setAxisTitle(QwtPlot::xBottom, "Time from trigger minus one revolution (ns)");
     1049 
     1050  // Loop through event data
     1051  RunHeader *R = RD->RHeader;
     1052  for (int i=0; i<List.size(); i++) {
     1053
     1054        ClearCurve(i);
     1055
     1056        // Check if current event contains requested trace
     1057    if (List[i].Board>=R->NBoards || List[i].Chip>=R->NChips || List[i].Channel>=R->NChannels) continue;
     1058
     1059        // Set trigger marker visibility
     1060        List[i].Trigger->setVisible(PhysPipeAction->isChecked());
     1061       
     1062        // Determine trigger cell
     1063        Trig = *((int *) RD->Data + List[i].Board*R->NChips + List[i].Chip);
     1064
     1065        for (unsigned int j=0; j<R->Samples; j++) {
     1066
     1067          if (PhysPipeAction->isChecked()) Cell = (j + Trig) % 1024;
     1068          else Cell = j;
     1069
     1070          x = j / RD->BStruct[List[i].Board].NomFreq;
     1071          y = *((short *) (RD->Data + R->NBoards*R->NChips*sizeof(int)) +
     1072                List[i].Board*R->NChips*R->NChannels*R->Samples + List[i].Chip*R->NChannels*R->Samples +
     1073                List[i].Channel*R->Samples + Cell) * RD->BStruct[List[i].Board].ScaleFactor;
     1074
     1075          AddPoint(i, x, y);
     1076         
     1077          // Set trigger point indicator
     1078          if (Trig == j/*+R->Offset*/) List[i].Trigger->setValue(x, y);
     1079    }
     1080  }
     1081
     1082  UpdatePlot();
     1083}
     1084
     1085// Remove list entry
     1086void EventScope::DeleteCurve(QwtPlotCurve *Curve) {
     1087
     1088  for (int i=0; i<List.size(); i++) if (List[i].Signal == Curve) {
     1089        delete List[i].Trigger;
     1090    List.removeAt(i);
     1091  }
     1092}
     1093
     1094//
     1095// Tab page classes
     1096//
     1097
     1098// Environment page
     1099TP_Environment::TP_Environment() {
     1100
     1101  QGridLayout *Layout = new QGridLayout(this);
     1102
     1103  // Status display
     1104  EddLineDisplay *Line = new EddLineDisplay("ARDUINO/Status");
     1105  Line->setMaximumWidth(200);
     1106  Layout->addWidget(Line, 0, 0, 1, 3);     
     1107
     1108  // Generate plot and data displays
     1109  EddPlot *Plot = new EddPlot();
     1110  for (int i=0; i<10; i++) {
     1111    Line = new EddLineDisplay("ARDUINO/Data", i);
     1112    Layout->addWidget(Line, i%5+1, i/5, 1, 1);
     1113    Plot->AddService("ARDUINO/Data", i);
     1114  }
     1115  Layout->addWidget(Plot, 0, 3, 6, 4);     
     1116
     1117  // Night sky monitor
     1118  Line = new EddLineDisplay("SQM/NSB");
     1119  Layout->addWidget(Line, 6, 0, 1, 1);         
     1120}
     1121
     1122// Bias page
     1123TP_Bias::TP_Bias() {
     1124
     1125  QGridLayout *Layout = new QGridLayout(this);
     1126  EddLineDisplay *Line;
     1127 
     1128  EddPlot *Plot = new EddPlot();
     1129  Plot->setMinimumWidth(400);
     1130  for (int i=0; i<18; i++) {
     1131    Line = new EddLineDisplay("Bias/VOLT/ID00", i);
     1132    Layout->addWidget(Line, i%9+1, 0+i/9, 1, 1);
     1133    Plot->AddService("Bias/VOLT/ID00", i);
     1134
     1135    Line = new EddLineDisplay("Bias/VOLT/ID00", i+32);
     1136    Layout->addWidget(Line, i%9+1, 2+i/9, 1, 1);
     1137    Plot->AddService("Bias/VOLT/ID00",i+32);
     1138  }
     1139
     1140  Layout->addWidget(Plot, 0, 4, 12, 3);
     1141  Line = new EddLineDisplay("Bias/Status");
     1142  Line->setMaximumWidth(200);
     1143  Layout->addWidget(Line, 0, 0, 1, 3);     
     1144
     1145  EddText *Text = new EddText("Bias/Textout", true);
     1146  Text->setFixedWidth(400);
     1147  Layout->addWidget(Text, 10, 0, 4, 4);     
     1148}
     1149
     1150// Feedback page
     1151TP_Feedback::TP_Feedback() {
     1152
     1153  QGridLayout *Layout = new QGridLayout(this);
     1154  EddLineDisplay *Line;
     1155
     1156  EddPlot *Plot = new EddPlot();
     1157  for (int i=0; i<36; i++) {
     1158    Line = new EddLineDisplay("Feedback/Average", i);
     1159    Layout->addWidget(Line, i%9+1, 0+i/9, 1, 1);
     1160    Plot->AddService("Feedback/Average", i);
     1161  }
     1162  Layout->addWidget(Plot, 0, 4, 11, 3);
     1163
     1164  //Graph = new EddPlot();
     1165  //for (int i=0; i<36; i++) {
     1166    //Text = Text.sprintf("Feedback/Sigma/ID%.2d/%.2d-%.3d",i/16, (i%16)/8, i%8);
     1167    //Graph->AddService(Text);
     1168  //}
     1169  //FeedbackLayout->addWidget(Graph, 10, 0, 10, 3);
     1170
     1171  Line = new EddLineDisplay("Feedback/Status");
     1172  Line->setMaximumWidth(200);
     1173  Layout->addWidget(Line, 0, 0, 1, 3);     
     1174  Line = new EddLineDisplay("Feedback/Count");
     1175  Layout->addWidget(Line, 0, 3, 1, 1);     
     1176
     1177  QWidget *Button = new QPushButton("Details");
     1178  Layout->addWidget(Button, 10, 0, 1, 1);     
     1179  connect(Button, SIGNAL(pressed()), SLOT(FeedbackDetails()));
     1180
     1181}
     1182
     1183void TP_Feedback::FeedbackDetails() {
     1184
     1185  EddLineDisplay *Line;
     1186  QWidget *Widget = new QWidget();
     1187  QGridLayout *Layout = new QGridLayout(Widget);
     1188  EddPlot *Plot = new EddPlot();
     1189  for (int i=0; i<36; i++) {
     1190    Line = new EddLineDisplay("Feedback/Sigma", i);
     1191    Layout->addWidget(Line, i%9+1, 0+i/9, 1, 1);
     1192    Plot->AddService("Feedback/Sigma", i);
     1193  }
     1194  Layout->addWidget(Plot, 0, 4, 11, 3);
     1195 
     1196  Widget->show();
     1197}
     1198
     1199// DAQ page
     1200TP_DAQ::TP_DAQ() {
     1201
     1202  QGridLayout *Layout = new QGridLayout(this);
     1203
     1204  // Event scope
     1205  Scope = new EventScope;
     1206  Scope->setMinimumWidth(700);
     1207
     1208  // Text boxes for run and event header
     1209  RunHeaderDisplay = new QPlainTextEdit();
     1210  EventHeaderDisplay = new QPlainTextEdit();
     1211  RunHeaderDisplay->setReadOnly(true);
     1212  EventHeaderDisplay->setReadOnly(true);
     1213
     1214  // Tab widget
     1215  QTabWidget *TabWidget = new QTabWidget();
     1216  TabWidget->addTab(Scope, "&Signals");
     1217  TabWidget->addTab(RunHeaderDisplay, "&Run Header");
     1218  TabWidget->addTab(EventHeaderDisplay, "&Event Header");
     1219  Layout->addWidget(TabWidget, 0, 1, 3, 3);
     1220
     1221  connect(Scope, SIGNAL(RunHeaderChanged(QString)), RunHeaderDisplay, SLOT(setPlainText(QString)));
     1222  connect(Scope, SIGNAL(EventHeaderChanged(QString)), EventHeaderDisplay, SLOT(setPlainText(QString)));
     1223
     1224  // Channel number
     1225  Channel = new QSpinBox;
     1226  connect(Channel, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
     1227  Channel->setToolTip("DRS channel number");
     1228
     1229  // Chip number
     1230  Chip = new QSpinBox;
     1231  connect(Chip, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
     1232  Chip->setToolTip("DRS chip number");
     1233
     1234  // Board number
     1235  Board = new QSpinBox;
     1236  connect(Board, SIGNAL(valueChanged(int)), SLOT(UpdateScope(int)));
     1237  Board->setToolTip("DRS board number");
     1238
     1239  // Pixel ID
     1240  PixelID = new QLineEdit;
     1241  PixelID->setMaximumWidth(60);
     1242  connect(PixelID, SIGNAL(returnPressed()), SLOT(TranslatePixelID()));
     1243  PixelID->setToolTip("Pixel identification");
     1244 
     1245  // Layout of pixel addressing widgets
     1246  QFormLayout *FormLayout = new QFormLayout();
     1247  FormLayout->setRowWrapPolicy(QFormLayout::WrapAllRows);
     1248  FormLayout->addRow("Channel", Channel);
     1249  FormLayout->addRow("Chip", Chip);
     1250  FormLayout->addRow("Board", Board);
     1251  FormLayout->addRow("Pixel ID", PixelID);
     1252  Layout->addLayout(FormLayout, 0, 0);
     1253 
     1254  // Add trace permanently
     1255  QPushButton *Button = new QPushButton("Keep trace");
     1256  Button->setToolTip("Keep trace in display");
     1257  Button->setMaximumWidth(80);
     1258  Layout->addWidget(Button, 2, 0);
     1259  connect(Button, SIGNAL(clicked()), SLOT(KeepCurrent()));
     1260}
     1261
     1262void TP_DAQ::TranslatePixelID() {
     1263 
     1264  if (Scope->Pixel_to_DRSboard(PixelID->text().toStdString()) == 999999999) {
     1265        QMessageBox::warning(this, "Edd Message","Pixel ID unknown.",QMessageBox::Ok);
     1266  }
     1267  else {
     1268    Board->setValue(Scope->Pixel_to_DRSboard(PixelID->text().toStdString()));
     1269    Chip->setValue(Scope->Pixel_to_DRSchip(PixelID->text().toStdString()));
     1270    Channel->setValue(Scope->Pixel_to_DRSchannel(PixelID->text().toStdString()));
     1271  }
     1272}
     1273
     1274// Update event scope
     1275void TP_DAQ::KeepCurrent() {
     1276
     1277  Scope->AddTrace(Board->value(), Chip->value(), Channel->value());
     1278}
     1279
     1280// Update event scope
     1281void TP_DAQ::UpdateScope(int) {
     1282
     1283  // Update pixel ID
     1284  PixelID->setText(Scope->DRS_to_Pixel(Board->value(), Chip->value(), Channel->value()).c_str());
     1285  // Update first trace
     1286  Scope->UpdateFirst(Board->value(), Chip->value(), Channel->value());
     1287}
     1288
     1289// DAQ page
     1290TP_Evidence::TP_Evidence() {
     1291
     1292  QGridLayout *Layout = new QGridLayout(this);
     1293  EddLineDisplay *Line;
     1294  EddText *Text;
     1295 
     1296  Line = new EddLineDisplay("Alarm/Status");
     1297  Line->setMaximumWidth(200);
     1298  Layout->addWidget(Line, 0, 0, 1, 2);     
     1299
     1300  Line = new EddLineDisplay("Alarm/MasterAlarm");
     1301  Layout->addWidget(Line, 0, 1, 1, 1);
     1302
     1303  Text = new EddText("Alarm/Summary", true);
     1304  Text->Accumulate = false;
     1305  Text->setMaximumWidth(200);
     1306  Text->setMaximumHeight(150);
     1307  Layout->addWidget(Text, 1, 0, 1, 2);
     1308
     1309  Line = new EddLineDisplay("DColl/Status");
     1310  Line->setMaximumWidth(200);
     1311  Layout->addWidget(Line, 3, 0, 1, 2);     
     1312
     1313  Line = new EddLineDisplay("DColl/DataSizekB");
     1314  Layout->addWidget(Line, 4, 0, 1, 1);
     1315
     1316  Line = new EddLineDisplay("DColl/LogSizekB");
     1317  Layout->addWidget(Line, 4, 1, 1, 1);
     1318
     1319  Line = new EddLineDisplay("DColl/CurrentFile");
     1320  Line->setMaximumWidth(400);
     1321  Layout->addWidget(Line, 5, 0, 1, 3);
     1322
     1323  Line = new EddLineDisplay("Config/Status");
     1324  Line->setMaximumWidth(200);
     1325  Layout->addWidget(Line, 6, 0, 1, 2);     
     1326
     1327  Line = new EddLineDisplay("Config/ModifyTime");
     1328  Line->setMaximumWidth(200);
     1329  Line->ShowAsTime = true;
     1330  Layout->addWidget(Line, 7, 0, 1, 1);
     1331
     1332  QPushButton *Button = new QPushButton();
     1333  Button->setText("Start DIM browser");
     1334  connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser()));
     1335  Layout->addWidget(Button, 7, 1, 1, 1);
     1336
     1337  Line = new EddLineDisplay("Edd/Rate_kBMin");
     1338  Layout->addWidget(Line, 8, 0, 1, 1);
     1339  Line = new EddLineDisplay("Edd/Total_MB");
     1340  Layout->addWidget(Line, 8, 1, 1, 1);
     1341}
     1342 
     1343// Start DIM Browser
     1344void TP_Evidence::StartDIMBrowser() {
     1345
     1346  QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/");
     1347}
     1348
     1349 
    8861350//--------------------------------------------------------------------
    8871351//*************************** Main GUI *******************************
     
    8911355//
    8921356GUI::GUI() {
    893  
     1357
    8941358  Handler = new EddDim();
    8951359 
     
    9011365  setWindowTitle("Edd - Evidence Data Display");
    9021366
    903   EddLineDisplay *Value;
    904   EddPlot *Graph;
    905   EddText *Textout;
    906   QString Text;
    907 
    908    // TextBox for value
    909  
    910 
    911   // Clock (updated every second)
    912   //Clock = new QwtAnalogClock(Central);
    913   //Clock->scaleDraw()->setPenWidth(3);
    914   //Clock->setLineWidth(6);
    915   //Clock->setFrameShadow(QwtDial::Sunken);
    916   //Clock->setGeometry(0,0,10,10);
    917   //Clock->setTime();
    918  
    919   //QTimer *Timer = new QTimer(Clock);
    920   //Timer->connect(Timer, SIGNAL(timeout()), Clock, SLOT(setCurrentTime()));
    921   //Timer->start(1000);
    922 
    923   MainWidget = new QWidget();
    924   MainLayout = new QGridLayout(MainWidget);
    925 
    926   Value = new EddLineDisplay("Alarm/Status");
    927   Value->setMaximumWidth(200);
    928   MainLayout->addWidget(Value, 0, 0, 1, 2);     
    929 
    930   Value = new EddLineDisplay("Alarm/MasterAlarm");
    931   MainLayout->addWidget(Value, 0, 1, 1, 1);
    932 
    933   Textout = new EddText("Alarm/Summary", true);
    934   Textout->Accumulate = false;
    935   Textout->setMaximumWidth(200);
    936   Textout->setMaximumHeight(150);
    937   MainLayout->addWidget(Textout, 1, 0, 1, 2);
    938 
    939   Value = new EddLineDisplay("DColl/Status");
    940   Value->setMaximumWidth(200);
    941   MainLayout->addWidget(Value, 3, 0, 1, 2);     
    942 
    943   Value = new EddLineDisplay("DColl/DataSizekB");
    944   MainLayout->addWidget(Value, 4, 0, 1, 1);
    945 
    946   Value = new EddLineDisplay("DColl/LogSizekB");
    947   MainLayout->addWidget(Value, 4, 1, 1, 1);
    948 
    949   Value = new EddLineDisplay("DColl/CurrentFile");
    950   Value->setMaximumWidth(400);
    951   MainLayout->addWidget(Value, 5, 0, 1, 3);
    952 
    953   Value = new EddLineDisplay("Config/Status");
    954   Value->setMaximumWidth(200);
    955   MainLayout->addWidget(Value, 6, 0, 1, 2);     
    956 
    957   Value = new EddLineDisplay("Config/ModifyTime");
    958   Value->setMaximumWidth(200);
    959   Value->ShowAsTime = true;
    960   MainLayout->addWidget(Value, 7, 0, 1, 1);
    961 
    962   QPushButton *Button = new QPushButton();
    963   Button->setText("Start DIM browser");
    964   connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser()));
    965   MainLayout->addWidget(Button, 7, 1, 1, 1);
    966 
    967   Value = new EddLineDisplay("Edd/Rate_kBMin");
    968   MainLayout->addWidget(Value, 8, 0, 1, 1);
    969   Value = new EddLineDisplay("Edd/Total_MB");
    970   MainLayout->addWidget(Value, 8, 1, 1, 1);
    971 
    972   // Layout of all widgets
    973   //MainLayout->addWidget(Value, 0, 0, 1, 1);
    974   //MainLayout->addWidget(Clock, 0, 1, 1, 1);
    975   //MainLayout->addWidget(Graph, 1, 0, 1, 2);
    976   //MainLayout->setColumnStretch(1, 10);
    977  
    978   //MainLayout->addWidget(Clock, 0, 1, 1, 1);
    979   //MainLayout->addWidget(Graph1, 2, 0, 1, 2);
    980 
    981   // Feedback page
    982   FeedbackWidget = new QWidget();
    983   FeedbackLayout = new QGridLayout(FeedbackWidget);
    984   Graph = new EddPlot();
    985   for (int i=0; i<36; i++) {
    986     Value = new EddLineDisplay("Feedback/Average", i);
    987     FeedbackLayout->addWidget(Value, i%9+1, 0+i/9, 1, 1);
    988     Graph->AddService("Feedback/Average", i);
    989   }
    990   FeedbackLayout->addWidget(Graph, 0, 4, 11, 3);
    991 
    992   //Graph = new EddPlot();
    993   //for (int i=0; i<36; i++) {
    994     //Text = Text.sprintf("Feedback/Sigma/ID%.2d/%.2d-%.3d",i/16, (i%16)/8, i%8);
    995     //Graph->AddService(Text);
    996   //}
    997   //FeedbackLayout->addWidget(Graph, 10, 0, 10, 3);
    998 
    999   Value = new EddLineDisplay("Feedback/Status");
    1000   Value->setMaximumWidth(200);
    1001   FeedbackLayout->addWidget(Value, 0, 0, 1, 3);     
    1002   Value = new EddLineDisplay("Feedback/Count");
    1003   FeedbackLayout->addWidget(Value, 0, 3, 1, 1);     
    1004 
    1005   QWidget *Value1 = new QPushButton("Details");
    1006   FeedbackLayout->addWidget(Value1, 10, 0, 1, 1);     
    1007   connect(Value1, SIGNAL(pressed()), this, SLOT(FeedbackDetails()));
    1008  
    1009 
    1010   // Bias voltage page
    1011   BiasWidget = new QWidget();
    1012   BiasLayout = new QGridLayout(BiasWidget);
    1013   Graph = new EddPlot();
    1014   for (int i=0; i<18; i++) {
    1015     Value = new EddLineDisplay("Bias/VOLT/ID00", i);
    1016     BiasLayout->addWidget(Value, i%9+1, 0+i/9, 1, 1);
    1017     Graph->AddService("Bias/VOLT/ID00", i);
    1018 
    1019     Value = new EddLineDisplay("Bias/VOLT/ID00", i+32);
    1020     BiasLayout->addWidget(Value, i%9+1, 2+i/9, 1, 1);
    1021     Graph->AddService("Bias/VOLT/ID00",i+32);
    1022   }
    1023 
    1024   BiasLayout->addWidget(Graph, 0, 4, 12, 3);
    1025   Value = new EddLineDisplay("Bias/Status");
    1026   Value->setMaximumWidth(200);
    1027   BiasLayout->addWidget(Value, 0, 0, 1, 3);     
    1028 
    1029   Textout = new EddText("Bias/Textout", true);
    1030   Textout->setFixedWidth(400);
    1031   BiasLayout->addWidget(Textout, 10, 0, 4, 4);     
    1032 
    1033   // Environment page
    1034   EnvironmentWidget = new QWidget();
    1035   EnvironmentLayout = new QGridLayout(EnvironmentWidget);
    1036   Value = new EddLineDisplay("ARDUINO/Status");
    1037   Value->setMaximumWidth(200);
    1038   EnvironmentLayout->addWidget(Value, 0, 0, 1, 3);     
    1039 
    1040   Graph = new EddPlot();
    1041   for (int i=0; i<10; i++) {
    1042     Value = new EddLineDisplay("ARDUINO/Data", i);
    1043     EnvironmentLayout->addWidget(Value, i%5+1, i/5, 1, 1);
    1044     Graph->AddService("ARDUINO/Data", i);
    1045   }
    1046   EnvironmentLayout->addWidget(Graph, 0, 3, 6, 4);     
    1047 
    1048   Value = new EddLineDisplay("SQM/NSB");
    1049   EnvironmentLayout->addWidget(Value, 6, 0, 1, 1);     
    1050 
    1051   // Tab widget
     1367  // Arrangement in tabs
    10521368  TabWidget = new QTabWidget(Central);
    1053   TabWidget->addTab(BiasWidget, "&Bias");
    1054   TabWidget->addTab(FeedbackWidget, "&Feedback");
    1055   TabWidget->addTab(EnvironmentWidget, "&Environment");
    1056   TabWidget->addTab(MainWidget, "Evidence");
     1369  TabWidget->addTab(new TP_DAQ, "&drsdaq");
     1370  TabWidget->addTab(new TP_Bias, "&Bias");
     1371  TabWidget->addTab(new TP_Feedback, "&Feedback");
     1372  TabWidget->addTab(new TP_Environment, "&Environment");
     1373  TabWidget->addTab(new TP_Evidence, "Evidence");
    10571374
    10581375  // Menu bar
     
    11121429}
    11131430
    1114 // Feedback details page
    1115 void GUI::FeedbackDetails() {
    1116 
    1117   QWidget *Value;
    1118   QWidget *Widget = new QWidget();
    1119   QGridLayout *Layout = new QGridLayout(Widget);
    1120   EddPlot *Graph = new EddPlot();
    1121   for (int i=0; i<36; i++) {
    1122     Value = new EddLineDisplay("Feedback/Sigma", i);
    1123     Layout->addWidget(Value, i%9+1, 0+i/9, 1, 1);
    1124     Graph->AddService("Feedback/Sigma", i);
    1125   }
    1126   Layout->addWidget(Graph, 0, 4, 11, 3);
    1127  
    1128   Widget->show();
    1129 }
    1130 
    1131 // Start DIM Browser
    1132 void GUI::StartDIMBrowser() {
    1133 
    1134   QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/");
    1135 }
    1136 
    11371431// Quit application when clicking close button on window
    11381432void GUI::closeEvent(QCloseEvent *) {
  • Evidence/Edd/Edd.h

    r204 r208  
    1818#include <qwt_symbol.h>
    1919#include <qwt_plot_marker.h>
     20#include <qwt_data.h>
    2021
    2122#include <limits.h>
     
    2425#include "dic.hxx"
    2526#include "Evidence.h"
     27#include "RawDataCTX.h"
     28#include "PixelMap.h"
    2629
    2730#define SVN_REVISION "$Revision$"
     
    3033
    3134QWidget *OpenHistory(char *, int);
    32 
    33 // Time scale for axis
    34 class EddTimeScale: public QwtScaleDraw {
    35 
    36   public:
    37     EddTimeScale() {}
    38 
    39     virtual QwtText label(double v) const {
    40 
    41           // Adapt text format to time span
    42           QString Format;
    43           if (scaleDiv().range() < 60*60) Format = "hh' h\n'mm:ss";
    44           else if (scaleDiv().range() < 24*60*60) Format = "hh:mm";
    45           else if (scaleDiv().range() < 30*24*60*60) Format = "h' h\n'd-MMM";
    46           else Format = "d-MMM'\n'yyyy";
    47 
    48           // Generate text
    49           QwtText Text = QDateTime::fromTime_t((int) v).toString(Format);
    50           QFont Font = Text.font();
    51           Font.setPointSize(7);
    52           Text.setFont(Font);
    53 
    54       return Text;
    55     }
    56 };
    57 
    58                  
    59 // General indicator for DIM service
    60 class EddLineDisplay: public QLineEdit {
    61     Q_OBJECT
    62 
     35bool SetStatus(QWidget *, QString, int, QString, int = -1);
     36
     37// Base class for Edd plot
     38// DeleteCurve() is pure virtual and needs to be implemented iin the application class
     39class EddBasePlot: public QwtPlot {
     40  Q_OBJECT
     41
     42  protected:   
    6343    QMenu *Menu;
    64     QPoint dragStart;
    65     QWidget *LastPlot;
    66        
    67         QString ServiceName;
    68         int Index;
    69        
    70     void mousePressEvent(QMouseEvent *);
    71     void mouseReleaseEvent(QMouseEvent *);
    72     void mouseMoveEvent(QMouseEvent *);
    73        
    74   public:
    75     EddLineDisplay(QString, int=0, QWidget * = NULL);
    76     ~EddLineDisplay();
    77 
    78         bool ShowAsTime;
    79        
    80   private slots:
    81         void Update(QString, int, QByteArray, QString, QString);
    82     void contextMenuEvent(QContextMenuEvent *);   
    83     void MenuOpenHistory();
    84     void MenuCopyService();
    85     void MenuCopyData();
    86 };
    87 
    88 // Graph class for history display
    89 class EddPlot: public QwtPlot {
    90     Q_OBJECT
    91 
     44    QAction *StripAction;
     45
     46  private:
    9247    struct PlotItem {
    93       QString Name;
    9448      QwtPlotCurve *Signal;
    95       double Smallest;
    96       double Largest;
    97           int SizeLimit;
    9849          QVector<double> x;
    9950          QVector<double> y;
    100           int Index;     
     51      double Smallest;
     52      double Largest;     
    10153    };
    102 
    10354    QList<struct PlotItem> Items;
    104     QMutex *Mutex;
    105    
    106     QMenu *Menu;
     55
    10756    QAction *YLogAction;
    10857    QAction *NormAction;
    10958    QAction *StyleAction;
    110     QAction *StripAction;
    11159   
    11260    QwtPlotPanner *Panner;
     
    11563        QwtPlotMagnifier *Magnifier;
    11664    QwtPicker *Picker;
     65        QwtDoubleRect BBox;
     66               
     67  public:
     68    EddBasePlot(QWidget * = NULL);
     69    ~EddBasePlot();
     70
     71        QwtPlotCurve *NewCurve(QwtText);
     72        void ClearCurve(unsigned int);
     73        void AddPoint(unsigned int, double, double);
     74        virtual void DeleteCurve(QwtPlotCurve *) = 0;
     75
     76  protected slots:
     77    void UpdatePlot();
     78
     79  private slots:
     80    void HandleZoom(const QwtDoubleRect &);
     81        void MouseSelection(const QwtPolygon &);
     82        void contextMenuEvent(QContextMenuEvent *);
     83    void MenuSingleTrace();       
     84    void MenuZoomOut();
     85    void MenuSaveASCII();
     86    void MenuSave();
     87    void MenuPrint();
     88        void MenuPlotHelp();
     89};
     90                 
     91// General indicator for DIM service
     92class EddLineDisplay: public QLineEdit {
     93    Q_OBJECT
     94
     95    QMenu *Menu;
     96    QPoint dragStart;
     97    QWidget *LastPlot;
     98       
     99        QString ServiceName;
     100        int Index;
     101       
     102    void mousePressEvent(QMouseEvent *);
     103    void mouseReleaseEvent(QMouseEvent *);
     104    void mouseMoveEvent(QMouseEvent *);
     105       
     106  public:
     107    EddLineDisplay(QString, int=0, QWidget * = NULL);
     108    ~EddLineDisplay();
     109
     110        bool ShowAsTime;
     111       
     112  private slots:
     113        void Update(QString, int, QByteArray, QString, QString);
     114    void contextMenuEvent(QContextMenuEvent *);   
     115    void MenuOpenHistory();
     116    void MenuCopyService();
     117    void MenuCopyData();
     118};
     119
     120// Graph class for history display
     121class EddPlot: public EddBasePlot {
     122    Q_OBJECT
     123
     124        // Time scale for axis
     125        class EddTimeScale: public QwtScaleDraw {
     126
     127          public:
     128                EddTimeScale() {}
     129
     130                virtual QwtText label(double v) const {
     131                  // Adapt text format to time span
     132                  QString Format;
     133                  if (scaleDiv().range() < 60*60) Format = "hh' h\n'mm:ss";
     134                  else if (scaleDiv().range() < 24*60*60) Format = "hh:mm";
     135                  else if (scaleDiv().range() < 30*24*60*60) Format = "h' h\n'd-MMM";
     136                  else Format = "d-MMM'\n'yyyy";
     137
     138                  // Generate text
     139                  QwtText Text = QDateTime::fromTime_t((int) v).toString(Format);
     140                  QFont Font = Text.font();
     141                  Font.setPointSize(7);
     142                  Text.setFont(Font);
     143
     144          return Text;
     145                }
     146        };
     147
     148    struct ItemDetails {
     149      QString Name;
     150          int Index;
     151      QwtPlotCurve *Signal;       
     152    };
     153    QList<struct ItemDetails> List;
     154
     155  private:
    117156        QwtLegend *Legend;
    118         QwtDoubleRect BBox;
     157        int SizeLimit;
    119158
    120159    void dragEnterEvent(QDragEnterEvent *);
     
    126165    ~EddPlot();
    127166    void AddService(QString, int = 0);
    128 
    129   private slots:
    130         void Update(QString, int, QByteArray, QString, QString);
    131     void UpdatePlot();
    132 
    133     void HandleZoom(const QwtDoubleRect &);
    134         void MouseSelection(const QwtPolygon &);
    135         void contextMenuEvent(QContextMenuEvent *);
     167        void DeleteCurve(QwtPlotCurve *);
     168
     169  private slots:
     170        void Update(QString, int, QByteArray, QString, QString);
    136171        void LegendClicked(QwtPlotItem *);
    137     void MenuZoomOut();
    138     void MenuSingleTrace();       
    139     void MenuSaveASCII();
    140     void MenuSave();
    141     void MenuPrint();
    142172    void MenuPasteService();
    143         void MenuPlotHelp();
    144 };
     173};
     174
    145175
    146176// Text history and output class
    147177class EddText: public QTextEdit {
    148     Q_OBJECT
    149 
     178  Q_OBJECT
     179
     180  private:
    150181        QString Name;
    151182        bool Pure;
     
    161192};
    162193
     194
    163195// Interface to DIM system
    164196class EddDim: public QObject, public DimInfo {
    165     Q_OBJECT
    166 
     197  Q_OBJECT
     198
     199  private:
    167200        struct Item {
    168201          QString Name;
     
    205238};
    206239
     240//
     241//
     242// ====== FACT specific part ======
     243//
     244//
     245
     246// Event oscilloscope
     247class EventScope: public EddBasePlot, public PixelMap {
     248  Q_OBJECT
     249
     250  private:
     251    struct ItemDetails {
     252          unsigned int Board, Chip, Channel;
     253      QwtPlotCurve *Signal;
     254          QwtPlotMarker *Trigger;
     255    };
     256    QList<struct ItemDetails> List;
     257
     258    QString Name;
     259        RawDataCTX *RD;
     260        CTX_ErrCode ErrCode;
     261        QAction *PhysPipeAction;
     262        FILE *Tmpfile;
     263
     264  public:
     265    EventScope(QWidget * = NULL);
     266    ~EventScope();
     267       
     268        void UpdateFirst(int, int, int);
     269        void AddTrace(int, int, int);
     270
     271  private slots:
     272        void Update(QString, int, QByteArray, QString, QString);
     273        void PlotTraces();
     274        void DeleteCurve(QwtPlotCurve *);
     275       
     276  signals:
     277        void RunHeaderChanged(QString);
     278        void EventHeaderChanged(QString);
     279};
     280
     281
     282// Tab page classes
     283class TP_Environment: public QWidget {
     284  Q_OBJECT
     285
     286  public:
     287    TP_Environment();
     288};
     289
     290class TP_Bias: public QWidget {
     291  Q_OBJECT
     292
     293  public:
     294    TP_Bias();
     295};
     296
     297class TP_Feedback: public QWidget {
     298  Q_OBJECT
     299
     300  private slots:
     301        void FeedbackDetails();
     302
     303  public:
     304    TP_Feedback();
     305};
     306
     307class TP_DAQ: public QWidget {
     308  Q_OBJECT
     309
     310  private:
     311        EventScope *Scope;
     312    QPlainTextEdit *RunHeaderDisplay, *EventHeaderDisplay;
     313
     314        QSpinBox *Channel, *Chip, *Board;
     315        QLineEdit *PixelID;
     316        QFormLayout *FormLayout;
     317
     318  private slots:
     319        void TranslatePixelID();
     320        void UpdateScope(int);
     321        void KeepCurrent();
     322
     323  public:
     324        TP_DAQ();       
     325};
     326
     327class TP_Evidence: public QWidget {
     328  Q_OBJECT
     329
     330  private slots:
     331        void StartDIMBrowser();
     332
     333  public:
     334        TP_Evidence(); 
     335};
     336
    207337
    208338// Main window class
    209339class GUI: public QMainWindow, public DimBrowser {
    210     Q_OBJECT
    211 
    212     QwtAnalogClock *Clock;
    213        
    214     QWidget *Central, *MainWidget, *BiasWidget, *FeedbackWidget, *FeedbackDetailsWidget, *EnvironmentWidget;
    215     QGridLayout *MainLayout, *BiasLayout, *FeedbackLayout, *FeedbackDetailsLayout, *EnvironmentLayout;
    216 
     340  Q_OBJECT
     341
     342  private:
     343    QWidget *Central;
    217344    QTabWidget *TabWidget;
    218345           
     
    226353    void MenuAbout();
    227354    void MenuNewHistory();
    228         void StartDIMBrowser();
    229         void FeedbackDetails();
    230355};
    231356
  • Evidence/Edd/Edd.pro

    r144 r208  
    66TARGET =
    77DEPENDPATH += .
    8 INCLUDEPATH += . .. /usr/local/qwt-5.2.0/include $(DIMDIR)/dim
     8INCLUDEPATH += . .. /ihp/local/qwt-5.2.1/include $(DIMDIR)/dim ../../drsdaq ../../pixelmap
    99
    1010# Input
    1111HEADERS += Edd.h
    12 SOURCES += Edd.cc ../Evidence.cc
    13 LIBS += -L/usr/local/qwt-5.2.0/lib -lqwt $(DIMDIR)/linux/libdim.a
     12SOURCES += Edd.cc ../Evidence.cc ../../drsdaq/RawDataCTX.cc ../../pixelmap/Pixel.cc ../../pixelmap/PixelMap.cc
     13LIBS += -L/ihp/local/qwt-5.2.1/lib -lqwt $(DIMDIR)/linux/libdim.a
Note: See TracChangeset for help on using the changeset viewer.