MNE-CPP  0.1.9
A Framework for Electrophysiology
rtfiffrawview.cpp
Go to the documentation of this file.
1 //=============================================================================================================
37 //=============================================================================================================
38 // INCLUDES
39 //=============================================================================================================
40 
41 #include "rtfiffrawview.h"
42 
45 
47 #include <fiff/fiff_info.h>
48 
49 //=============================================================================================================
50 // QT INCLUDES
51 //=============================================================================================================
52 
53 #include <QGridLayout>
54 #include <QHeaderView>
55 #include <QTableView>
56 #include <QMenu>
57 #include <QSvgGenerator>
58 #include <QSettings>
59 #include <QScrollBar>
60 #include <QMouseEvent>
61 
62 #if !defined(NO_QOPENGLWIDGET)
63  #include <QOpenGLWidget>
64 #endif
65 
66 //=============================================================================================================
67 // USED NAMESPACES
68 //=============================================================================================================
69 
70 using namespace DISPLIB;
71 using namespace FIFFLIB;
72 using namespace Eigen;
73 using namespace RTPROCESSINGLIB;
74 
75 //=============================================================================================================
76 // DEFINE MEMBER METHODS
77 //=============================================================================================================
78 
79 RtFiffRawView::RtFiffRawView(const QString& sSettingsPath,
80  QWidget *parent,
81  Qt::WindowFlags f)
82 : AbstractView(parent, f)
83 , m_iT(10)
84 , m_fSamplingRate(1024)
85 , m_fZoomFactor(1.0f)
86 , m_bHideBadChannels(false)
87 , m_iDistanceTimeSpacer(1)
88 , m_iClickPosX(0)
89 {
90  m_sSettingsPath = sSettingsPath;
91  m_pTableView = new QTableView;
92 
93 #if !defined(NO_QOPENGLWIDGET)
94  m_pTableView->setViewport(new QOpenGLWidget);
95 #endif
96 
97  // Install event filter for tracking mouse movements
98  m_pTableView->viewport()->installEventFilter(this);
99  m_pTableView->setMouseTracking(true);
100 
101  // Set layout
102  QVBoxLayout *neLayout = new QVBoxLayout(this);
103  neLayout->addWidget(m_pTableView);
104  neLayout->setContentsMargins(0,0,0,0);
105  this->setLayout(neLayout);
106 
107  loadSettings();
108 }
109 
110 //=============================================================================================================
111 
113 {
114  saveSettings();
115 }
116 
117 //=============================================================================================================
118 
120 {
121 #if !defined(NO_QOPENGLWIDGET)
122  if(m_pTableView) {
123  m_pTableView->setViewport(new QOpenGLWidget);
124  }
125 #endif
126 }
127 
128 //=============================================================================================================
129 
130 void RtFiffRawView::setSettingsPath(const QString& sSettingsPath)
131 {
132  m_sSettingsPath = sSettingsPath;
133  loadSettings();
134 }
135 
136 //=============================================================================================================
137 
138 void RtFiffRawView::init(QSharedPointer<FIFFLIB::FiffInfo> &info)
139 {
140  m_pFiffInfo = info;
141  m_fSamplingRate = m_pFiffInfo->sfreq;
142 
143  //Init the model
144  m_pModel = new RtFiffRawViewModel(this);
145  m_pModel->setFiffInfo(m_pFiffInfo);
146  m_pModel->setSamplingInfo(m_fSamplingRate, m_iT, true);
149  connect(this, &RtFiffRawView::addSampleAsEvent,
150  m_pModel, &RtFiffRawViewModel::addEvent, Qt::UniqueConnection);
151 
152  //Init bad channel list
153  m_qListBadChannels.clear();
154  for(int i = 0; i<m_pModel->rowCount(); i++) {
155  if(m_pModel->data(m_pModel->index(i,2)).toBool()) {
156  m_qListBadChannels << i;
157  }
158  }
159 
160  //Init the delegate
162  m_pDelegate->initPainterPaths(m_pModel);
163 
164  connect(this, &RtFiffRawView::markerMoved,
166 
167  //Init the view
168  m_pTableView->setModel(m_pModel);
169  m_pTableView->setItemDelegate(m_pDelegate);
170  m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
171 
172  connect(m_pTableView.data(), &QTableView::doubleClicked,
174 
175  connect(m_pTableView.data(), &QTableView::customContextMenuRequested,
177 
178  //set some size settings for m_pTableView
179  m_pTableView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
180  m_pTableView->setShowGrid(false);
181  m_pTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); //Stretch 2 column to maximal width
182  m_pTableView->horizontalHeader()->hide();
183  m_pTableView->verticalHeader()->setDefaultSectionSize(m_pTableView->height() / m_fZoomFactor);//Row Height
184  m_pTableView->setAutoScroll(false);
185  m_pTableView->setColumnHidden(0,true); //because content is plotted jointly with column=1
186  m_pTableView->setColumnHidden(2,true);
187  m_pTableView->resizeColumnsToContents();
188  m_pTableView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
189 
190  connect(m_pTableView->verticalScrollBar(), &QScrollBar::valueChanged,
192 }
193 
194 //=============================================================================================================
195 
196 void RtFiffRawView::addData(const QList<Eigen::MatrixXd> &data)
197 {
198  if(!data.isEmpty()) {
199  m_pModel->addData(data);
200 
201  if(m_qListBadChannels.size() != m_pFiffInfo->bads.size()) {
202  m_qListBadChannels.clear();
203  for(int i = 0; i<m_pModel->rowCount(); i++) {
204  if(m_pModel->data(m_pModel->index(i,2)).toBool()) {
205  m_qListBadChannels << i;
206  }
207  }
208 
209  //Hide non selected channels/rows in the data views
210  for(int i = 0; i<m_qListBadChannels.size(); i++) {
211  if(m_bHideBadChannels) {
212  m_pTableView->hideRow(m_qListBadChannels.at(i));
213  } else {
214  m_pTableView->showRow(m_qListBadChannels.at(i));
215  }
216  }
217  }
218  } else {
219  qWarning() << "[RtFiffRawView::addData] Received data list is empty.";
220  }
221 }
222 
223 //=============================================================================================================
224 
226 {
227  return m_pModel->getLastBlock();
228 }
229 
230 //=============================================================================================================
231 
232 bool RtFiffRawView::eventFilter(QObject *object, QEvent *event)
233 {
234 // if (object == m_pTableView->viewport() && event->type() == QEvent::MouseMove) {
235 // QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
236 // emit markerMoved(mouseEvent->pos(), m_pTableView->rowAt(mouseEvent->pos().y()));
237 // return true;
238 // }
239 
240  return QWidget::eventFilter(object, event);
241 }
242 
243 //=============================================================================================================
244 
245 void RtFiffRawView::setBackgroundColor(const QColor& backgroundColor)
246 {
247  m_backgroundColor = backgroundColor;
248 
249  if(m_pModel) {
250  m_pModel->setBackgroundColor(m_backgroundColor);
251  }
252 
253 // QPalette pal;
254 // pal.setColor(QPalette::Window, m_backgroundColor);
255 // m_pTableView->viewport()->setPalette(pal);
256 // m_pTableView->viewport()->setBackgroundRole(QPalette::Window);
257 }
258 
259 //=============================================================================================================
260 
262 {
263  return m_backgroundColor;
264 }
265 
266 //=============================================================================================================
267 
268 QMap<qint32, float> RtFiffRawView::getScalingMap()
269 {
270  return m_qMapChScaling;
271 }
272 
273 //=============================================================================================================
274 
275 void RtFiffRawView::setScalingMap(const QMap<qint32, float>& scaleMap)
276 {
277  m_qMapChScaling = scaleMap;
278  m_pModel->setScaling(scaleMap);
279 }
280 
281 //=============================================================================================================
282 
283 void RtFiffRawView::setSignalColor(const QColor& signalColor)
284 {
285  m_pDelegate->setSignalColor(signalColor);
286 }
287 
288 //=============================================================================================================
289 
291 {
292  return m_pDelegate->getSignalColor();
293 }
294 
295 //=============================================================================================================
296 
298 {
299  if(m_bHideBadChannels) {
300  m_bHideBadChannels = false;
301  } else {
302  m_bHideBadChannels = true;
303  }
304 
305  //Hide non selected channels/rows in the data views
306  for(int i = 0; i<m_qListBadChannels.size(); i++) {
307  if(m_bHideBadChannels) {
308  m_pTableView->hideRow(m_qListBadChannels.at(i));
309  } else {
310  m_pTableView->showRow(m_qListBadChannels.at(i));
311  }
312  }
313 
314  //Update the visible channel list which are to be filtered
316 }
317 
318 //=============================================================================================================
319 
321 {
322  return m_bHideBadChannels;
323 }
324 
325 //=============================================================================================================
326 
327 void RtFiffRawView::showSelectedChannelsOnly(const QStringList &selectedChannels)
328 {
329  m_slSelectedChannels = selectedChannels;
330 
331  //Hide non selected channels/rows in the data views
332  for(int i = 0; i<m_pModel->rowCount(); i++) {
333  QString channel = m_pModel->data(m_pModel->index(i, 0), Qt::DisplayRole).toString();
334 
335  //if channel is a bad channel and bad channels are to be hidden -> do not show
336  if(!selectedChannels.contains(channel) || (m_qListBadChannels.contains(i) && m_bHideBadChannels)) {
337  m_pTableView->hideRow(i);
338  } else {
339  m_pTableView->showRow(i);
340  }
341  }
342 
343  //Update the visible channel list which are to be filtered
345 }
346 
347 //=============================================================================================================
348 
349 void RtFiffRawView::setZoom(double zoomFac)
350 {
351  m_fZoomFactor = zoomFac;
352 
353  m_pTableView->verticalHeader()->setDefaultSectionSize(m_pTableView->height() / m_fZoomFactor);//Row Height
354 }
355 
356 //=============================================================================================================
357 
359 {
360  return m_fZoomFactor;
361 }
362 
363 //=============================================================================================================
364 
366 {
367  m_iT = T;
368 
369  m_pModel->setSamplingInfo(m_fSamplingRate, T);
370 }
371 
372 //=============================================================================================================
373 
375 {
376  return m_iT;
377 }
378 
379 //=============================================================================================================
380 
382 {
383  return m_fSamplingRate;
384 }
385 
386 //=============================================================================================================
387 
388 void RtFiffRawView::takeScreenshot(const QString& fileName)
389 {
390  if(fileName.contains(".svg", Qt::CaseInsensitive)) {
391  // Generate screenshot
392  QSvgGenerator svgGen;
393  svgGen.setFileName(fileName);
394  svgGen.setSize(m_pTableView->size());
395  svgGen.setViewBox(m_pTableView->rect());
396 
397  m_pTableView->render(&svgGen);
398  }
399 
400  if(fileName.contains(".png", Qt::CaseInsensitive)) {
401  QPixmap pixMap(m_pTableView->grab());
402  pixMap.save(fileName);
403  }
404 }
405 
406 //=============================================================================================================
407 
408 void RtFiffRawView::updateProjection(const QList<FIFFLIB::FiffProj>& projs)
409 {
410  m_pModel->updateProjection(projs);
411 }
412 
413 //=============================================================================================================
414 
416 {
417  m_pModel->updateCompensator(to);
418 }
419 
420 //=============================================================================================================
421 
423 {
424  m_pModel->updateSpharaActivation(state);
425 }
426 
427 //=============================================================================================================
428 
429 void RtFiffRawView::updateSpharaOptions(const QString& sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
430 {
431  m_pModel->updateSpharaOptions(sSytemType, nBaseFctsFirst, nBaseFctsSecond);
432 }
433 
434 //=============================================================================================================
435 
436 void RtFiffRawView::setFilter(const FilterKernel& filterData)
437 {
438  m_pModel->setFilter(QList<FilterKernel>() << filterData);
439 }
440 
441 //=============================================================================================================
442 
444 {
445  m_pModel->setFilterActive(state);
446 }
447 
448 //=============================================================================================================
449 
450 void RtFiffRawView::setFilterChannelType(const QString &channelType)
451 {
452  m_pModel->setFilterChannelType(channelType);
453 }
454 
455 //=============================================================================================================
456 
457 void RtFiffRawView::triggerInfoChanged(const QMap<double, QColor>& colorMap,
458  bool active,
459  const QString &triggerCh,
460  double threshold)
461 {
462  m_pModel->triggerInfoChanged(colorMap, active, triggerCh, threshold);
463 }
464 
465 //=============================================================================================================
466 
468 {
469  m_iDistanceTimeSpacer = value;
470  m_pModel->distanceTimeSpacerChanged(value);
471 }
472 
473 //=============================================================================================================
474 
476 {
477  return m_iDistanceTimeSpacer;
478 }
479 
480 //=============================================================================================================
481 
483 {
484  m_pModel->resetTriggerCounter();
485 }
486 
487 //=============================================================================================================
488 
490 {
491  if(m_sSettingsPath.isEmpty()) {
492  return;
493  }
494 
495  QSettings settings("MNECPP");
496 }
497 
498 //=============================================================================================================
499 
501 {
502  if(m_sSettingsPath.isEmpty()) {
503  return;
504  }
505 
506  QSettings settings("MNECPP");
507 }
508 
509 //=============================================================================================================
510 
512 {
513  switch(mode) {
514  case GuiMode::Clinical:
515  break;
516  default: // default is research mode
517  break;
518  }
519 }
520 
521 //=============================================================================================================
522 
523 void RtFiffRawView::updateProcessingMode(ProcessingMode mode)
524 {
525  switch(mode) {
526  case ProcessingMode::Offline:
527  break;
528  default: // default is realtime mode
529  break;
530  }
531 }
532 
533 //=============================================================================================================
534 
536 {
537  m_iClickPosX = pos.x();
538 
539  //obtain index where index was clicked
540  QModelIndex index = m_pTableView->indexAt(pos);
541 
542  //get selected items
543  QModelIndexList selected = m_pTableView->selectionModel()->selectedIndexes();
544 
545  //create custom context menu and actions
546  QMenu *menu = new QMenu(this);
547 
548  menu->addSection("Events");
549 
550  QAction* addEventMarker = menu->addAction(tr("Add event"));
551  connect(addEventMarker, &QAction::triggered,
553 
554  //Marking
555 
556  menu->addSection("Channel Marking");
557 
558  if(!m_qListBadChannels.contains(index.row())) {
559  QAction* doMarkChBad = menu->addAction(tr("Mark as bad"));
560  connect(doMarkChBad, &QAction::triggered,
561  this, &RtFiffRawView::markChBad);
562  } else {
563  QAction* doMarkChGood = menu->addAction(tr("Mark as good"));
564  connect(doMarkChGood, &QAction::triggered,
565  this, &RtFiffRawView::markChBad);
566  }
567 
568  // non C++11 alternative
569  m_qListCurrentSelection.clear();
570  for(qint32 i = 0; i < selected.size(); ++i)
571  if(selected[i].column() == 1)
572  m_qListCurrentSelection.append(m_pModel->getIdxSelMap()[selected[i].row()]);
573 
574  menu->addSection("Selection");
575 
576  QAction* doSelection = menu->addAction(tr("Only show selection"));
577  connect(doSelection, &QAction::triggered,
579 
580  //select channels
581  QAction* hideSelection = menu->addAction(tr("Hide selection"));
582  connect(hideSelection, &QAction::triggered, this,
584 
585  //undo selection
586  QAction* resetAppliedSelection = menu->addAction(tr("Reset selection"));
587  connect(resetAppliedSelection, &QAction::triggered,
589  connect(resetAppliedSelection, &QAction::triggered,
591 
592  //show context menu
593  menu->popup(m_pTableView->viewport()->mapToGlobal(pos));
594 }
595 
596 //=============================================================================================================
597 
599 {
600  //Hide non selected channels/rows in the data views
601  for(int i = 0; i<m_pModel->rowCount(); i++) {
602  //if channel is a bad channel and bad channels are to be hidden -> do not show
603  if(m_qListCurrentSelection.contains(i)) {
604  m_pTableView->showRow(i);
605  } else {
606  m_pTableView->hideRow(i);
607  }
608  }
609 
610  //Update the visible channel list which are to be filtered
611  //visibleRowsChanged();
612 
613  //m_pModel->selectRows(m_qListCurrentSelection);
614 }
615 
616 //=============================================================================================================
617 
619 {
620  for(int i=0; i<m_qListCurrentSelection.size(); i++) {
621  m_pTableView->hideRow(m_qListCurrentSelection.at(i));
622  }
623 
624  //Update the visible channel list which are to be filtered
625  //visibleRowsChanged();
626 }
627 
628 //=============================================================================================================
629 
631 {
632  // non C++11 alternative
633  for(qint32 i = 0; i < m_pFiffInfo->chs.size(); ++i) {
634  if(m_qListBadChannels.contains(i)) {
635  if(!m_bHideBadChannels) {
636  m_pTableView->showRow(i);
637  }
638  } else {
639  m_pTableView->showRow(i);
640  }
641  }
642 
643  //Update the visible channel list which are to be filtered
644  //visibleRowsChanged();
645 }
646 
647 //=============================================================================================================
648 
650 {
651  if(!m_pTableView || !m_pModel || !m_pDelegate) {
652  return;
653  }
654 
655  int from = m_pTableView->rowAt(0);
656 // if(from != 0){
657 // from--;
658 
659  int to = m_pTableView->rowAt(m_pTableView->height()-1);
660  if(to != m_pModel->rowCount()-1)
661  to++;
662 
663  if(from > to)
664  to = m_pModel->rowCount()-1;
665 
666 // //Update visible rows in order to only filter the visible rows
667 // QStringList channelNames;
668 
669 // for(int i = from; i<=to; i++) {
670 // channelNames << m_pModel->data(m_pModel->index(i, 0), Qt::DisplayRole).toString();
671 // }
672 
673 // m_pModel->createFilterChannelList(channelNames);
674 
675  m_pDelegate->setUpperItemIndex(from/*+1*/);
676 
677  //qDebug() <<"RtFiffRawView::visibleRowsChanged - from "<< from << " to" << to;
678 }
679 
680 //=============================================================================================================
681 
683 {
684  QModelIndexList selected = m_pTableView->selectionModel()->selectedIndexes();
685 
686  for(int i=0; i<selected.size(); i++) {
687  if(m_qListBadChannels.contains(selected[i].row())) { //mark as good
688  m_pModel->markChBad(selected[i], false);
689  m_qListBadChannels.removeAll(selected[i].row());
690  }
691  else {
692  m_pModel->markChBad(selected[i], true);
693  m_qListBadChannels.append(selected[i].row());
694  }
695  }
696 
697  m_pModel->updateProjection(m_pFiffInfo->projs);
698 
699  //Hide non selected channels/rows in the data views
700  for(int i = 0; i<m_qListBadChannels.size(); i++) {
701  if(m_bHideBadChannels) {
702  m_pTableView->hideRow(m_qListBadChannels.at(i));
703  } else {
704  m_pTableView->showRow(m_qListBadChannels.at(i));
705  }
706  }
707 
708  emit channelMarkingChanged();
709 }
710 
711 //=============================================================================================================
712 
714 {
715 
716 }
717 
718 //=============================================================================================================
719 
720 void RtFiffRawView::onAddEvent(bool bChecked)
721 {
722  Q_UNUSED(bChecked)
723  double dDx = static_cast<double>(m_pTableView->columnWidth(1)) / static_cast<double>(m_pModel->getMaxSamples());
724  double dSample = static_cast<double>(m_iClickPosX) / dDx;
725 
726  int iFirstSampleOffset = m_pModel->getFirstSampleOffset();
727 
728  // Dont allow adding events to blank space in the beginning
729  if (dSample > m_pModel->getCurrentSampleIndex() && iFirstSampleOffset == 0){
730  return;
731  }
732 
733  //Add offset
734  int iAbsoluteSample = static_cast<int>(dSample) + iFirstSampleOffset;
735 
736  //Account for whether adding before or after draw point
737  if (dSample > m_pModel->getCurrentSampleIndex()){
738  iAbsoluteSample -= m_pModel->getMaxSamples();
739  }
740 
741  qDebug() << "EVENT SAMPLE:" << iAbsoluteSample;
742 
743  emit addSampleAsEvent(iAbsoluteSample);
744 }
void setDistanceTimeSpacer(int value)
The FilterKernel class represents a filter object that generates the FIR filter coefficients using Pa...
The RtFiffRawViewDelegate class represents a RTMSA delegate which creates the plot paths...
QMap< qint32, float > getScalingMap()
void setFilter(const RTPROCESSINGLIB::FilterKernel &filterData)
void onAddEvent(bool bChecked)
void setSignalColor(const QColor &signalColor)
void triggerDetected(int numberDetectedTriggers, const QMap< int, QList< QPair< int, double > > > &mapDetectedTriggers)
void setZoom(double zoomFac)
QSharedPointer< FIFFLIB::FiffInfo > m_pFiffInfo
void toggleFreeze(const QModelIndex &index)
void setFilterChannelType(const QString &channelType)
void updateProcessingMode(ProcessingMode mode)
void setFilterActive(bool state)
The FilterKernel class provides methods to create/design a FIR filter kernel.
Definition: filterkernel.h:132
void addData(const QList< Eigen::MatrixXd > &data)
void updateSpharaOptions(const QString &sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
void markerMoved(QPoint position, int activeRow)
QList< qint32 > m_qListBadChannels
QMap< qint32, float > m_qMapChScaling
void triggerDetected(int numberDetectedTriggers, const QMap< int, QList< QPair< int, double > > > &mapDetectedTriggers)
QPointer< DISPLIB::RtFiffRawViewDelegate > m_pDelegate
void updateCompensator(int to)
The RtFiffRawViewModel class implements the data access model for a real-time multi sample array data...
RtFiffRawView(const QString &sSettingsPath="", QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
void updateSpharaActivation(bool state)
Declaration of the RtFiffRawViewModel Class.
void setBackgroundColor(const QColor &backgroundColor)
void setScalingMap(const QMap< qint32, float > &scaleMap)
QPointer< QTableView > m_pTableView
Eigen::MatrixXd getLastBlock()
void updateGuiMode(GuiMode mode)
void triggerInfoChanged(const QMap< double, QColor > &colorMap, bool active, const QString &triggerCh, double threshold)
QList< qint32 > m_qListCurrentSelection
float getSamplingFreq() const
bool eventFilter(QObject *object, QEvent *event)
void showSelectedChannelsOnly(const QStringList &selectedChannels)
void markerMoved(QPoint position, int activeRow)
void channelContextMenu(QPoint pos)
Declaration of the RtFiffRawViewDelegate Class.
QStringList m_slSelectedChannels
void init(QSharedPointer< FIFFLIB::FiffInfo > &info)
FiffInfo class declaration.
void updateProjection(const QList< FIFFLIB::FiffProj > &projs)
void takeScreenshot(const QString &fileName)
void setSettingsPath(const QString &sSettingsPath)
QPointer< DISPLIB::RtFiffRawViewModel > m_pModel
The AbstractView class provides the base calss for all Disp viewers.
Definition: abstractview.h:75
Declaration of the RtFiffRawView Class.