BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
RealDataSelectorWidget.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/coregui/Views/ImportDataWidgets/RealDataSelectorWidget.cpp
6 //! @brief Implements class RealDataSelectorWidget
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Device/Data/DataUtils.h"
29 #include <QApplication>
30 #include <QFileDialog>
31 #include <QItemSelectionModel>
32 #include <QLineEdit>
33 #include <QListView>
34 #include <QMenu>
35 #include <QSplitter>
36 #include <QTreeView>
37 #include <QVBoxLayout>
38 
40  : QWidget(parent)
41  , m_itemTree(new QTreeView)
42  , m_itemTreeModel(new RealDataTreeModel)
43  , m_propertiesWidget(new RealDataPropertiesWidget)
44  , m_import2dDataAction(new QAction(this))
45  , m_import1dDataAction(new QAction(this))
46  , m_renameDataAction(new QAction(this))
47  , m_removeDataAction(new QAction(this))
48  , m_rotateDataAction(new QAction(this))
49 {
50  setMinimumSize(128, 600);
51  setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
52  setWindowTitle("RealDataSelectorWidget");
53 
54  // #baimport ++ necessary to tree somehow?
55  /*
56  QSize RealDataItemSelectorWidget::sizeHint() const
57  {
58  return QSize(Constants::ITEM_SELECTOR_WIDGET_WIDTH, Constants::ITEM_SELECTOR_WIDGET_HEIGHT);
59  }
60 
61  QSize RealDataItemSelectorWidget::minimumSizeHint() const { return QSize(25, 25); }
62  */
63 
64  m_import2dDataAction->setText("Import 2D data");
65  m_import2dDataAction->setIcon(QIcon(":/images/import.svg"));
66  m_import2dDataAction->setIconText("2D");
67  m_import2dDataAction->setToolTip("Import 2D data");
68  connect(m_import2dDataAction, &QAction::triggered, [this]() { importData(2); });
69 
70  m_import1dDataAction->setText("Import 1D data");
71  m_import1dDataAction->setIcon(QIcon(":/images/import.svg"));
72  m_import1dDataAction->setIconText("1D");
73  m_import1dDataAction->setToolTip("Import 1D data");
74  connect(m_import1dDataAction, &QAction::triggered, [this]() { importData(1); });
75 
76  m_renameDataAction->setText("Rename");
77  m_renameDataAction->setIcon(QIcon()); // #baTODO: Icon needed?
78  m_renameDataAction->setIconText("Rename");
79  m_renameDataAction->setToolTip("Rename data");
80  connect(m_renameDataAction, &QAction::triggered, this,
82 
83  m_removeDataAction->setText("Remove");
84  m_removeDataAction->setIcon(QIcon(":/images/delete.svg"));
85  m_removeDataAction->setIconText("Remove");
86  m_removeDataAction->setToolTip("Remove selected data");
87  connect(m_removeDataAction, &QAction::triggered, this,
89 
90  m_rotateDataAction->setText("Rotate");
91  m_rotateDataAction->setIcon(QIcon(":/images/rotate-left.svg"));
92  m_rotateDataAction->setIconText("Rotate");
93  m_rotateDataAction->setToolTip("Rotate intensity data by 90 deg counterclockwise");
94  connect(m_rotateDataAction, &QAction::triggered, this,
96 
97  QToolBar* toolBar = new StyledToolBar(this);
98  toolBar->setMinimumSize(toolBar->minimumHeight(), toolBar->minimumHeight());
99  toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
100  toolBar->addAction(m_import2dDataAction);
101  toolBar->addAction(m_import1dDataAction);
102  toolBar->addAction(m_removeDataAction);
103  toolBar->addAction(m_rotateDataAction);
104 
105  // #baimport ++ following line necessary for tree as well? relevant for RealItems at all?
106  // m_itemTree->setAttribute(Qt::WA_MacShowFocusRect, false);
107  m_itemTree->setItemsExpandable(false);
108  m_itemTree->setRootIsDecorated(false);
109  m_itemTree->setHeaderHidden(true);
110  m_itemTree->setContextMenuPolicy(Qt::CustomContextMenu);
111  m_itemTree->setModel(m_itemTreeModel);
112 
113  auto splitter = new QSplitter;
114  splitter->setOrientation(Qt::Vertical);
115  splitter->addWidget(m_itemTree);
116  splitter->addWidget(m_propertiesWidget);
117  splitter->setChildrenCollapsible(true);
118 
119  auto mainLayout = new QVBoxLayout;
120  mainLayout->setMargin(0);
121  mainLayout->setSpacing(0);
122  mainLayout->setContentsMargins(0, 0, 0, 0);
123  mainLayout->addWidget(toolBar);
124  mainLayout->addWidget(splitter);
125  setLayout(mainLayout);
126 
127  connect(m_itemTree, &QTreeView::customContextMenuRequested, this,
129 
131 }
132 
134 {
135  return QSize(200, 400);
136 }
137 
139 {
140  return QSize(128, 200);
141 }
142 
144 {
145  m_itemTreeModel->setRealDataModel(realDataModel);
146 
147  connect(m_itemTreeModel, &QAbstractItemModel::modelReset,
148  [this]() { m_itemTree->expandAll(); });
149 
150  connect(m_itemTreeModel, &QAbstractItemModel::rowsInserted,
151  [this]() { m_itemTree->expandAll(); });
152 
153  connect(m_itemTree->selectionModel(), &QItemSelectionModel::selectionChanged, this,
154  &RealDataSelectorWidget::onSelectionChanged, Qt::UniqueConnection);
155 }
156 
158 {
160 }
161 
163 {
164  m_itemTree->selectionModel()->clearSelection();
165  QModelIndex index = m_itemTreeModel->indexForItem(item);
166  if (index.isValid())
167  m_itemTree->selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent);
168 }
169 
171 {
172  return m_itemTree->selectionModel()->currentIndex();
173 }
174 
176 {
180 }
181 
183 {
184  auto realDataItemAtPoint = m_itemTreeModel->itemForIndex(m_itemTree->indexAt(point));
185  updateActionEnabling(realDataItemAtPoint);
186 
187  QMenu menu;
188  menu.setToolTipsVisible(true);
189 
190  if (realDataItemAtPoint != nullptr) {
191  menu.addAction(m_renameDataAction);
192  menu.addAction(m_removeDataAction);
193  if (realDataItemAtPoint->isIntensityData())
194  menu.addAction(m_rotateDataAction);
195  menu.addSeparator();
196  }
197 
198  menu.addAction(m_import2dDataAction);
199  menu.addAction(m_import1dDataAction);
200  menu.exec(m_itemTree->mapToGlobal(point));
201 }
202 
204 {
205  QMap<QString, AbstractDataLoader*> loaderOfFilter;
206  QString filters;
207  QString selectedFilter;
208  if (ndim == 2) {
209  filters = "Intensity File (*.int *.gz *.tif *.tiff *.txt *.csv);;"
210  "Other (*.*)";
212  } else {
213  for (auto loader : DataLoaders1D::instance().loaders()) {
214  const QString filter =
215  loader->name()
216  + " (*.txt *.csv *.dat)"; // #baimport - take file filters from loader
217  loaderOfFilter[filter] = loader;
218 
219  if (!filters.isEmpty())
220  filters += ";;";
221  filters += filter;
222  }
223  filters += ";;Other (*.*)";
224 
226  }
227  QString dirname = AppSvc::projectManager()->userImportDir();
228  QStringList fileNames = QFileDialog::getOpenFileNames(Q_NULLPTR, "Open Intensity Files",
229  dirname, filters, &selectedFilter);
230 
231  if (fileNames.isEmpty())
232  return;
233 
234  QString newImportDir = GUIHelpers::fileDir(fileNames[0]);
235  if (newImportDir != dirname)
236  AppSvc::projectManager()->setImportDir(newImportDir);
237 
238  if (ndim == 1)
240  else
242 
243  for (const auto& fileName : fileNames) {
244  QFileInfo info(fileName);
245  auto baseNameOfLoadedFile = info.baseName();
246 
247  if (ndim == 2) {
248  std::unique_ptr<OutputData<double>> data = ImportDataUtils::Import2dData(fileName);
249  if (data) {
250  auto realDataItem = m_itemTreeModel->insertIntensityDataItem();
251  realDataItem->setName(baseNameOfLoadedFile);
252  realDataItem->setOutputData(data.release());
253  setCurrentItem(realDataItem);
254  }
255  } else if (ndim == 1) {
256  auto realDataItem = m_itemTreeModel->insertSpecularDataItem();
257  realDataItem->setName(baseNameOfLoadedFile);
258  realDataItem->setNativeFileName(fileName);
259 
260  const AbstractDataLoader* selectedLoader =
261  loaderOfFilter.value(selectedFilter, nullptr);
262  const QString errorText = ImportDataUtils::Import1dData(realDataItem, selectedLoader);
263  if (errorText.isEmpty())
264  setCurrentItem(realDataItem);
265  else {
266  m_itemTreeModel->removeItem(realDataItem);
267 
268  GUIHelpers::warning("File import",
269  QString("The file '%1' could not be imported.")
270  .arg(QDir::toNativeSeparators(fileName)),
271  errorText);
272  }
273  }
274  }
275 }
276 
278 {
279  if (currentIndex().isValid())
280  m_itemTree->edit(currentIndex());
281 }
282 
284 {
286 }
287 
289 {
290  if (!currentItem() || !currentItem()->isIntensityData())
291  // should never happen because of action disabling => no
292  // dialog necessary
293  return;
294 
295  if (currentItem()->rotationAffectsSetup()) {
296  const QString title("Rotate data");
297  const QString message("Rotation will break the link between the data and the instrument. "
298  "Detector masks or projections, if they exist, will be removed.");
299  if (!GUIHelpers::question(MainWindow::instance(), title, message,
300  "Do you wish to rotate the data?", "Yes, please rotate",
301  "No, cancel data rotation"))
302  return;
303  }
304 
305  QApplication::setOverrideCursor(Qt::WaitCursor);
306  currentItem()->rotateData();
307  QApplication::restoreOverrideCursor();
308 }
309 
311 {
313 }
314 
316 {
317  m_import2dDataAction->setEnabled(true);
318  m_import1dDataAction->setEnabled(true);
319 
320  m_rotateDataAction->setEnabled(item != nullptr ? item->isIntensityData() : false);
321  m_removeDataAction->setEnabled(item != nullptr);
322  m_renameDataAction->setEnabled(item != nullptr);
323 }
324 
326 {
327  // ensure a current item when widget is shown
328  if (!currentItem())
330 }
Defines class AppSvc.
Defines class DataLoaders1D.
Defines namespace DataUtils.
Defines class GUIHelpers functions.
Defines class MainWindow.
Defines class ProjectManager.
Defines ImportDataUtils namespace.
Defines class QREDataLoader.
Defines class RealDataItem.
Defines class RealDataModel.
Defines class RealDataPropertiesWidget.
Defines class RealDataSelectorWidget.
Defines class RealDataTreeModel.
Defines class StyledToolBar.
Base class for all data loaders (classes which can import real data)
static ProjectManager * projectManager()
Definition: AppSvc.cpp:18
static DataLoaders1D & instance()
The one and only instance.
static MainWindow * instance()
Returns the one and only instance of this class.
Definition: mainwindow.cpp:129
void setRecentlyUsedImportFilter1D(const QString &filter)
QString recentlyUsedImportFilter2D() const
void setRecentlyUsedImportFilter2D(const QString &filter)
void setImportDir(const QString &dirname)
Sets user import directory in system settings.
QString userImportDir() const
Returns directory name which was used by the user to import files.
QString recentlyUsedImportFilter1D() const
The RealDataItem class represents intensity data imported from file and intended for fitting.
Definition: RealDataItem.h:35
bool isIntensityData() const
void setName(const QString &name)
The RealDataModel class is a model to store all imported RealDataItem's.
Definition: RealDataModel.h:26
The RealDataPropertiesWidget class holds instrument selector to link with RealDataItem.
void setItem(RealDataItem *item)
Set current RealDataItem to display in instrument selector.
void setModel(RealDataModel *realDataModel)
void setCurrentItem(RealDataItem *item)
RealDataTreeModel * m_itemTreeModel
void onContextMenuRequest(const QPoint &point)
virtual QSize minimumSizeHint() const override
virtual void showEvent(QShowEvent *) override
RealDataPropertiesWidget * m_propertiesWidget
RealDataSelectorWidget(QWidget *parent=0)
void selectionChanged(SessionItem *)
virtual QSize sizeHint() const override
Tree model for real data item selection. Used for the tree in the import view.
QModelIndex indexForItem(RealDataItem *item) const
void setRealDataModel(RealDataModel *model)
RealDataItem * insertIntensityDataItem()
RealDataItem * topMostItem() const
The topmost visible item. Can be null of course.
RealDataItem * insertSpecularDataItem()
RealDataItem * itemForIndex(const QModelIndex &index) const
void removeItem(RealDataItem *item)
The StyledToolBar class represents our standard narrow toolbar with the height 24 pixels.
Definition: StyledToolBar.h:22
void warning(QWidget *parent, const QString &title, const QString &text, const QString &detailedText)
Definition: GUIHelpers.cpp:74
QString fileDir(const QString &fileName)
Returns file directory from the full file path.
Definition: GUIHelpers.cpp:193
bool question(QWidget *parent, const QString &title, const QString &text, const QString &detailedText, const QString &yesText, const QString &noText)
Definition: GUIHelpers.cpp:94
QString Import1dData(RealDataItem *realDataItem, const AbstractDataLoader *selectedLoader)
Import 1D data into the given item.
std::unique_ptr< OutputData< double > > Import2dData(const QString &baseNameOfLoadedFile)