/* ============================================================ Edd - Evidence Data Display Qt-based graphical user interface for the Evidence contron system EddLineDisplay changes its background colour in case it display a DIM status service February 2010, Oliver Grimm ============================================================ */ #include "Edd.h" Qt::GlobalColor LineColors[] = {Qt::black, Qt::blue, Qt::red, Qt::green, Qt::white, Qt::darkRed, Qt::darkGreen, Qt::darkBlue, Qt::cyan, Qt::darkCyan, Qt::magenta, Qt::darkMagenta, Qt::gray, Qt::darkGray, Qt::lightGray}; class EddDim *Handler; // History chooser function (opens plot for numeric data, TextHist for all other) QWidget *OpenHistory(char *Service, int Index) { char *Name, *Format; DimBrowser Browser; Browser.getServices(Service); if (Browser.getNextService(Name, Format) != DimSERVICE) return new EddPlot(Service, Index); if (strlen(Format) == 1 && *Format != 'C') return new EddPlot(Service, Index); else return new EddText(Service); } ////////////////////////////////////////// // Text display for arbitary DIM service// ////////////////////////////////////////// // Constructor EddLineDisplay::EddLineDisplay(QString Name, int Index, QWidget *P): QLineEdit(P), ServiceName(Name), Index(Index) { LastPlot = NULL; // Widget properties setReadOnly(true); setMaximumWidth(100); ShowAsTime = false; // Connect to DIM handler if (connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) { printf("Failed connection for %s\n", Name.toAscii().data()); } // Context menu Menu = new QMenu(this); Menu->addAction("Open new history", this, SLOT(MenuOpenHistory())); Menu->addAction("Copy service", this, SLOT(MenuCopyService())); Menu->addAction("Copy data", this, SLOT(MenuCopyData())); // Subscribe to service Handler->Subscribe(Name); } // Destructor EddLineDisplay::~EddLineDisplay() { Handler->Unsubscribe(ServiceName); } // Update widget void EddLineDisplay::Update(QString Name, int Time, QByteArray Array, QString Format, QString Text) { if (ServiceName != Name) return; QPalette Pal = palette(); // Check if service available if (Time == -1) { setText("n/a"); setStatusTip(QString("%1: unavailable").arg(ServiceName)); Pal.setColor(QPalette::Base, Qt::lightGray); } else { // Backgound colour determined by last byte switch (Array[Array.size()]) { case 0: Pal.setColor(QPalette::Base, Qt::white); break; case 1: Pal.setColor(QPalette::Base, Qt::yellow); break; case 2: Pal.setColor(QPalette::Base, Qt::red); break; case 3: Pal.setColor(QPalette::Base, Qt::red); break; default: break; } if (Format[0].toUpper() != 'C') Text = Text.section(' ', Index, Index); if (!ShowAsTime) setText(Text); else setText(QDateTime::fromTime_t(Text.toInt()).toString()); setCursorPosition(0); // Update status tip setStatusTip(QString("%1 (%4): Last update %2 Format '%3'").arg(ServiceName).arg( QDateTime::fromTime_t(Time).toString()).arg(Format).arg(Index)); } setPalette(Pal); } // Open plot if mouse release within widget void EddLineDisplay::mouseReleaseEvent(QMouseEvent *Event) { if (Event->button()!=Qt::LeftButton || !contentsRect().contains(Event->pos())) return; // Check if last history plot still open, then raise foreach (QWidget *Widget, QApplication::allWidgets()) { if (Widget == LastPlot) { Widget->activateWindow(); Widget->raise(); return; } } // If not, open new plot EddLineDisplay::MenuOpenHistory(); } // Handling of mouse press event: Register start position for drag void EddLineDisplay::mousePressEvent(QMouseEvent *Event) { if (Event->button() == Qt::LeftButton) dragStart = Event->pos(); } // Handling of dragging (Drag and MimeData will be deleted by Qt) void EddLineDisplay::mouseMoveEvent(QMouseEvent *Event) { if ((Event->buttons() & Qt::LeftButton) == 0) return; if ((Event->pos()-dragStart).manhattanLength() < QApplication::startDragDistance()) return; QDrag *Drag = new QDrag(this); QMimeData *MimeData = new QMimeData; QByteArray Data; MimeData->setData("Edd/Service", Data.append(ServiceName + " " + QString::number(Index))); Drag->setMimeData(MimeData); Drag->exec(); } // // Opening context menu // void EddLineDisplay::contextMenuEvent(QContextMenuEvent *Event) { Menu->exec(Event->globalPos()); } // Menu: Open history plot void EddLineDisplay::MenuOpenHistory() { LastPlot = OpenHistory(ServiceName.toAscii().data(), Index); if (LastPlot != NULL) LastPlot->show(); } // Menu: Copy service name void EddLineDisplay::MenuCopyService() { QMimeData *MimeData = new QMimeData; QByteArray Data; MimeData->setData("Edd/Service", Data.append(ServiceName + " " + QString::number(Index))); QApplication::clipboard()->setMimeData(MimeData); } // Menu: Copy data void EddLineDisplay::MenuCopyData() { QApplication::clipboard()->setText(text()); } ////////////////////////////////// // History plot for DIM service // ////////////////////////////////// // // Constructor // EddPlot::EddPlot(QString DIMService, int Index, QWidget *P): QwtPlot(P) { Mutex = new QMutex(QMutex::Recursive); // Widget properties setAcceptDrops(true); setAttribute(Qt::WA_DeleteOnClose); setAutoReplot(false); setCanvasBackground(QColor(Qt::yellow)); setAxisScaleDraw(QwtPlot::xBottom, new TimeScale()); Zoomer = new QwtPlotZoomer(QwtPlot::xBottom,QwtPlot::yLeft,canvas()); connect(Zoomer, SIGNAL(zoomed(const QwtDoubleRect &)), this, SLOT(HandleZoom(const QwtDoubleRect &))); Panner = new QwtPlotPanner(canvas()); Panner->setMouseButton(Qt::LeftButton, Qt::ShiftModifier); Grid = new QwtPlotGrid; Grid->setMajPen(QPen(Qt::gray, 0, Qt::DotLine)); Grid->attach(this); Legend = new QwtLegend(); Legend->setItemMode(QwtLegend::ClickableItem); insertLegend(Legend, QwtPlot::TopLegend); connect(this, SIGNAL(legendClicked (QwtPlotItem *)), SLOT(LegendClicked(QwtPlotItem *))); // Connect to DIM handler if (connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) { printf("Failed connection for %s\n", DIMService.toAscii().data()); } // Context menu Menu = new QMenu(this); YLogAction = Menu->addAction("y scale log", this, SLOT(UpdatePlot())); YLogAction->setCheckable(true); NormAction = Menu->addAction("Normalize", this, SLOT(UpdatePlot())); NormAction->setCheckable(true); StyleAction = Menu->addAction("Draw dots", this, SLOT(UpdatePlot())); StyleAction->setCheckable(true); Menu->addAction("Zoom out", this, SLOT(MenuZoomOut())); Menu->addAction("Single trace", this, SLOT(MenuSingleTrace())); Menu->addSeparator(); Menu->addAction("Save as ASCII", this, SLOT(MenuSaveASCII())); Menu->addAction("Save plot", this, SLOT(MenuSave())); Menu->addAction("Print plot", this, SLOT(MenuPrint())); Menu->addSeparator(); Menu->addAction("Paste service", this, SLOT(MenuPasteService())); // DIM client if (!DIMService.isEmpty()) AddService(DIMService, Index); } // // Destructor (items with parent widget are automatically deleted) // EddPlot::~EddPlot() { for (int i=0; iUnsubscribe(Items[i].Name); delete Items[i].Signal; } delete Grid; delete Mutex; } // // Add history service to plot // void EddPlot::AddService(QString Name, int Index) { // Lock before accessing Items list QMutexLocker Locker(Mutex); // Check if already subscribed to service for (int i=0; iattach(this); New.Signal->setTitle(Name+"("+QString::number(Index)+")"); New.Signal->setPen(QColor(LineColors[Items.size() % (sizeof(LineColors)/sizeof(Qt::GlobalColor))])); New.SizeLimit = 5000; New.Index = Index; Items.append(New); Handler->Subscribe(Name); } // Update widget (must happen in GUI thread) void EddPlot::Update(QString Name, int Time, QByteArray, QString Format, QString Text) { // Lock before accessing Items list QMutexLocker Locker(Mutex); // Determine which plot item this call belongs to int ItemNo; for (ItemNo=0; ItemNo Items[ItemNo].SizeLimit) { Items[ItemNo].x.clear(); Items[ItemNo].y.clear(); } // If buffer empty, request new history buffer if (Items[ItemNo].x.isEmpty()) { int Time, Size; void *Data; class EvidenceHistory *HistClass = Handler->GetHistory(Items[ItemNo].Name); if (HistClass->GetHistory()) { double Smallest = DBL_MAX, Largest = DBL_MIN; double Number=0; while (HistClass->Next(Time, Size, Data)) { switch (Format[0].toUpper().toAscii()) { case 'I': case 'L': Number = *((int *) Data + Items[ItemNo].Index); break; case 'S': Number = *((short *) Data + Items[ItemNo].Index); break; case 'F': Number = *((float *) Data + Items[ItemNo].Index); break; case 'D': Number = *((double *) Data + Items[ItemNo].Index); break; case 'X': Number = *((long long *) Data + Items[ItemNo].Index); break; default: break; } Items[ItemNo].x.append(Time); Items[ItemNo].y.append(Number); if (Largest < Items[ItemNo].y.last()) Largest = Items[ItemNo].y.last(); if (Smallest > Items[ItemNo].y.last()) Smallest = Items[ItemNo].y.last(); } Items[ItemNo].Smallest = Smallest; Items[ItemNo].Largest = Largest; // Local buffer always at least twice as large as history if (Items[ItemNo].SizeLimit < 2*Items[ItemNo].x.size()) { Items[ItemNo].SizeLimit = 2*Items[ItemNo].x.size(); } } } // Append data QString Txt = Text; Txt = Txt.section(' ', Items[ItemNo].Index, Items[ItemNo].Index); Items[ItemNo].x.append(Time); Items[ItemNo].y.append(atof(Txt.toAscii().data())); // Update largest and smallest value if (Items[ItemNo].y.last() > Items[ItemNo].Largest) Items[ItemNo].Largest = Items[ItemNo].y.last(); if (Items[ItemNo].y.last() < Items[ItemNo].Smallest) Items[ItemNo].Smallest = Items[ItemNo].y.last(); // Update status tip QDateTime Timex = QDateTime::fromTime_t(Time); setStatusTip(QString("%1: Last update %2 Format '%3'").arg(Name).arg(Timex.toString()).arg(Format)); } UpdatePlot(); } // // Update all curves in plot // void EddPlot::UpdatePlot() { static QwtSymbol Symbol, Sym1; Symbol.setStyle(QwtSymbol::Ellipse); Symbol.setSize(4); if (!YLogAction->isChecked()) { setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine); } else setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine); // Lock before accessing Items list QMutexLocker Locker(Mutex); for (int ItemNo=0; ItemNoisChecked()) Items[ItemNo].Signal->setSymbol(Symbol); else Items[ItemNo].Signal->setSymbol(Sym1); int DataPoints = Items[ItemNo].x.size(); if (DataPoints == 0) continue; // Normalize y scale if requested double *y = new double [DataPoints]; for (int i=0; iisChecked()) { if (Items[ItemNo].Smallest != Items[ItemNo].Largest) { y[i] = (y[i] - Items[ItemNo].Smallest)/(Items[ItemNo].Largest-Items[ItemNo].Smallest); } else y[i] = 1; } } // Plot data Items[ItemNo].Signal->setData(Items[ItemNo].x.data(), y, DataPoints); Items[ItemNo].Signal->show(); Zoomer->setZoomBase(Items[ItemNo].Signal->boundingRect()); delete[] y; } replot(); } // // Reset graph axes to autoscale when fully unzoomed // void EddPlot::HandleZoom(const QwtDoubleRect &) { if(Zoomer->zoomRectIndex() == 0) { setAxisAutoScale(QwtPlot::xBottom); setAxisAutoScale(QwtPlot::yLeft); } } // // Drag and drop methods // void EddPlot::dragEnterEvent(QDragEnterEvent *Event) { if (Event->mimeData()->hasFormat("Edd/Service")) Event->acceptProposedAction(); } void EddPlot::dropEvent(QDropEvent *Event) { QByteArray D(Event->mimeData()->data("Edd/Service")); AddService(D.left(D.lastIndexOf(' ')), D.right(D.size()-D.lastIndexOf(' ')).toInt()); } // Opening context menu void EddPlot::contextMenuEvent(QContextMenuEvent *Event) { Menu->exec(Event->globalPos()); } // Drag&Drop method void EddPlot::LegendClicked(QwtPlotItem *Item) { QString D(Item->title().text()); D.replace('(',' ').chop(1); QDrag *Drag = new QDrag(this); QMimeData *MimeData = new QMimeData; QByteArray Data; MimeData->setData("Edd/Service", Data.append(D)); Drag->setMimeData(MimeData); Drag->exec(); } // Zoom completely out void EddPlot::MenuZoomOut() { Zoomer->zoom(0); UpdatePlot(); } // Remove all items except last void EddPlot::MenuSingleTrace() { // Lock before accessing Items list QMutexLocker Locker(Mutex); while (Items.size() > 1) { Handler->Unsubscribe(Items.last().Name); delete Items.last().Signal; Items.takeLast(); } UpdatePlot(); } // Save data of plot as test void EddPlot::MenuSaveASCII() { QString Filename = QFileDialog::getSaveFileName(this, "Filename", ".", "Text files (*.txt *.ascii *.asc);;All files (*)"); if (Filename.length() <= 0) return; QFile File(Filename); if (!File.open(QFile::WriteOnly | QIODevice::Text | QFile::Truncate)) { QMessageBox::warning(this, "Edd Message","Could not open file for writing.",QMessageBox::Ok); return; } // Lock before accessing Items list QMutexLocker Locker(Mutex); QTextStream Stream(&File); // Write x and y data for all signals to file for (int ItemNo=0; ItemNodataSize(); i++) { Stream << (int) Items[ItemNo].x.at(i) << " " << Items[ItemNo].Signal->y(i) << endl; } } } // Print plot void EddPlot::MenuPrint() { QPrinter *Printer = new QPrinter; QPrintDialog *PrintDialog = new QPrintDialog(Printer, this); if (PrintDialog->exec() == QDialog::Accepted) { QPainter Painter(Printer); QPixmap Pixmap = QPixmap::grabWidget(this); Painter.drawPixmap(0, 0, Pixmap); } delete Printer; delete PrintDialog; } // Save plot as image void EddPlot::MenuSave() { QString Filename = QFileDialog::getSaveFileName(this, "Filename of image", "/home/ogrimm/ddd", "Image files (*.bmp *.jpg *.png *.ppm *.tiff *.xbm *.xpm);;All files (*)"); if (Filename.length()>0) { QPixmap Pixmap = QPixmap::grabWidget(this); if(!Pixmap.save(Filename)) { QMessageBox::warning(this, "Edd Message","Could not write image file.",QMessageBox::Ok); remove(Filename.toAscii().data()); } } } // Add new service by pasting name void EddPlot::MenuPasteService() { const QMimeData *D = QApplication::clipboard()->mimeData(); if (!D->hasFormat("Edd/Service")) return; QByteArray E(D->data("Edd/Service")); AddService(E.left(E.lastIndexOf(' ')), E.right(E.size()-E.lastIndexOf(' ')).toInt()); } ////////////////////////////////////// // History text box for DIM service // ////////////////////////////////////// // // Constructor // EddText::EddText(QString Name, bool Pure, QWidget *P): QTextEdit(P), Name(Name), Pure(Pure) { // Widget properties setReadOnly(true); setAttribute(Qt::WA_DeleteOnClose); setAutoFillBackground(true); document()->setMaximumBlockCount(1000); Accumulate = true; // Connect to DIM handler if (connect(Handler, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) { printf("Failed connection for %s\n", Name.toAscii().data()); } if (!Pure) { // Get history for this service int Time, Size; void *Data; class EvidenceHistory *HistClass = Handler->GetHistory(Name); if (HistClass->GetHistory()) { while (HistClass->Next(Time, Size, Data)) { moveCursor (QTextCursor::Start); insertPlainText(QString("(")+QDateTime::fromTime_t(Time).toString()+") "); insertPlainText(QString((char *) Data) + "\n"); } } } // DIM client Handler->Subscribe(Name); } // Destructor EddText::~EddText() { Handler->Unsubscribe(Name); } // Update widget (must happen in GUI thread) void EddText::Update(QString Name, int Time, QByteArray, QString Format, QString Text) { if (this->Name != Name) return; QPalette Pal = palette(); // Check if service available if (Time == -1) { setStatusTip(QString("%1: unavailable").arg(Name)); Pal.setColor(QPalette::Base, Qt::lightGray); setPalette(Pal); return; } Pal.setColor(QPalette::Base, Qt::white); setPalette(Pal); QDateTime Timex = QDateTime::fromTime_t(Time); // Clear display in case text should not accumulate if (Accumulate == false) clear(); if (!Pure) { moveCursor(QTextCursor::Start); insertPlainText(QString("(")+Timex.toString()+QString(") ")); insertPlainText(Text + "\n"); } else if (Format == "C") insertPlainText(Text); // Update status tip setStatusTip(QString("%1: Last update %2 Format '%3'").arg(Name).arg(Timex.toString()).arg(Format)); } ///////////////////////////// // Interface to Dim system // ///////////////////////////// EddDim::EddDim() { Mutex = new QMutex(QMutex::Recursive); MinuteVolume = 0; TotalVolume = 0; QTimer *Timer = new QTimer(this); Timer->connect(Timer, SIGNAL(timeout()), this, SLOT(UpdateStatistics())); Timer->start(10000); // Connect to DIM handler if (connect(this, SIGNAL(YEP(QString, int, QByteArray, QString, QString)), SLOT(Update(QString, int, QByteArray, QString, QString))) == false) { printf("Failed connection in EddDim()\n"); } } EddDim::~EddDim() { for (int i=0; igetName(), -1); else { char *Text = EvidenceServer::ToString(getInfo()); YEP(getInfo()->getName(), getInfo()->getTimestamp(), QByteArray((char *) getInfo()->getData(), getInfo()->getSize()), getInfo()->getFormat(), Text); free(Text); } } // // Main GUI (all widgets have ultimately Central as parent) // GUI::GUI() { Handler = new EddDim(); // Set features of main window Central = new QWidget(this); setCentralWidget(Central); setStatusBar(new QStatusBar(this)); setGeometry(100, 100, 800, 650); setWindowTitle("Edd - Evidence Data Display"); EddLineDisplay *Value; EddPlot *Graph; EddText *Textout; QString Text; // TextBox for value // Clock (updated every second) //Clock = new QwtAnalogClock(Central); //Clock->scaleDraw()->setPenWidth(3); //Clock->setLineWidth(6); //Clock->setFrameShadow(QwtDial::Sunken); //Clock->setGeometry(0,0,10,10); //Clock->setTime(); //QTimer *Timer = new QTimer(Clock); //Timer->connect(Timer, SIGNAL(timeout()), Clock, SLOT(setCurrentTime())); //Timer->start(1000); MainWidget = new QWidget(); MainLayout = new QGridLayout(MainWidget); Value = new EddLineDisplay("Alarm/Status"); Value->setMaximumWidth(200); MainLayout->addWidget(Value, 0, 0, 1, 2); Value = new EddLineDisplay("Alarm/MasterAlarm"); MainLayout->addWidget(Value, 0, 1, 1, 1); Textout = new EddText("Alarm/Summary", true); Textout->Accumulate = false; Textout->setMaximumWidth(200); Textout->setMaximumHeight(150); MainLayout->addWidget(Textout, 1, 0, 1, 2); Value = new EddLineDisplay("DColl/Status"); Value->setMaximumWidth(200); MainLayout->addWidget(Value, 3, 0, 1, 2); Value = new EddLineDisplay("DColl/DataSizekB"); MainLayout->addWidget(Value, 4, 0, 1, 1); Value = new EddLineDisplay("DColl/LogSizekB"); MainLayout->addWidget(Value, 4, 1, 1, 1); Value = new EddLineDisplay("DColl/CurrentFile"); Value->setMaximumWidth(400); MainLayout->addWidget(Value, 5, 0, 1, 3); Value = new EddLineDisplay("Config/Status"); Value->setMaximumWidth(200); MainLayout->addWidget(Value, 6, 0, 1, 2); Value = new EddLineDisplay("Config/ModifyTime"); Value->setMaximumWidth(200); Value->ShowAsTime = true; MainLayout->addWidget(Value, 7, 0, 1, 1); QPushButton *Button = new QPushButton(); Button->setText("Start DIM browser"); connect(Button, SIGNAL(released()), SLOT(StartDIMBrowser())); MainLayout->addWidget(Button, 7, 1, 1, 1); Value = new EddLineDisplay("Edd/Rate_kBMin"); MainLayout->addWidget(Value, 8, 0, 1, 1); Value = new EddLineDisplay("Edd/Total_MB"); MainLayout->addWidget(Value, 8, 1, 1, 1); // Layout of all widgets //MainLayout->addWidget(Value, 0, 0, 1, 1); //MainLayout->addWidget(Clock, 0, 1, 1, 1); //MainLayout->addWidget(Graph, 1, 0, 1, 2); //MainLayout->setColumnStretch(1, 10); //MainLayout->addWidget(Clock, 0, 1, 1, 1); //MainLayout->addWidget(Graph1, 2, 0, 1, 2); // Feedback page FeedbackWidget = new QWidget(); FeedbackLayout = new QGridLayout(FeedbackWidget); Graph = new EddPlot(); for (int i=0; i<36; i++) { Value = new EddLineDisplay("Feedback/Average", i); FeedbackLayout->addWidget(Value, i%9+1, 0+i/9, 1, 1); Graph->AddService("Feedback/Average", i); } FeedbackLayout->addWidget(Graph, 0, 4, 11, 3); //Graph = new EddPlot(); //for (int i=0; i<36; i++) { //Text = Text.sprintf("Feedback/Sigma/ID%.2d/%.2d-%.3d",i/16, (i%16)/8, i%8); //Graph->AddService(Text); //} //FeedbackLayout->addWidget(Graph, 10, 0, 10, 3); Value = new EddLineDisplay("Feedback/Status"); Value->setMaximumWidth(200); FeedbackLayout->addWidget(Value, 0, 0, 1, 3); Value = new EddLineDisplay("Feedback/Count"); FeedbackLayout->addWidget(Value, 0, 3, 1, 1); QWidget *Value1 = new QPushButton("Details"); FeedbackLayout->addWidget(Value1, 10, 0, 1, 1); connect(Value1, SIGNAL(pressed()), this, SLOT(FeedbackDetails())); // Bias voltage page BiasWidget = new QWidget(); BiasLayout = new QGridLayout(BiasWidget); Graph = new EddPlot(); for (int i=0; i<18; i++) { Value = new EddLineDisplay("Bias/VOLT/ID00", i); BiasLayout->addWidget(Value, i%9+1, 0+i/9, 1, 1); Graph->AddService("Bias/VOLT/ID00", i); Value = new EddLineDisplay("Bias/VOLT/ID00", i+32); BiasLayout->addWidget(Value, i%9+1, 2+i/9, 1, 1); Graph->AddService("Bias/VOLT/ID00",i+32); } BiasLayout->addWidget(Graph, 0, 4, 12, 3); Value = new EddLineDisplay("Bias/Status"); Value->setMaximumWidth(200); BiasLayout->addWidget(Value, 0, 0, 1, 3); Textout = new EddText("Bias/Textout", true); Textout->setFixedWidth(400); BiasLayout->addWidget(Textout, 10, 0, 4, 4); // Environment page EnvironmentWidget = new QWidget(); EnvironmentLayout = new QGridLayout(EnvironmentWidget); Value = new EddLineDisplay("ARDUINO/Status"); Value->setMaximumWidth(200); EnvironmentLayout->addWidget(Value, 0, 0, 1, 3); Graph = new EddPlot(); for (int i=0; i<10; i++) { Value = new EddLineDisplay("ARDUINO/Data", i); EnvironmentLayout->addWidget(Value, i%5+1, i/5, 1, 1); Graph->AddService("ARDUINO/Data", i); } EnvironmentLayout->addWidget(Graph, 0, 3, 6, 4); Value = new EddLineDisplay("SQM/NSB"); EnvironmentLayout->addWidget(Value, 6, 0, 1, 1); // Tab widget TabWidget = new QTabWidget(Central); TabWidget->addTab(BiasWidget, "&Bias"); TabWidget->addTab(FeedbackWidget, "&Feedback"); TabWidget->addTab(EnvironmentWidget, "&Environment"); TabWidget->addTab(MainWidget, "Evidence"); // Menu bar QMenu* Menu = menuBar()->addMenu("&Menu"); Menu->addAction("New history plot", this, SLOT(MenuNewHistory())); Menu->addSeparator(); Menu->addAction("About", this, SLOT(MenuAbout())); Menu->addSeparator(); QAction* QuitAction = Menu->addAction("Quit", qApp, SLOT(quit())); QuitAction->setShortcut(Qt::CTRL + Qt::Key_Q); // Show main window show(); } GUI::~GUI() { delete Central; } void GUI::MenuAbout() { QString Rev(SVN_REVISION); Rev.remove(0,1).chop(2); QMessageBox::about(this, "About Edd","Evidence Data Display\n\n" "Written by Oliver Grimm, IPP, ETH Zurich\n" "This version compiled "__DATE__" ("+Rev+")\n\n" "Graphical user interface implemented with Qt and Qwt.\n" "Evidence control system based on DIM (http://dim.web.cern.ch).\n\n" "Comments to oliver.grimm@phys.ethz.ch."); } // Open request for new history plot void GUI::MenuNewHistory() { QStringList List; char *Name, *Format; int Type; bool OK; // Find all services that are not history services and sort getServices("*"); while ((Type = getNextService(Name, Format)) != 0) { if (Type==DimSERVICE && strstr(Name, ".hist")==NULL) List.append(Name); } List.sort(); // Open dialog and open history window QString Result = QInputDialog::getItem(this, "Edd Request", "Enter DIM service name", List, 0, true, &OK); if (OK && !Result.isEmpty()) { Result = Result.trimmed(); if (Result.endsWith(".hist")) Result.chop(5); QWidget *Hist = OpenHistory(Result.toAscii().data(), 0); if (Hist != NULL) Hist->show(); } } // Feedback details page void GUI::FeedbackDetails() { QWidget *Value; QWidget *Widget = new QWidget(); QGridLayout *Layout = new QGridLayout(Widget); EddPlot *Graph = new EddPlot(); for (int i=0; i<36; i++) { Value = new EddLineDisplay("Feedback/Sigma", i); Layout->addWidget(Value, i%9+1, 0+i/9, 1, 1); Graph->AddService("Feedback/Sigma", i); } Layout->addWidget(Graph, 0, 4, 11, 3); Widget->show(); } // Start DIM Browser void GUI::StartDIMBrowser() { QProcess::startDetached("did", QStringList(), QString(getenv("DIMDIR"))+"/linux/"); } //--------------------------------------------------------------------- //************************ All functions **************************** //------------------------------------------------------------------- // Quit application when clicking close button on window void GUI::closeEvent(QCloseEvent *) { qApp->quit(); } //--------------------------------------------------------------------- //**************************** Main program *************************** //--------------------------------------------------------------------- int main(int argc, char *argv[]) { QApplication app(argc, argv); GUI MainWindow; return app.exec(); }