CFEL - ASG Software Suite  2.5.0
CASS
one_d_viewer.cpp
Go to the documentation of this file.
1 // Copyright (C) 2013 Lutz Foucar
2 
3 /**
4  * @file one_d_viewer.cpp contains viewer for 1d data
5  *
6  * @author Lutz Foucar
7  */
8 
9 #include <QtCore/QSettings>
10 #include <QtCore/QVector>
11 #include <QtCore/QDebug>
12 #include <QtCore/QTime>
13 
14 #if QT_VERSION >= 0x050000
15 #include <QtWidgets/QVBoxLayout>
16 #include <QtWidgets/QToolBar>
17 #include <QtWidgets/QWidgetAction>
18 #include <QtWidgets/QMenu>
19 #include <QtWidgets/QColorDialog>
20 #include <QtWidgets/QInputDialog>
21 #include <QtWidgets/QFileDialog>
22 #include <QtWidgets/QMessageBox>
23 #else
24 #include <QtGui/QVBoxLayout>
25 #include <QtGui/QToolBar>
26 #include <QtGui/QWidgetAction>
27 #include <QtGui/QMenu>
28 #include <QtGui/QColorDialog>
29 #include <QtGui/QInputDialog>
30 #include <QtGui/QFileDialog>
31 #include <QtGui/QMessageBox>
32 #endif
33 #include <QtGui/QIcon>
34 
35 #include <qwt_plot.h>
36 #include <qwt_plot_curve.h>
37 #include <qwt_plot_grid.h>
38 #include <qwt_scale_widget.h>
39 #include <qwt_legend.h>
40 #include <qwt_scale_engine.h>
41 #include <qwt_legend_label.h>
42 
43 #include "one_d_viewer.h"
44 
45 #include "result.hpp"
46 #include "minmax_control.h"
47 #include "one_d_viewer_data.h"
48 #include "file_handler.h"
49 #include "curve_plot.h"
50 #include "data.h"
51 #include "data_source_manager.h"
52 #include "jocassviewer.h"
53 
54 using namespace jocassview;
55 using namespace cass;
56 
58  : DataViewer(title,parent)
59 {
60  // add settings object to retrieve the settings for this view
61  QSettings settings;
62  settings.beginGroup(windowTitle());
63 
64  // Add the plot where the 1d data will be displayed as central widget
65  _plot = new QwtPlot(this);
66  // add a curve that should be displayed
67  _curves.push_front(new PlotCurve);
68  _curves[0]->setTitle(title);
70  _curves[0]->setData(data);
71  QPen pen;
72  pen.setColor(settings.value("CurveColor",QColor(Qt::blue)).value<QColor>());
73  pen.setWidth(settings.value("CurveWidth",1).toInt());
74  _curves[0]->setStyle(QwtPlotCurve::Steps);
75  _curves[0]->setPen(pen);
76  _curves[0]->attach(_plot);
77  // add a grid to show on the plot
78  _grid = new QwtPlotGrid;
79  _grid->setMajorPen(QPen(Qt::black, 0, Qt::DashLine));
80  _grid->setMinorPen(QPen(Qt::black, 0, Qt::DotLine));
81  _grid->attach(_plot);
82  _gridLines = settings.value("GridEnabled",0).toUInt();
83  // add a legend to the plot
84  _legend = new QwtLegend;
85  _legend->setDefaultItemMode(QwtLegendData::Checkable);
86  _plot->insertLegend(_legend,QwtPlot::RightLegend);
87  QwtLegendLabel *curveLegendLabel(qobject_cast<QwtLegendLabel *>(_legend->legendWidget(_plot->itemToInfo(_curves[0]))));
88  curveLegendLabel->setContextMenuPolicy(Qt::CustomContextMenu);
89  curveLegendLabel->setChecked(true);
90  connect(curveLegendLabel,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(on_legend_right_clicked(QPoint)));
91  connect(_legend,SIGNAL(checked(const QVariant&,bool,int)),this,SLOT(on_legend_checked(const QVariant &,bool)));
92  // add the plot to the widget
94 
95  // create the toolbar
96  QToolBar * toolbar(new QToolBar("Plot Control",this));
97  addToolBar(Qt::BottomToolBarArea,toolbar);
98 
99  // Add a button that allows to add a reference curve
100  toolbar->addAction(QIcon(":images/graph_add.png"),
101  tr("Add a reference Graph to the Plot"),
102  this,SLOT(on_add_graph_triggered()));
103 
104  // Add grid control to toolbar
105  _gridControl = new QAction(QIcon(":images/grid.png"),
106  tr("toggle Grid"),toolbar);
107  connect(_gridControl,SIGNAL(triggered()),this,SLOT(on_grid_triggered()));
108  toolbar->addAction(_gridControl);
109 
110  // Add title display to the toolbar
111  _axisTitleControl = new QAction(QIcon(":images/axistitle.png"),
112  tr("Toggle Axis Titles"),toolbar);
113  _axisTitleControl->setCheckable(true);
114  _axisTitleControl->setChecked(settings.value("DisplayTitles",true).toBool());
115  connect(_axisTitleControl,SIGNAL(triggered()),this,SLOT(replot()));
116  toolbar->addAction(_axisTitleControl);
117 
118  // Add legend control to toolbar
119  _legendControl = new QAction(QIcon(":images/legend.png"),tr("toggle Legend"),toolbar);
120  _legendControl->setCheckable(true);
121  _legendControl->setChecked(settings.value("LegendShown",true).toBool());
122  connect(_legendControl,SIGNAL(triggered()),this,SLOT(replot()));
123  toolbar->addAction(_legendControl);
124 
125  // Add separator to toolbar
126  toolbar->addSeparator();
127 
128  // Add x-axis control to the toolbar
129  _xControl = new MinMaxControl(QString(windowTitle() + "/x-scale"),toolbar);
130  connect(_xControl,SIGNAL(controls_changed()),this,SLOT(replot()));
131  QWidgetAction *xControlAction(new QWidgetAction(toolbar));
132  xControlAction->setDefaultWidget(_xControl);
133  toolbar->addAction(xControlAction);
134 
135  // Add separator to toolbar
136  toolbar->addSeparator();
137 
138  // Add y-axis control to the toolbar
139  _yControl = new MinMaxControl(QString(windowTitle() + "/y-scale"),toolbar);
140  connect(_yControl,SIGNAL(controls_changed()),this,SLOT(replot()));
141  QWidgetAction *yControlAction(new QWidgetAction(toolbar));
142  yControlAction->setDefaultWidget(_yControl);
143  toolbar->addAction(yControlAction);
144 
145  qsrand(QTime::currentTime().msec());
146  // Set the size and position of the window
147  resize(settings.value("WindowSize",size()).toSize());
148  move(settings.value("WindowPosition",pos()).toPoint());
149 
150  settings.endGroup();
151 }
152 
154 {
155 
156 }
157 
159 {
160  QList<Data*>list;
161  QwtPlotItemList plotlist(_plot->itemList(QwtPlotItem::Rtti_PlotCurve));
162  for (QwtPlotItemIterator it = plotlist.begin(); it != plotlist.end() ; ++it)
163  {
164  PlotCurve *curve(dynamic_cast<PlotCurve*>(*it));
165  list.append(dynamic_cast<OneDViewerData*>(curve->data()));
166  }
167  return list;
168 }
169 
171 {
172  return QString("1DViewer");
173 }
174 
175 void OneDViewer::saveData(const QString &filename)
176 {
177  /** when the filename indicates that it should be saved as png, do so */
178  QFileInfo fileInfo(filename);
179  if (fileInfo.suffix().toUpper() == QString("png").toUpper())
180  {
181  if (!fileInfo.exists())
182  {
183  QPixmap pix(this->grab());
184  if (fileInfo.suffix().toUpper() == QString("png").toUpper())
185  {
186  pix.save(filename, "PNG");
187  }
188  }
189  }
190  /** otherwise store the data individually as data files */
191  else
192  {
193  QList<Data*> dataList(data());
194  QList<Data*>::iterator dataIt(dataList.begin());
195  while (dataIt != dataList.end())
196  {
197  QString fname(filename);
198  if(!FileHandler::isContainerFile(filename))
199  fname.insert(fname.lastIndexOf("."),"_" + QString::fromStdString((*dataIt)->result()->name()));
200  FileHandler::saveData(filename,(*dataIt)->result());
201  ++dataIt;
202  }
203  }
204 }
205 
207 {
208  replot();
209 }
210 
212 {
213  QStringList list;
214  list <<"h5"<<"hst"<<"csv"<<"png";
215  return list;
216 }
217 
219 {
220  /** check if grid should be enabled */
221  _grid->enableX(static_cast<bool>(_gridLines & 0x1));
222  _grid->enableXMin(static_cast<bool>(_gridLines & 0x4));
223  _grid->enableY(static_cast<bool>(_gridLines & 0x2));
224  _grid->enableYMin(static_cast<bool>(_gridLines & 0x8));
225 
226  /** hide /show the legend (this is a hack, since legends can't be directly hidden)
227  * retrieve all curve plots from the plot and get theier corresponding
228  * legend widget. This needs to be hidden and then the legend to be updated
229  */
230  QwtPlotItemList list(_plot->itemList(QwtPlotItem::Rtti_PlotCurve));
231  for (QwtPlotItemIterator it = list.begin(); it != list.end() ; ++it)
232  _legend->legendWidget(_plot->itemToInfo(*it))->setVisible(_legendControl->isChecked());
233 
234  OneDViewerData *data(dynamic_cast<OneDViewerData*>(_curves[0]->data()));
235  /** set the scales to be log or linear */
236  data->setXRangeForLog(_xControl->log());
237  if(_xControl->log())
238  _plot->setAxisScaleEngine(QwtPlot::xBottom, new QwtLogScaleEngine);
239  else
240  _plot->setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine);
241 
242  data->setYRangeForLog(_yControl->log());
243  if(_yControl->log())
244  _plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLogScaleEngine);
245  else
246  _plot->setAxisScaleEngine(QwtPlot::yLeft, new QwtLinearScaleEngine);
247 
248  /** check if autoscale, and set the axis limits */
249  if (_xControl->autoscale())
250  _plot->setAxisAutoScale(QwtPlot::xBottom);
251  else
252  _plot->setAxisScale(QwtPlot::xBottom,_xControl->min(),_xControl->max());
253 
254  if (_yControl->autoscale())
255  _plot->setAxisAutoScale(QwtPlot::yLeft);
256  else
257  _plot->setAxisScale(QwtPlot::yLeft,_yControl->min(),_yControl->max());
258 
259  /** display the axis titles */
260  if (_axisTitleControl->isChecked())
261  {
262  if (!this->data().isEmpty())
263  {
264  Data::result_t::shared_pointer result(this->data().front()->result());
265  if (result)
266  {
267  QString xtitle(QString::fromStdString(result->axis(Data::result_t::xAxis).title));
268  _plot->axisWidget(QwtPlot::xBottom)->setTitle(xtitle);
269  }
270  }
271  }
272  else
273  _plot->axisWidget(QwtPlot::xBottom)->setTitle("");
274 
275  /** update the layout and replot the plot */
276  _plot->updateLayout();
277  _plot->replot();
278 
279  /** save the states of the controls */
280  QSettings settings;
281  settings.beginGroup(windowTitle());
282  settings.setValue("CurveColor",_curves[0]->pen().color());
283  settings.setValue("CurveWidth",_curves[0]->pen().width());
284  settings.setValue("GridEnabled",_gridLines);
285  settings.setValue("LegendShown",_legendControl->isChecked());
286  settings.setValue("DisplayTitles",_axisTitleControl->isChecked());
287  settings.endGroup();
288 }
289 
291 {
292  /** check if the sender of the signal is of widget type (is the legend item) */
293  if (!sender()->isWidgetType())
294  return;
295 
296  /** retrieve the legenditem widget and the corresponding curve, determine the
297  * position where the right click happen to be able to open the menu at this
298  * position
299  */
300  QWidget *curveWidget(dynamic_cast<QWidget*>(sender()));
301  PlotCurve * curve(dynamic_cast<PlotCurve*>((_plot->infoToItem(_legend->itemInfo(curveWidget)))));
302  QPoint globalPos(curveWidget->mapToGlobal(pos));
303 
304  /** create the context menu and execute it (block in this function until a
305  * choice has been made).
306  *
307  * In case this is the main curve (name is the name of the main curve), don't
308  * add the option to delete the curve. Otherwise create and connect their
309  * triggered signals to the appropriate private slots that will react on
310  * the choice.
311  */
312  QMenu menu;
313  QAction *act;
314  act = menu.addAction(tr("Color"),this,SLOT(change_curve_color()));
315  act->setParent(curveWidget);
316  act = menu.addAction(tr("Line Width"),this,SLOT(change_curve_width()));
317  act->setParent(curveWidget);
318  if(curve->title() != windowTitle())
319  {
320  act = menu.addSeparator();
321  act = menu.addAction(tr("Delete"),this,SLOT(remove_curve()));
322  act->setParent(curveWidget);
323  }
324  menu.exec(globalPos);
325 }
326 
327 void OneDViewer::on_legend_checked(const QVariant &itemInfo, bool on)
328 {
329  QwtPlotItem *curve(_plot->infoToItem(itemInfo));
330  curve->setVisible(on);
331  replot();
332 }
333 
335 {
336  if (!curve)
337  {
338  if (!sender()->parent()->isWidgetType())
339  return;
340  QWidget *curveWidget(dynamic_cast<QWidget*>(sender()->parent()));
341  curve = dynamic_cast<PlotCurve*>(_plot->infoToItem(_legend->itemInfo(curveWidget)));
342  }
343 
344  QPen pen(curve->pen());
345 
346  QColor col(QColorDialog::getColor(pen.color(),this,tr("Select Color")));
347  if (col.isValid())
348  pen.setColor(col);
349 
350  curve->setPen(pen);
351  replot();
352 }
353 
355 {
356  if (!curve)
357  {
358  if (!sender()->parent()->isWidgetType())
359  return;
360  QWidget *curveWidget(dynamic_cast<QWidget*>(sender()->parent()));
361  curve = dynamic_cast<PlotCurve*>(_plot->infoToItem(_legend->itemInfo(curveWidget)));
362  }
363 
364  QPen pen(curve->pen());
365 
366  bool ok(false);
367  int width(QInputDialog::getInt(this,tr("Set Line Width"),tr("Line width"),pen.width(),0,20,1,&ok));
368  if (ok)
369  pen.setWidth(width);
370 
371  curve->setPen(pen);
372  replot();
373 }
374 
376 {
377  if (!curve)
378  {
379  if (!sender()->parent()->isWidgetType())
380  return;
381  QWidget *curveWidget(dynamic_cast<QWidget*>(sender()->parent()));
382  curve = dynamic_cast<PlotCurve*>(_plot->infoToItem(_legend->itemInfo(curveWidget)));
383  }
384 
385  _curves.removeAll(curve);
386  curve->detach();
387  _legend->update();
388 
389  replot();
390 }
391 
393 {
394  /** ask the user from which source the added graph should come */
396  sourceNames << "***New Source***";
397  int currentIdx(sourceNames.indexOf(DataSourceManager::currentSourceName()));
398  bool ok(false);
399  QString sourceName(QInputDialog::getItem(0, QObject::tr("Select Source"),
400  QObject::tr("Source:"), sourceNames,
401  currentIdx, false, &ok));
402  if (!ok || sourceName.isEmpty())
403  return;
404  /** if the source should be a new one, ask the user for the filename of the
405  * new source and add it to the list of sources
406  */
407  if (sourceName == "***New Source***")
408  {
409  QString filter("Data Files (*.csv *.hst *.h5 *.hdf5)");
410  QString fileName = QFileDialog::getOpenFileName(this,
411  tr("Open Reference Data File"),
412  QDir::currentPath(), filter);
413  if(fileName.isEmpty())
414  return;
415  DataSourceManager::addSource(fileName,new FileHandler(fileName),false);
416  sourceName = fileName;
417  }
418 
419  /** retrieve the list of items that are available from the source, if more
420  * than 1 ask the user which should be added
421  */
422  DataSource * source(DataSourceManager::source(sourceName));
423  QStringList items(source->resultNames());
424  QString item(QInputDialog::getItem(0, QObject::tr("Select Key"),
425  QObject::tr("Key:"), items, 0, false, &ok));
426  if (!ok || item.isEmpty())
427  return;
428 
429  /** retrieve the result from the source and check if it is a 1d result */
430  Data::result_t::shared_pointer result(source->result(item));
431  if (!(result && result->dim() ==1))
432  {
433  QMessageBox::critical(this,tr("Error"),tr("The requested data doesn't exit or is not 1d data"));
434  return;
435  }
436 
437  /** create a new data container and add the result to it */
439  data->setSourceName(sourceName);
440  data->setResult(result);
441 
442  /** add a new curve to the plot and intialize it with the data and a random
443  * color then set up the legenditem and its context menu for the curve
444  */
445  _curves.push_back(new PlotCurve);
446  PlotCurve * curve(_curves.back());
447  QPen pen;
448  pen.setWidth(1);
449  pen.setColor(QColor::fromHsv(qrand() % 256, 255, 190));
450  curve->setPen(pen);
451  curve->setTitle(item);
452  curve->setStyle(QwtPlotCurve::Steps);
453  curve->attach(_plot);
454  curve->setData(data);
455  QwtLegendLabel *curveWidget(qobject_cast<QwtLegendLabel*>(_legend->legendWidget(_plot->itemToInfo(curve))));
456  curveWidget->setContextMenuPolicy(Qt::CustomContextMenu);
457  curveWidget->setChecked(true);
458  connect(curveWidget,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(on_legend_right_clicked(QPoint)));
459 
460  /** and replot the plot */
461  replot();
462 }
463 
465 {
466  _gridLines = (_gridLines+1) & 0xF;
467  while (_gridLines == 4 ||
468  _gridLines == 6 ||
469  _gridLines == 8 ||
470  _gridLines == 9 ||
471  _gridLines == 12 ||
472  _gridLines == 13 ||
473  _gridLines == 14)
474  _gridLines = (_gridLines+1) & 0xF;
475  replot();
476 }
contains the jocassviewer class
virtual QList< Data * > data()
retrieve the displayed data
addToolBar(Qt::ToolBarArea area, QToolBar *toolbar)
QAction * _legendControl
an action to control the legend of curves
Definition: one_d_viewer.h:166
base class for viewers
Definition: data_viewer.h:37
getItem(QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current=0, bool editable=true, bool *ok=0, Qt::WindowFlags flags=0)
OneDViewer(QString title, QWidget *parent=0)
constructor
static void addSource(const QString &sourcename, DataSource *source, bool setActive=true)
add a data source
virtual void setSourceName(const QString &name)
set the source name
Definition: data.cpp:24
std::tr1::shared_ptr< self_type > shared_pointer
a shared pointer of this class
Definition: result.hpp:323
bool log() const
return wether log is enabled
static void saveData(const QString &filename, result_t::shared_pointer data)
save data to a given file
read and write data to files
Definition: file_handler.h:30
contains the base class for add viewer data
contains singleton class to manage the data sources
mapToGlobal(const QPoint &pos)
the 1d data wrapper
QwtPlot * _plot
the plot inside which the data will be displayed
Definition: data_viewer.h:115
true Then one can use the IsHit Processor later on
things written only at end of run H5Dump ProcessorSummary size
currentPath()
quint8 _gridLines
flags to tell which grid lines should be drawn
Definition: one_d_viewer.h:163
virtual QString type() const
retrieve the type of the data viewer
result classes
tr(const char *sourceText, const char *disambiguation=0, int n=-1)
virtual QStringList dataFileSuffixes() const
suffixes for the data of this viewer
contains the viewer for 1d data
widget to control the min and max values
QAction * _axisTitleControl
an action to control the legend of curves
Definition: one_d_viewer.h:172
QAction * _gridControl
an action to control the grid in the plot
Definition: one_d_viewer.h:157
void setResult(result_t::shared_pointer result)
set the cass data to be wrapped by this
fromHsv(int h, int s, int v, int a=255)
setValue(const QString &key, const QVariant &value)
getInt(QWidget *parent, const QString &title, const QString &label, int value=0, int min=-2147483647, int max=2147483647, int step=1, bool *ok=0, Qt::WindowFlags flags=0)
virtual void saveData(const QString &filename)
save the data to file
void change_curve_color(PlotCurve *curve=0)
change the curves color
void on_legend_checked(const QVariant &item, bool on)
react when an legend item has been clicked
fromStdString(const std::string &str)
append(const T &value)
base class for data sources
Definition: data_source.h:26
save(const QString &fileName, const char *format=0, int quality=-1)
static bool isContainerFile(const QString &filename)
return whether the file is a container file
void change_curve_width(PlotCurve *curve=0)
change the curves line width
bool autoscale() const
return whether the plot should be autoscaled
virtual result_t::shared_pointer result(const QString &key, quint64 id=0)=0
retrieve a result from the source
contains a file handler
virtual void dataChanged()
update the plot
setCentralWidget(QWidget *widget)
fluorescence front
void on_grid_triggered()
react on when the gridControl has been triggered
setColor(const QColor &color)
void on_legend_right_clicked(QPoint pos)
react when an legend item has been selected
MinMaxControl * _xControl
control for the x-axis
Definition: one_d_viewer.h:145
void replot()
redraw the plot
getColor(const QColor &initial, QWidget *parent, const QString &title, ColorDialogOptions options=0)
static DataSource * source(const QString &sourcename=QString())
retrieve an available source
currentTime()
value(const QString &key, const QVariant &defaultValue=QVariant()
MinMaxControl * _yControl
control for the y-axis
Definition: one_d_viewer.h:148
static QStringList sourceNames()
retrieve the names of all current active sources
setWidth(int width)
setDefaultWidget(QWidget *widget)
void setYRangeForLog(bool log)
set up the bounding rect for when y should be log scale
QwtPlotGrid * _grid
a grid in the plot
Definition: one_d_viewer.h:160
an alternative curve plot
Definition: curve_plot.h:26
critical(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons=Ok, StandardButton defaultButton=NoButton)
double max() const
retieve the maximum value
QwtLegend * _legend
a legend for the different curves
Definition: one_d_viewer.h:169
contains a control over min and max values
QList< PlotCurve * > _curves
this plots curves
Definition: one_d_viewer.h:151
contains an alternative curve plot
indexOf(const QRegExp &rx, int from=0)
void setXRangeForLog(bool log)
set up the bounding rect for when x should be log scale
getOpenFileName(QWidget *parent=0, const QString &caption=QString()
insert(int position, const QString &str)
static QString currentSourceName()
return the current source name
void on_add_graph_triggered()
react when addGraph action has been triggered
virtual ~OneDViewer()
destructor
double min() const
retrieve the minimum value
void remove_curve(PlotCurve *curve=0)
remove the curve from the plot
addAction(QAction *action)
contains the wrapper of the data for the 1d viewer
beginGroup(const QString &prefix)
lastIndexOf(const QString &str, int from=-1, Qt::CaseSensitivity cs=Qt::CaseSensitive)
virtual QStringList resultNames()=0
retrieve the list items that can be displayed