BornAgain  1.19.79
Simulate and fit neutron and x-ray scattering at grazing incidence
InstrumentLibraryEditor.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/View/Instrument/InstrumentLibraryEditor.cpp
6 //! @brief Implements class InstrumentLibraryEditor
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 
27 #include "ui_InstrumentLibraryEditor.h"
28 #include <QAction>
29 #include <QFormLayout>
30 #include <QGroupBox>
31 #include <QInputDialog>
32 #include <QMessageBox>
33 #include <QPushButton>
34 #include <QTextEdit>
35 
37  : QDialog(parent)
38  , m_ui(new Ui::InstrumentLibraryEditor)
39  , m_treeModel(new TreeModel(this, gSessionData->instrumentLibrary.collectedItems()))
40  , m_chosenItem(nullptr)
41 {
42  m_ui->setupUi(this);
43 
44  setAttribute(Qt::WA_StyledBackground, true);
45  setProperty("stylable", true); // for stylesheet addressing
46  setWindowIcon(QIcon(":/images/library.svg"));
47  setWindowFlag(Qt::WindowContextHelpButtonHint, false);
48 
50 
51  m_ui->treeView->setItemsExpandable(false);
52  m_ui->treeView->setRootIsDecorated(false);
53  m_ui->treeView->setHeaderHidden(true);
54  m_ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
55  m_ui->treeView->setModel(m_treeModel);
56  m_ui->treeView->expandAll();
57  m_ui->treeView->setVerticalScrollMode(QTreeView::ScrollPerPixel);
58  m_ui->treeView->setIndentation(0);
59  m_ui->treeView->setItemDelegate(new ItemDelegateForHTML(this));
60  m_ui->treeView->setIconSize(QSize(128, 128));
61 
62  connect(m_treeModel, &QAbstractItemModel::modelReset,
63  [this]() { m_ui->treeView->expandAll(); });
64 
65  // ensure a current item when widget is shown
66  // setCurrentItem(m_treeModel->topMostItem());
69 }
70 
72 {
74 }
75 
77 {
79 }
80 
82 {
84 }
85 
87 {
89 }
90 
92 {
94 }
95 
97 {
98  setWindowTitle("Instrument Library - Choose instrument");
99 
101  m_ui->treeView, [=](const QModelIndex& i, bool h) { return getOverlayActions(i, h); });
102  m_ui->treeView->setItemDelegate(new ItemDelegateForHTML(this));
103 
104  connect(m_ui->treeView, &QTreeView::doubleClicked, this,
106  connect(m_ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this,
109 
110  if (exec() == QDialog::Accepted)
111  return m_chosenItem;
112 
113  return nullptr;
114 }
115 
117 {
118  const QString& newName =
120  auto* addedInstrument = gSessionData->instrumentLibrary.add(newName, instrumentToAdd);
121 
122  setWindowTitle("Instrument Library - Add instrument");
123 
124  m_treeModel->setNewInstrument(addedInstrument);
125  m_treeModel->setTypeEnabled(TreeModel::instrumentType(addedInstrument), true);
126 
128  m_ui->treeView, [=](const QModelIndex& i, bool h) { return getOverlayActions(i, h); });
129  m_ui->treeView->setItemDelegate(new ItemDelegateForHTML(this));
130  connect(m_ui->treeView->selectionModel(), &QItemSelectionModel::currentChanged, this,
132 
133  m_ui->buttonBox->addButton(QDialogButtonBox::Close);
134  m_ui->buttonBox->button(QDialogButtonBox::Ok)->hide();
135  m_ui->buttonBox->button(QDialogButtonBox::Cancel)->hide();
136 
137  QModelIndex index = m_treeModel->indexForItem(addedInstrument);
138  m_ui->treeView->expandAll();
139  m_ui->treeView->setCurrentIndex(index);
140  m_ui->treeView->scrollTo(index, QAbstractItemView::PositionAtTop);
142  exec();
143 }
144 
146 {
148  if (m_chosenItem != nullptr)
149  accept();
150 }
151 
153 {
154  m_chosenItem = m_treeModel->itemForIndex(m_ui->treeView->currentIndex());
155  m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(m_chosenItem != nullptr);
157 }
158 
159 QList<QAction*> InstrumentLibraryEditor::getOverlayActions(const QModelIndex& index, bool asHover)
160 {
161  if (m_treeModel->isHeadline(index))
162  return {};
163 
164  // -- index belongs to item
165  if (!asHover)
166  return {};
167 
168  auto* item = m_treeModel->itemForIndex(index);
169  if (item == nullptr)
170  return {};
171 
172  auto* removeAction = new QAction(this);
173  removeAction->setText("Remove");
174  removeAction->setIcon(QIcon(":/images/delete.svg"));
175  removeAction->setIconText("Remove");
176  removeAction->setToolTip("Remove this instrument");
177  connect(removeAction, &QAction::triggered, [=]() { m_treeModel->removeItem(item); });
178 
179  return {removeAction};
180 }
181 
183 {
184  auto* currentInstrument = m_treeModel->itemForIndex(m_ui->treeView->currentIndex());
185  if (!currentInstrument) {
186  m_ui->scrollArea->setWidget(new QWidget(m_ui->scrollArea)); // blank widget
187  return;
188  }
189 
190  QWidget* w = new QWidget(m_ui->scrollArea);
191  auto* layout = new QVBoxLayout(w);
192 
193  w->setAttribute(Qt::WA_StyledBackground, true);
194  w->setProperty("stylable", true); // for stylesheet addressing
195 
196  auto* g = new QGroupBox(m_ui->scrollArea);
197  g->setTitle(QString("Information (%1 instrument)").arg(currentInstrument->instrumentType()));
198 
199  auto* formLayout = new QFormLayout(g);
200  formLayout->setMargin(17);
201  formLayout->setSpacing(8);
202  layout->addWidget(g);
203 
204  auto* nameEdit = new QLineEdit(g);
205  formLayout->addRow("Name:", nameEdit);
206  nameEdit->setText(currentInstrument->instrumentName());
207  connect(nameEdit, &QLineEdit::textEdited, this,
209 
210  auto* descriptionEdit = new QTextEdit(g);
211  descriptionEdit->setMinimumWidth(300);
212  descriptionEdit->setMaximumHeight(100);
213  descriptionEdit->setAcceptRichText(false);
214  descriptionEdit->setTabChangesFocus(true);
215  descriptionEdit->setPlainText(currentInstrument->description());
216  formLayout->addRow("Description:", descriptionEdit);
217  connect(descriptionEdit, &QTextEdit::textChanged,
218  [=]() { onInstrumentDescriptionEdited(descriptionEdit->toPlainText()); });
219 
221 
222  if (auto* sp = dynamic_cast<SpecularInstrumentItem*>(currentInstrument)) {
223  auto* editor = new SpecularInstrumentEditor(
224  m_ui->scrollArea, sp, gSessionData->instrumentLibrary.editController());
225  connect(editor, &SpecularInstrumentEditor::dataChanged, this,
227  layout->addWidget(editor);
228  } else if (auto* os = dynamic_cast<OffspecInstrumentItem*>(currentInstrument)) {
229  auto* editor = new OffspecInstrumentEditor(m_ui->scrollArea, os);
230  connect(editor, &OffspecInstrumentEditor::dataChanged, this,
232  layout->addWidget(editor);
233  } else if (auto* gisas = dynamic_cast<GISASInstrumentItem*>(currentInstrument)) {
234  auto* editor = new GISASInstrumentEditor(m_ui->scrollArea, gisas);
235  connect(editor, &GISASInstrumentEditor::dataChanged, this,
237  layout->addWidget(editor);
238  } else if (auto* dp = dynamic_cast<DepthProbeInstrumentItem*>(currentInstrument)) {
239  auto* editor = new DepthProbeInstrumentEditor(m_ui->scrollArea, dp);
240  connect(editor, &DepthProbeInstrumentEditor::dataChanged, this,
242  layout->addWidget(editor);
243  } else
244  ASSERT(false);
245 
246  m_ui->scrollArea->setWidget(w);
247 }
248 
250 {
251  QModelIndex index = m_ui->treeView->currentIndex();
252  m_treeModel->setData(index, newName, Qt::EditRole);
253 }
254 
256 {
257  QModelIndex index = m_ui->treeView->currentIndex();
258  m_treeModel->setData(index, t, Qt::ToolTipRole);
259 }
260 
262 {
263  auto* currentInstrument = m_treeModel->itemForIndex(m_ui->treeView->currentIndex());
265 }
266 
267 /*********************************************************************************************/
268 
270  : InstrumentsTreeModel(parent, model)
271  , m_newInstrument(nullptr)
272 {
273 }
274 
276 {
277  m_newInstrument = addedInstrument;
278 }
279 
280 QVariant InstrumentLibraryEditor::TreeModel::data(const QModelIndex& index, int role) const
281 {
282  if (isHeadline(index))
283  return InstrumentsTreeModel::data(index, role);
284 
285  auto* const item = itemForIndex(index);
286 
287  if (role == Qt::DisplayRole) {
288  auto descr = item->description();
289  if (!descr.isEmpty()) {
290  descr.prepend("<br><br>");
291  // max 4 lines
292  while (descr.count("\n") > 3) {
293  descr.truncate(descr.lastIndexOf("\n"));
294  descr += " [...]";
295  }
296  descr.replace("\n", "<br>");
297  }
298  return "<b>" + item->instrumentName() + "</b>" + descr;
299  }
300 
301  if (role == Qt::DecorationRole && (item == m_newInstrument)) {
302  if (role == Qt::DecorationRole)
303  switch (instrumentType(item)) {
304  case Gisas:
305  return QIcon(":/images/gisas_instrument_new.svg");
306  case Offspec:
307  return QIcon(":/images/offspec_instrument_new.svg");
308  case Specular:
309  return QIcon(":/images/specular_instrument_new.svg");
310  case DepthProbe:
311  return QIcon(":/images/depth_instrument_new.svg");
312  default:
313  break;
314  }
315  }
316  return InstrumentsTreeModel::data(index, role);
317 }
ApplicationSettings * appSettings
global pointer to the instance
Defines class ApplicationSettings.
Defines class DepthProbeInstrumentEditor.
Defines class GISASInstrumentEditor.
Defines class GroupBoxCollapser.
Defines class InstrumentItem and all its children.
Defines class InstrumentLibraryEditor.
Defines class ItemDelegateForHTML.
Defines class ItemViewOverlayButtons.
Defines class OffspecInstrumentEditor.
SessionData * gSessionData
global pointer to the single instance
Definition: SessionData.cpp:17
Defines struct SessionData.
Defines class SpecularInstrumentEditor.
Defines GUI::StyleUtils namespace.
void loadWindowSizeAndPos(QWidget *w)
void saveWindowSizeAndPos(const QWidget *w)
Editor for GISAS instruments.
static GroupBoxCollapser * installIntoGroupBox(QGroupBox *groupBox, bool expanded=true)
Abstract base class for instrument-specific item classes.
QString instrumentName() const
A model extension for InstrumentsTreeModel which.
void setNewInstrument(InstrumentItem *addedInstrument)
Set the instrument which shall have a "NEW" sign in its icon.
TreeModel(QObject *parent, InstrumentCollection *model)
QVariant data(const QModelIndex &index, int role) const override
Ui::InstrumentLibraryEditor * m_ui
InstrumentLibraryEditor(QWidget *parent)
void onInstrumentDescriptionEdited(const QString &t)
InstrumentItem * execChoose()
Execute the dialog for choosing an instrument from the library. Returns nullptr if canceled.
void onItemDoubleClickedForChoose(const QModelIndex &index)
QList< QAction * > getOverlayActions(const QModelIndex &index, bool asHover)
void execAdd(const InstrumentItem &instrumentToAdd)
Execute the dialog to add an instrument to the library.
void onInstrumentNameEdited(const QString &newName)
InstrumentsEditController * editController()
InstrumentItem * add(const QString &name, const InstrumentItem &itemToCopy)
Returns the new element.
QString suggestName(const QString &name) const
void notifyInstrumentChanged(InstrumentItem *instrument)
Simply emits the instrumentChanged signal. Call this whenever you change an instrument's data without...
Tree model for instrument item selection. Used e.g. for the instrument library.
bool setData(const QModelIndex &index, const QVariant &value, int role) override
static InstrumentType instrumentType(InstrumentItem *item)
QModelIndex indexForItem(InstrumentItem *item) const
InstrumentItem * itemForIndex(const QModelIndex &index) const
bool isHeadline(const QModelIndex &index) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void setTypeEnabled(InstrumentType type, bool b)
void removeItem(InstrumentItem *item)
For representing HTML text in an item *‍/.
static void install(QAbstractItemView *view, FnGetActions fnGetActions)
void setResizable(QDialog *dialog)
Make modal dialog resizable.
Definition: StyleUtils.cpp:100
InstrumentLibrary instrumentLibrary
Definition: SessionData.h:26