BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
QREDataLoader.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/Loaders/QREDataLoader.cpp
6 //! @brief Implements class QREDataLoader
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2021
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Base/Axis/PointwiseAxis.h"
17 #include "Device/Coord/AxisNames.h"
20 #include "GUI/Util/CoordName.h"
24 #include "ui_QREDataLoaderProperties.h"
25 #include <QFile>
26 #include <QString>
27 #include <QTextStream>
28 
29 namespace {
30 
31 //! For emitting a signal on method exit
32 class AutoEmit {
33 public:
34  AutoEmit(std::function<void()> fn)
35  : m_fn(std::move(fn))
36  {
37  }
38  ~AutoEmit() { m_fn(); }
39 
40 private:
41  std::function<void()> m_fn;
42 };
43 
44 QVector<QPair<int, int>> expandLineNumberPattern(const QString& pattern, bool* ok = nullptr)
45 {
46  QVector<QPair<int, int>> result;
47 
48  // splitting "1, 2-3" first on comma-separated tokens
49  for (const auto& token : pattern.split(",")) {
50  const auto parts = token.split("-");
51  // splitting on dash-separated tokens
52  if (!parts.empty()) {
53  // if no "-" is present, make from "1" a pair {1, 1}
54  // if "-" is present, make from "1-2" a pair {1,2}
55  bool ok2 = true;
56  const auto conv0 = parts[0].toInt(&ok2);
57  if (ok2) {
58  const auto conv1 = parts.size() > 1 ? parts[1].toInt(&ok2) : conv0;
59  if (ok2)
60  result.push_back({conv0, conv1});
61  else {
62  if (ok != nullptr) {
63  *ok = false;
64  }
65  return {};
66  }
67  }
68  }
69  }
70 
71  return result;
72 }
73 
74 } // namespace
75 
77  : m_propertiesWidget(nullptr)
78 {
80 }
81 
82 QString QREDataLoader::name() const
83 {
84  return "CSV file (Reflectometry - Q/R/sigma_R)";
85 }
86 
88 {
89  return "QREDataLoader";
90 }
91 
93 {
94  if (m_propertiesWidget == nullptr)
96 
97  auto* l = new QHBoxLayout(parent);
98  l->setContentsMargins(0, 0, 0, 0);
99  parent->setLayout(l);
100  l->addWidget(m_propertiesWidget);
101 
102  if (m_importSettings.separator == " ")
103  m_propertiesWidget->m_ui->separatorCombo->setCurrentText("<SPACE>");
104  else if (m_importSettings.separator == "\t")
105  m_propertiesWidget->m_ui->separatorCombo->setCurrentText("<TAB>");
106  else
107  m_propertiesWidget->m_ui->separatorCombo->setCurrentText(m_importSettings.separator);
108 
109  m_propertiesWidget->m_ui->headerPrefixEdit->setText(m_importSettings.headerPrefix);
110  m_propertiesWidget->m_ui->linesToSkipEdit->setText(m_importSettings.linesToSkip);
111 
112  for (const auto dataType : {DataType::Q, DataType::R, DataType::dR}) {
113  m_propertiesWidget->columnSpinBox((int)dataType)
114  ->setValue(m_importSettings.columnDefinitions[dataType].column + 1); // view is 1-based
115 
116  m_propertiesWidget->factorSpinBox((int)dataType)
117  ->setValue(m_importSettings.columnDefinitions[dataType].factor);
118  }
119 
120  m_propertiesWidget->m_ui->enableErrorCheckBox->setChecked(
122 
124  m_propertiesWidget->m_ui->qUnitCombo->setCurrentIndex(1);
125  else
126  m_propertiesWidget->m_ui->qUnitCombo->setCurrentIndex(0); // 1/nm
127 
130  emit importSettingsChanged();
131  });
132 }
133 
135 {
139 
140  for (const auto dataType : {DataType::Q, DataType::R, DataType::dR}) {
141  m_importSettings.columnDefinitions[dataType].enabled = true;
142  m_importSettings.columnDefinitions[dataType].column = (int)dataType;
144  m_importSettings.columnDefinitions[dataType].factor = 1.0;
145  }
146 
148 }
149 
150 QByteArray QREDataLoader::serialize() const
151 {
152  // changed in version 2: no file hash anymore (1 was only a developer version)
153  // changed in version 3: refactored lists/vectors (2 was only a developer version)
154  // changed in version 4: refactored lists/vectors (3 was only a developer version)
155 
156  QByteArray a;
157  QDataStream s(&a, QIODevice::WriteOnly);
158  s.setVersion(QDataStream::Qt_5_12);
159 
160  s << (quint8)4; // version
161  s << m_fileContent;
162  s << m_importSettings;
163  s << m_importResult.lines;
165  s << m_importResult.qValues;
166  s << m_importResult.rValues;
167  s << m_importResult.eValues;
171  s << m_importResult.error;
173 
174  return a;
175 }
176 
177 void QREDataLoader::deserialize(const QByteArray& data)
178 {
179  m_importSettings.columnDefinitions.clear(); // sufficient
181 
182  QDataStream s(data);
183  s.setVersion(QDataStream::Qt_5_12);
184 
185  quint8 version;
186  s >> version;
187 
188  if (version < 4) // anything smaller 4 was internal developer version => no backwards
189  // compatibility necessary
191 
192  if (version == 4) {
193  s >> m_fileContent;
194  s >> m_importSettings;
195  s >> m_importResult.lines;
197  s >> m_importResult.qValues;
198  s >> m_importResult.rValues;
199  s >> m_importResult.eValues;
203  s >> m_importResult.error;
205  } else
207 
208  if (s.status() != QDataStream::Ok)
210 }
211 
213 {
214  auto* loader = new QREDataLoader();
215  loader->deserialize(serialize());
216  return loader;
217 }
218 
220 {
221  AutoEmit emitter([this] { contentsProcessed(); }); // automatic signal calling in any return
222 
223  // Important: If the current options match the ones in m_parsingResult, then nothing should be
224  // performed. Otherwise e.g. a linked instrument may have to be re-linked
225 
226  m_importResult.error.clear();
227 
228  ASSERT(m_item != nullptr);
229  ASSERT(m_item->isSpecularData());
230 
231  const auto invalidateItemData = [this]() {
233  m_item->specularDataItem()->setDatafield(nullptr);
234  };
235 
236  const bool parsingSettingsChanged =
240  const bool calculationSettingsChanged =
242  const bool calculationIsNecessary = (parsingSettingsChanged || calculationSettingsChanged);
243  const bool creationOfDatafieldIsNecessary = calculationIsNecessary;
244 
245  if (parsingSettingsChanged)
246  // everything has to be re-parsed
248 
249  if (calculationIsNecessary)
251 
253 
254  // -- make a few checks (mainly for fulfilling PointwiseAxis::sanityCheck())
256  m_importResult.error = "At least two full rows must exist";
257 
258  if (!m_importResult.error.isEmpty()) {
259  invalidateItemData();
260  return;
261  }
262 
263  if (creationOfDatafieldIsNecessary) {
264  try {
266  } catch (...) {
267  m_importResult.error = "Import not successful - caught an exception.";
268  invalidateItemData();
269  }
270  }
271 }
272 
274 {
275  return (m_importResult.error.isEmpty() ? 0 : 1) + m_importResult.calculationErrors.size();
276 }
277 
279 {
280  return m_importResult.calculationErrors.size();
281 }
282 
284 {
285  if (!m_importResult.error.isEmpty())
286  return {m_importResult.error};
287 
288  return {};
289 }
290 
292 {
294 }
295 
296 QByteArray QREDataLoader::fileContent() const
297 {
298  return m_fileContent;
299 }
300 
302 {
303  // #baimport - move to utils; create unit test
304  // search for lines which start with a number, then try the separators
305 
306  const auto isFirstNumberChar = [](const QChar& c) {
307  return c.isNumber() || c == '.' || c == '+' || c == '-';
308  };
309 
310  const auto belongsToNumber = [](const QChar& c) {
311  return c.isNumber() || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-';
312  };
313 
314  QTextStream in(m_fileContent);
315  int lineNr = 0;
316  const int maxLinesToExamine = 100;
317  while (!in.atEnd() && lineNr < maxLinesToExamine) {
318  lineNr++;
319  QString line = in.readLine().trimmed();
320  if (line.isEmpty())
321  continue;
322  if (!isFirstNumberChar(line[0]))
323  continue;
324 
325  // line starts with a number => search gap after it
326  int startOfGap = 1;
327  while (startOfGap < line.size() && belongsToNumber(line[startOfGap]))
328  startOfGap++;
329 
330  if (startOfGap == line.size())
331  continue;
332 
333  int endOfGap = startOfGap;
334  while (endOfGap < line.size() && !belongsToNumber(line[endOfGap]))
335  endOfGap++;
336 
337  QStringRef gapContent(&line, startOfGap, endOfGap - startOfGap);
338  if (gapContent.isEmpty())
339  continue;
340 
341  if (gapContent.contains("\t")) {
343  return;
344  }
345 
346  gapContent = gapContent.trimmed();
347  if (gapContent.isEmpty()) {
349  return;
350  }
351 
352  if (gapContent.contains(";")) {
354  return;
355  }
356 
357  if (gapContent.contains(",")) {
359  return;
360  }
361  }
362 }
363 
364 void QREDataLoader::setFileContents(const QByteArray& fileContent)
365 {
367 }
368 
370 {
372 
373  const QStringList headerPrefixes = (m_importSettings.headerPrefix.trimmed().isEmpty())
374  ? QStringList()
375  : m_importSettings.headerPrefix.split(",");
376 
377  const auto lineIsHeader = [headerPrefixes](const QString& line) {
378  for (const auto& prefix : headerPrefixes) {
379  if (line.startsWith(prefix.trimmed()))
380  return true;
381  }
382 
383  return false;
384  };
385 
386  const auto skippedLines = expandLineNumberPattern(m_importSettings.linesToSkip);
387  const auto lineShouldBeSkipped = [skippedLines](int lineNr) {
388  for (const auto& pair : skippedLines) {
389  if (lineNr >= pair.first && lineNr <= pair.second)
390  return true;
391  }
392  return false;
393  };
394 
395  QTextStream in(m_fileContent);
396  int lineNr = 0;
397  // if separator is SPACE: e.g. three consecutive SPACEs do not represent 3 columns => delete
398  // empty parts
399  QString::SplitBehavior splitBehavior =
400  m_importSettings.separator == " " ? QString::SkipEmptyParts : QString::KeepEmptyParts;
401 
402  while (!in.atEnd()) {
403  lineNr++;
404 
405  QString line = in.readLine();
406 
407  const bool skip =
408  lineIsHeader(line) || lineShouldBeSkipped(lineNr) || line.trimmed().isEmpty();
409 
410  m_importResult.lines << qMakePair(skip, line);
411  }
412 
414 
415  for (int lineNr = 0; lineNr < m_importResult.lines.size(); lineNr++) {
416  const bool skip = m_importResult.lines[lineNr].first;
417  if (skip)
418  continue;
419 
420  const QStringList lineEntries =
421  m_importResult.lines[lineNr].second.split(m_importSettings.separator, splitBehavior);
422 
424  std::max(m_importResult.maxColumnCount, lineEntries.count());
425 
426  QVector<double> rowEntriesAsDouble;
427 
428  for (int col = 0; col < lineEntries.count(); col++) {
429  bool ok = false;
430  double val = lineEntries[col].toDouble(&ok);
431  if (!ok)
432  val = std::numeric_limits<double>::quiet_NaN();
433 
434  rowEntriesAsDouble << val;
435  }
436 
437  m_importResult.rawValues[lineNr] = rowEntriesAsDouble;
438  }
439 }
440 
442 {
447 
448  // -- calculate the Q/R/E values (take from specified column, use factor)
449  const auto& c = m_importSettings.columnDefinitions; // easier access
450  const bool errorColumnIsEnabled = c[DataType::dR].enabled;
451  const double unitFac = (c[DataType::Q].unit == UnitInFile::perAngstrom) ? 10.0 : 1.0;
452  const double qFactor = c[DataType::Q].factor * unitFac;
453  const double rFactor = c[DataType::R].factor;
454  const double eFactor = c[DataType::dR].factor;
455 
456  const int qCol = c[DataType::Q].column;
457  const int rCol = c[DataType::R].column;
458  const int eCol = c[DataType::dR].column;
459 
460  QSet<double> foundQValues;
461 
462  for (int lineNr = 0; lineNr < m_importResult.lines.size(); lineNr++) {
463  const bool skipLine = m_importResult.lines[lineNr].first;
464  if (skipLine)
465  continue;
466 
467  const auto& rawValues = m_importResult.rawValues[lineNr];
468 
469  const bool qColIsValid = qCol >= 0 && qCol < rawValues.size();
470  const bool rColIsValid = rCol >= 0 && rCol < rawValues.size();
471  const bool eColIsValid = eCol >= 0 && eCol < rawValues.size();
472 
473  const double q =
474  qColIsValid ? rawValues[qCol] * qFactor : std::numeric_limits<double>::quiet_NaN();
475  const double r =
476  rColIsValid ? rawValues[rCol] * rFactor : std::numeric_limits<double>::quiet_NaN();
477  const double e =
478  eColIsValid ? rawValues[eCol] * eFactor : std::numeric_limits<double>::quiet_NaN();
479 
480  if (std::isnan(q)) {
482  qCol + 1);
483  continue;
484  }
485 
486  if (std::isnan(r)) {
488  rCol + 1);
489  continue;
490  }
491 
492  if (std::isnan(e) && errorColumnIsEnabled) {
494  eCol + 1);
495  continue;
496  }
497 
498  if (foundQValues.contains(q)) {
500  continue;
501  }
502 
503  if (r > 1.0 && !m_importSettings.allowValuesGreaterOne) {
505  continue;
506  }
507 
508  if (r < 0.0) {
510  continue;
511  }
512 
513  m_importResult.qValues[lineNr] = q;
514  m_importResult.rValues[lineNr] = r;
515  m_importResult.eValues[lineNr] = e;
517  foundQValues << q;
518  }
519 }
520 
522 {
523  // create data sorted by ascending Q values.
524  // For this, the line numbers are sorted by Q
525  QVector<int> lineNumbers;
526  for (int lineNr = 0; lineNr < m_importResult.lines.size(); lineNr++) {
527  const bool skipLine = m_importResult.lines[lineNr].first;
528  const bool lineHasError = m_importResult.calculationErrors.contains(lineNr);
529  if (skipLine || lineHasError)
530  continue;
531 
532  lineNumbers.push_back(lineNr);
533  }
534 
535  std::sort(lineNumbers.begin(), lineNumbers.end(),
536  [&](int a, int b) { return m_importResult.qValues[a] < m_importResult.qValues[b]; });
537 
538  // -- create Datafield
539  std::vector<double> qVec;
540  std::vector<double> rVec;
541 
542  for (auto lineNr : lineNumbers) {
543  qVec.push_back(m_importResult.qValues[lineNr]);
544  rVec.push_back(m_importResult.rValues[lineNr]);
545  }
546  auto* oData = new Datafield({new PointwiseAxis("qVector", qVec)}, rVec);
547 
548  // -- Replacement of item->setImportData(std::move(data));
549  item->initNativeData();
550 
551  QString units_name = GUI::Util::CoordName::nameFromCoord(Coords::QSPACE);
552 
553  // -- Replacement of specularItem->reset(std::move(data));
554  SpecularDataItem* specularItem = item->specularDataItem();
555  ComboProperty combo = ComboProperty() << units_name;
556 
557  specularItem->setAxesUnits(combo);
558 
559  auto label_map = DataUtils::AxisNames::specAxis;
560  const auto xAxisTitle = QString::fromStdString(label_map[Coords::QSPACE]);
561  const auto* const yAxisTitle = "Signal [a.u.]"; // taken from ImportDataInfo::axisLabel
562 
563  specularItem->setXaxisTitle(xAxisTitle);
564  specularItem->setYaxisTitle(yAxisTitle);
565  specularItem->setDatafield(oData); // takes ownership of odata
566  specularItem->setAxesRangeToData();
567 
568  item->setNativeDataUnits(units_name);
569  item->setNativeDatafield(oData->clone()); // also takes ownership
570 }
571 
572 QDataStream& operator<<(QDataStream& stream, const QREDataLoader::ImportSettings& s)
573 {
574  stream << s.serialize();
575  return stream;
576 }
577 
578 QDataStream& operator>>(QDataStream& stream, QREDataLoader::ImportSettings& s)
579 {
580  QByteArray b;
581  stream >> b;
582  s.deserialize(b);
583  return stream;
584 }
585 
587 {
588  if (!m_propertiesWidget)
589  return;
590 
591  auto* const ui = m_propertiesWidget->m_ui;
592 
593  m_importSettings.separator = ui->separatorCombo->currentText();
594  if (m_importSettings.separator == "<TAB>")
596  if (m_importSettings.separator == "<SPACE>")
598 
599  m_importSettings.headerPrefix = ui->headerPrefixEdit->text();
600  m_importSettings.linesToSkip = ui->linesToSkipEdit->text();
601 
602  for (const auto dataType : m_importSettings.columnDefinitions.keys()) {
603  auto& colDef = m_importSettings.columnDefinitions[dataType];
604 
605  colDef.column = m_propertiesWidget->columnSpinBox((int)dataType)->value() - 1;
606  colDef.factor = m_propertiesWidget->factor((int)dataType);
607  }
608 
610  m_propertiesWidget->m_ui->qUnitCombo->currentIndex() == 0 ? UnitInFile::perNanoMeter
612 
614  m_propertiesWidget->m_ui->enableErrorCheckBox->isChecked();
615 }
616 
618 {
619  lines.clear();
620  rawValues.clear();
621  qValues.clear();
622  rValues.clear();
623  eValues.clear();
625  maxColumnCount = 0;
626  calculationErrors.clear();
627  error.clear();
628  importSettings.columnDefinitions.clear(); // sufficient
629 }
630 
632 {
633  qValues.clear();
634  rValues.clear();
635  eValues.clear();
636  calculationErrors.clear();
637  validCalculatedLines = 0;
638 }
639 
641 {
642  calculationErrors[line] = ErrorDefinition(type, data);
643 }
644 
646 {
647  calculationErrors[line] = ErrorDefinition(type, data);
648 }
649 
651 {
652  auto error = calculationErrors.value(line, ErrorDefinition());
653  return error.type == ErrorDefinition::none ? QString() : error.toString();
654 }
655 
657 {
658  return serialize() != other.serialize();
659 }
660 
662 {
663  QByteArray a;
664  QDataStream s(&a, QIODevice::WriteOnly);
665  s.setVersion(QDataStream::Qt_5_12);
666 
667  s << (quint8)1; // version
668  s << separator;
669  s << headerPrefix;
670  s << linesToSkip;
671 
672  s << (quint8)columnDefinitions.count();
673  for (const auto dataType : columnDefinitions.keys()) {
674  s << (quint8)dataType;
675  s << columnDefinitions[dataType].enabled;
676  s << columnDefinitions[dataType].column;
677  s << (quint8)columnDefinitions[dataType].unit;
678  s << columnDefinitions[dataType].factor;
679  }
680 
681  return a;
682 }
683 
684 void QREDataLoader::ImportSettings::deserialize(const QByteArray& data)
685 {
686  columnDefinitions.clear();
687 
688  QDataStream s(data);
689  s.setVersion(QDataStream::Qt_5_12);
690 
691  quint8 version;
692  s >> version;
693 
694  if (version == 1) {
695  s >> separator;
696  s >> headerPrefix;
697  s >> linesToSkip;
698 
699  quint8 nDefs;
700  s >> nDefs;
701  for (int i = 0; i < nDefs; i++) {
702  quint8 dataType;
703  s >> dataType;
704  auto& colDef = columnDefinitions[(DataType)dataType];
705  s >> colDef.enabled;
706  s >> colDef.column;
707  quint8 unit;
708  s >> unit;
709  colDef.unit = UnitInFile(unit);
710  s >> colDef.factor;
711  }
712  } else
714 
715  if (s.status() != QDataStream::Ok)
717 }
718 
720 {
721  return enabled == other.enabled && column == other.column && unit == other.unit
722  && factor == other.factor;
723 }
724 
726  : type(t)
727  , data(d)
728 {
729 }
731  : type(t)
732  , data(d)
733 {
734 }
735 
737 {
738  switch (type) {
739  case columnDoesNotContainValidNumber:
740  return QString("Raw column %1 does not contain a valid number - line is discarded")
741  .arg(std::get<int>(data));
742 
743  case duplicateQ:
744  return QString("The value %1 for Q is duplicate - line is discarded")
745  .arg(std::get<double>(data));
746 
747  case RGreaterOne:
748  return QString("The value %1 for R is greater than 1.0 - line is discarded")
749  .arg(std::get<double>(data));
750 
751  case RLessZero:
752  return QString("The value %1 for R is less than 0 - line is discarded")
753  .arg(std::get<double>(data));
754 
755  default:
756  return "Unspecified error";
757  }
758 }
759 
760 QDataStream& operator<<(QDataStream& stream, const QREDataLoader::ErrorDefinition& s)
761 {
762  stream << (quint8)s.type;
763  if (std::holds_alternative<int>(s.data)) {
764  stream << true;
765  stream << quint32(std::get<int>(s.data));
766  } else {
767  stream << false;
768  stream << qreal(std::get<double>(s.data));
769  }
770 
771  return stream;
772 }
773 
774 QDataStream& operator>>(QDataStream& stream, QREDataLoader::ErrorDefinition& s)
775 {
776  quint8 t;
777  stream >> t;
779  bool isInt = false;
780  stream >> isInt;
781  if (isInt) {
782  quint32 d;
783  stream >> d;
784  s.data = int(d);
785  } else {
786  qreal d;
787  stream >> d;
788  s.data = double(d);
789  }
790 
791  return stream;
792 }
Defines namespace GUI::Util::CoordName.
Defines class DeserializationException.
Defines class AutomaticMultiColumnDataLoader1DProperties.
Defines class QREDataLoaderResultModel.
QDataStream & operator<<(QDataStream &stream, const QREDataLoader::ImportSettings &s)
QDataStream & operator>>(QDataStream &stream, QREDataLoader::ImportSettings &s)
Defines class QREDataLoader.
Defines class RealDataItem.
Defines class SpecularDataItem.
@ other
The unit has no enum value defined in here (e.g. when defined as an explicit string)
Base class for result tables of data loaders. Derive from this class and return an instance in YourDa...
Abstract base class for all data loaders (classes to import real data).
void contentsProcessed()
Emitted whenever contents have been processed.
void importSettingsChanged()
Emitted whenever an import setting changed.
RealDataItem * m_item
The real-data-item which owns this loader. Never delete this!
Custom property to define list of string values with multiple selections. Intended for QVariant.
Definition: ComboProperty.h:25
void setAxesUnits(const ComboProperty &units)
Definition: DataItem.cpp:96
static DeserializationException streamError()
static DeserializationException tooOld()
static DeserializationException tooNew()
Properties widget for the QREDataLoader.
QByteArray fileContent() const override
Returns the original file content. If not available any more (like for legacy project file import),...
QString persistentClassName() const override
A name which can be used for save/load purposes (which will not change ever more)
friend QDataStream & operator<<(QDataStream &stream, const QREDataLoader::ImportSettings &s)
void guessSettings() override
Guess appropriate settings (for example the separator in a CSV file). Is called only once,...
int numLineRelatedErrors() const override
Number of errors related to a specific line. Such an error means that a particular content (line) can...
int numErrors() const override
Number of errors found while processing the content. An error means that either a particular content ...
void initWithDefaultImportSettings() override
Set import settings to defaults.
void setFileContents(const QByteArray &fileContent) override
Sets the file contents to be imported. If the file was a compressed file, then the decompressed conte...
QByteArray serialize() const override
Returns every internal setting so it can be restored completely.
void calculateFromParseResult() const
void deserialize(const QByteArray &data) override
Initialize from serialization data. If any error occurred, then a DeserializationException has to be ...
void applyImportSettings() override
Read all values from the properties UI into the internal variables.
QByteArray m_fileContent
AbstractDataLoader * clone() const override
Create a complete clone, including all internal states.
AbstractDataLoaderResultModel * createResultModel() const override
Create a table model which contains the import information like original file content,...
void datafieldFromParsingResult(RealDataItem *item) const
void populateImportSettingsWidget(QWidget *parent) override
Fills the widget on the import dialog pane. The implementation here in the base class does nothing (m...
QStringList lineUnrelatedErrors() const override
Errors not related to a particular line.
QString name() const override
The name shown in the format selection combo.
QPointer< QREDataLoaderProperties > m_propertiesWidget
struct QREDataLoader::ImportSettings m_importSettings
ImportResult m_importResult
void parseFileContent() const
void processContents() override
Process the file contents. Can be called more than once, e.g. if the import settings have changed....
friend class QREDataLoaderResultModel
friend QDataStream & operator>>(QDataStream &stream, QREDataLoader::ImportSettings &s)
Provides access to experimental data, for display and fitting. Owns an AbstractDataLoader.
Definition: RealDataItem.h:33
void removeNativeData()
void setNativeDatafield(Datafield *data)
takes ownership of data
void initNativeData()
bool isSpecularData() const
void setNativeDataUnits(const QString &units)
SpecularDataItem * specularDataItem()
void setYaxisTitle(const QString &title) override
void setDatafield(Datafield *data) override
The given pointer becomes owned by this class!!
void setXaxisTitle(const QString &title) override
void setAxesRangeToData() override
set zoom range of x,y axes to axes of input data
QString nameFromCoord(Coords units)
Returns axes units names from their domain counterpart.
Definition: CoordName.cpp:36
bool operator==(const ColumnDefinition &other) const
Contains a line related error (stored in the import result). Used for showing line related errors in ...
Definition: QREDataLoader.h:84
std::variant< int, double > data
Additional data; meaning depends on the error type (see implementation of toString() for more informa...
ErrorDefinition(Type t=none, int d=0)
QString toString() const
Human readable error text.
QVector< double > rValues
index is 0-based line number
int maxColumnCount
max found columns in raw data
QString error
error unrelated to lines
void addError(int line, ErrorDefinition::Type type, int data=0)
int validCalculatedLines
number of valid resulting data rows
QVector< QVector< double > > rawValues
index is 0-based line number
QMap< int, ErrorDefinition > calculationErrors
calculation error per line; line is 0-based
QVector< double > eValues
index is 0-based line number
QString errorText(int line) const
ImportSettings importSettings
Settings used for the import.
QVector< double > qValues
index is 0-based line number
QVector< QPair< bool, QString > > lines
bool describes whether line is skipped index is 0-based line number
Settings for importing the file.
Definition: QREDataLoader.h:69
QString separator
column separator
Definition: QREDataLoader.h:70
void deserialize(const QByteArray &data)
bool allowValuesGreaterOne
always true for now (see ##94); could be made configurable later on
Definition: QREDataLoader.h:73
QMap< DataType, ColumnDefinition > columnDefinitions
Definition: QREDataLoader.h:75
QString headerPrefix
prefix denoting header line
Definition: QREDataLoader.h:71
bool operator!=(const ImportSettings &other) const
QString linesToSkip
pattern denoting line to skip (i.e. '1,10-12,42')
Definition: QREDataLoader.h:72