BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
SpecularDataImportWidget.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/Import/SpecularDataImportWidget.cpp
6 //! @brief Implements class SpecularDataImportWidget
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 
26 #include "ui_SpecularDataImportWidget.h"
27 #include <QAction>
28 #include <QBoxLayout>
29 #include <QFileDialog>
30 #include <QMenu>
31 #include <QStringListModel>
32 #include <QTextStream>
33 #include <QTimer>
34 
36  : SessionItemWidget(parent)
37  , m_ui(new Ui::SpecularDataImportWidget)
38  , m_loader(nullptr)
39 {
40  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
41 
42  m_ui->setupUi(this);
43  m_ui->warningsIcon->setFixedSize(20, 20);
44  m_ui->warningsIcon->setPixmap(QPixmap(":/images/warning_16x16.png"));
45 
46  m_ui->linkedInstrumentGroup->hide(); // #baimport - remove from UI if not used in the future
47 
48  // #baUserDefLoaders - remove next line when implementation is complete
49  m_ui->createNewFormatButton->hide();
50 
53 
54  connect(m_ui->formatSelectionComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
56  connect(m_ui->createNewFormatButton, &QPushButton::clicked, this,
58 
59  connect(m_ui->originalRowCheckBox, &QCheckBox::stateChanged, this,
61 
62  connect(m_ui->rawDataCheckBox, &QCheckBox::stateChanged, this,
64 
65  connect(m_ui->calculatedDataCheckBox, &QCheckBox::stateChanged, this,
67 
68  connect(m_ui->specularDataCanvas->customPlot(), &QCustomPlot::axisClick, this,
70 
71  m_ui->specularDataCanvas->enableDeprecatedOnMousePress(false); // we have an own handler
72 
73  m_ui->plotToolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
74  for (auto* action : m_ui->specularDataCanvas->actionList())
75  m_ui->plotToolbar->addAction(action);
76 }
77 
79 {
80  SessionItemWidget::setItem(_realDataItem);
81  m_ui->specularDataCanvas->setItem(specularDataItem());
82 
84  ASSERT(m_loader); // only items which have a loader are allowed for this widget. Every other
85  // items do not support this widget
86 
88 
89  QSignalBlocker b(m_ui->formatSelectionComboBox);
90  m_ui->formatSelectionComboBox->setCurrentText(m_loader->name());
91 
93  updatePreview();
96 }
97 
99 {
100  return {};
101 }
102 
104 {
105  QMenu menu;
106  for (auto* action : actionList())
107  menu.addAction(action);
108  menu.exec(point);
109 }
110 
111 void SpecularDataImportWidget::onPlotAxisClicked(QCPAxis* axis, QCPAxis::SelectablePart /*part*/,
112  QMouseEvent* event)
113 {
114  if (event->button() == Qt::RightButton && axis->axisType() == QCPAxis::atLeft) {
115  QMenu menu;
116 
117  auto* lin = new QAction("Linear");
118  connect(lin, &QAction::triggered, [=]() { specularDataItem()->setLog(false); });
119  lin->setCheckable(true);
120  lin->setChecked(!specularDataItem()->isLog());
121 
122  auto* log = new QAction("Logarithmic");
123  connect(log, &QAction::triggered, [=]() { specularDataItem()->setLog(true); });
124  log->setCheckable(true);
125  log->setChecked(specularDataItem()->isLog());
126 
127  auto* ag = new QActionGroup(&menu);
128  ag->addAction(lin);
129  ag->addAction(log);
130 
131  menu.addAction(lin);
132  menu.addAction(log);
133 
134  menu.exec(event->globalPos());
135  }
136 }
137 
139 {
141 }
142 
144 {
145  return dynamic_cast<const RealDataItem*>(currentItem());
146 }
147 
149 {
150  return dynamic_cast<RealDataItem*>(currentItem());
151 }
152 
154 {
155  QSignalBlocker b(m_ui->formatSelectionComboBox);
156  m_ui->formatSelectionComboBox->clear();
157  for (auto* loader : DataLoaders1D::instance().recentlyUsedLoaders())
158  m_ui->formatSelectionComboBox->addItem(loader->name());
159  for (auto* loader : DataLoaders1D::instance().loaders())
160  m_ui->formatSelectionComboBox->addItem(loader->name());
161 
162  // e.g. legacy loader is not present in the combo by default. Add it here so it can be selected
163  if (m_loader != nullptr)
164  if (m_ui->formatSelectionComboBox->findText(m_loader->name()) < 0)
165  m_ui->formatSelectionComboBox->addItem(m_loader->name());
166 }
167 
169 {
170  for (auto* child : m_ui->propertiesWidget->children())
171  delete child;
172 
173  if (m_ui->propertiesWidget->layout())
174  delete m_ui->propertiesWidget->layout();
175 
176  if (m_loader)
177  m_loader->populateImportSettingsWidget(m_ui->propertiesWidget);
178 
179  const bool hasChildren = !m_ui->propertiesWidget->children().empty();
180 
181  m_ui->propertiesWidget->setVisible(hasChildren);
182 }
183 
185 {
186  const QString name = m_ui->formatSelectionComboBox->currentText();
187 
188  for (auto* loader : DataLoaders1D::instance().loaders())
189  if (name == loader->name())
190  return loader;
191 
192  return nullptr;
193 }
194 
196 {
197  if (m_loader && m_loader->fileContent().isEmpty()) {
198  QSignalBlocker b(m_ui->formatSelectionComboBox);
199  m_ui->formatSelectionComboBox->setCurrentText(m_loader->name());
200 
202  "Changing the loader is not possible because the original file "
203  "contents are not available any more.");
204 
205  return;
206  }
207 
208  if (m_loader)
209  m_loader->disconnect(this);
210 
211  m_loader = dynamic_cast<AbstractDataLoader1D*>(selectedLoader()->clone());
216  QApplication::setOverrideCursor(Qt::WaitCursor);
219  QApplication::restoreOverrideCursor();
220 
222  updatePreview();
225 }
226 
228 {
229  QApplication::setOverrideCursor(Qt::WaitCursor);
230 
231  if (m_loader) {
232  auto* oldModel = m_ui->dataResultView->selectionModel(); // sic!! according to Qt docu
233  // of QAbstractItemView::setModel
234  auto* resultModel = m_loader->createResultModel();
235  if (resultModel != nullptr) {
236  const auto originalSections = resultModel->sectionsOfColumnType(
238 
239  const auto rawSections =
240  resultModel->sectionsOfColumnType(AbstractDataLoaderResultModel::ColumnType::raw);
241 
242  const auto processedSections = resultModel->sectionsOfColumnType(
244 
245  QSignalBlocker b1(m_ui->originalRowCheckBox);
246  QSignalBlocker b2(m_ui->rawDataCheckBox);
247  QSignalBlocker b3(m_ui->calculatedDataCheckBox);
248 
249  if (originalSections.isEmpty()) {
250  m_ui->originalRowCheckBox->setChecked(false);
251  m_ui->originalRowCheckBox->setEnabled(false);
252  } else
253  m_ui->originalRowCheckBox->setEnabled(true);
254 
255  if (rawSections.isEmpty()) {
256  m_ui->rawDataCheckBox->setChecked(false);
257  m_ui->rawDataCheckBox->setEnabled(false);
258  } else
259  m_ui->rawDataCheckBox->setEnabled(true);
260 
261  if (processedSections.isEmpty()) {
262  m_ui->calculatedDataCheckBox->setChecked(false);
263  m_ui->calculatedDataCheckBox->setEnabled(false);
264  } else
265  m_ui->calculatedDataCheckBox->setEnabled(true);
266 
267  m_ui->dataResultView->setModel(resultModel);
268  auto* horHeader = m_ui->dataResultView->horizontalHeader();
269 
270  for (int section : originalSections)
271  horHeader->setSectionHidden(section, !m_ui->originalRowCheckBox->isChecked());
272 
273  for (int section : rawSections)
274  horHeader->setSectionHidden(section, !m_ui->rawDataCheckBox->isChecked());
275 
276  for (int section : processedSections)
277  horHeader->setSectionHidden(section, !m_ui->calculatedDataCheckBox->isChecked());
278 
279  // if the result model has a line column, then do not show the vertical header view
280  const bool hasLinesColumn =
281  !resultModel->sectionsOfColumnType(AbstractDataLoaderResultModel::ColumnType::line)
282  .isEmpty();
283  m_ui->dataResultView->verticalHeader()->setHidden(hasLinesColumn);
284 
285  m_ui->dataResultView->resizeColumnsToContents();
286  } else
287  m_ui->dataResultView->setModel(nullptr);
288 
289  delete oldModel;
290  }
291 
292  if (m_loader && m_loader->numErrors() > 0) {
293  m_ui->warningsIcon->show();
294  m_ui->warningsLabel->show();
295  m_ui->warningsListWidget->show();
296  m_ui->warningsListWidget->clear();
297 
298  auto warnings = m_loader->lineUnrelatedErrors();
299  const int nLineRelatedWarnings = m_loader->numErrors() - warnings.size();
300 
301  if (nLineRelatedWarnings == 1)
302  warnings << "1 line related warning. Please check the data tab on the right for more "
303  "information.";
304  else if (nLineRelatedWarnings > 1)
305  warnings
306  << QString(
307  "%1 line related warnings. Please check the data tab on the right for more "
308  "information.")
309  .arg(nLineRelatedWarnings);
310 
311  if (warnings.size() > 1)
312  for (auto& w : warnings)
313  w.prepend("* ");
314 
315  for (auto& w : warnings)
316  new QListWidgetItem(w, m_ui->warningsListWidget);
317  } else {
318  m_ui->warningsIcon->hide();
319  m_ui->warningsLabel->hide();
320  m_ui->warningsListWidget->hide();
321  }
322 
323  QApplication::restoreOverrideCursor();
324 }
325 
327 {
328  bool ok;
329  QString name = QInputDialog::getText(
330  this, "New format", "Please enter a name for the new format", QLineEdit::Normal, "", &ok);
331  if (!ok || name.isEmpty())
332  return;
333 
335 
336  fillLoaderCombo();
337  m_ui->formatSelectionComboBox->setCurrentText(name);
339 }
340 
342 {
343  m_loader->applyImportSettings(); // #baimport: may be duplicate
344  QApplication::setOverrideCursor(Qt::WaitCursor);
346  QApplication::restoreOverrideCursor();
347 
348  // If there is a linked instrument, any change in import settings can break the compatibility.
349  // Therefore check the compatibility and break the link if necessary
350  ASSERT(gSessionData->projectDocument.has_value());
351  const auto* linkedInstrument =
352  gSessionData->projectDocument.value()->collectedItems()->findInstrumentById(
353  realDataItem()->instrumentId());
354 
355  if (linkedInstrument != nullptr)
356  if (!linkedInstrument->alignedWith(realDataItem()))
358 
359 
360  updatePreview();
361 }
362 
364 {
365  return realDataItem()->nativeFileName();
366 }
Defines class AbstractDataLoaderResultModel.
Defines functions in namespace GUI::Model::DataItemUtils.
void cloneAsUserDefinedLoader(AbstractDataLoader1D *loader, const QString &name)
clones the loader as a user defined loader and puts it in DataLoaders1D store
Utility functions for data loaders.
Defines class DataLoaders1D.
Defines global pointers.
Defines class InstrumentItem and all its children.
Defines class ProjectDocument.
Defines class RealDataItem.
SessionData * gSessionData
global pointer to the single instance
Definition: SessionData.cpp:17
Defines struct SessionData.
Defines class SpecularDataImportWidget.
Defines class SpecularDataItem.
Abstract base class for reflectometry data loaders.
QVector< int > sectionsOfColumnType(ColumnType type) const
The table header sections which belong to the given column type. Empty if this column type is not pre...
Abstract base class for all data loaders (classes to import real data).
virtual void applyImportSettings()
Read all values from the properties UI into the internal variables.
virtual void populateImportSettingsWidget(QWidget *parent)
Fills the widget on the import dialog pane. The implementation here in the base class does nothing (m...
virtual AbstractDataLoaderResultModel * createResultModel() const
Create a table model which contains the import information like original file content,...
virtual void guessSettings()
Guess appropriate settings (for example the separator in a CSV file). Is called only once,...
void importSettingsChanged()
Emitted whenever an import setting changed.
virtual QString name() const =0
The name shown in the format selection combo.
virtual void setFileContents(const QByteArray &fileContent)=0
Sets the file contents to be imported. If the file was a compressed file, then the decompressed conte...
virtual int numErrors() const
Number of errors found while processing the content. An error means that either a particular content ...
virtual void processContents()=0
Process the file contents. Can be called more than once, e.g. if the import settings have changed....
virtual void initWithDefaultImportSettings()
Set import settings to defaults.
virtual QByteArray fileContent() const
Returns the original file content. If not available any more (like for legacy project file import),...
virtual QStringList lineUnrelatedErrors() const
Errors not related to a particular line.
virtual AbstractDataLoader * clone() const =0
Create a complete clone, including all internal states.
void setRealDataItem(RealDataItem *item)
Define the real data item on which the import shall work.
static DataLoaders1D & instance()
The one and only instance.
Provides access to experimental data, for display and fitting. Owns an AbstractDataLoader.
Definition: RealDataItem.h:33
void unlinkFromInstrument()
AbstractDataLoader * dataLoader() const
QString nativeFileName() const
void setDataLoader(AbstractDataLoader *loader)
Takes ownership of loader.
The SessionItemWidget class is a base for all widgets representing the content of SessionItem....
SessionItem * currentItem()
virtual void setItem(SessionItem *item)
Base class for a GUI data item.
Definition: SessionItem.h:204
Widget to define and show 1D (specular) imports by data loaders, e.g. CSV file import Contains space ...
Ui::SpecularDataImportWidget * m_ui
AbstractDataLoader1D * m_loader
QList< QAction * > actionList() override
void onPlotAxisClicked(QCPAxis *axis, QCPAxis::SelectablePart part, QMouseEvent *event)
AbstractDataLoader * selectedLoader()
SpecularDataImportWidget(QWidget *parent=nullptr)
void setItem(SessionItem *realDataItem) override
void onContextMenuRequest(const QPoint &point)
const RealDataItem * realDataItem() const
void setLog(bool log_flag)
static QMainWindow * mainWindow
Definition: Globals.h:22
SpecularDataItem * specularDataItem(SessionItem *parent)
Returns SpecularDataItem contained as a child in givent parent.
QString const & name(EShape k)
Definition: particles.cpp:20
void information(QWidget *parent, const QString &title, const QString &text, const QString &detailedText)
Definition: MessageBox.cpp:22
std::optional< ProjectDocument * > projectDocument
Definition: SessionData.h:27