Newer
Older
// ************************************************************************************************
// BornAgain: simulate and fit reflection and scattering
//! @file GUI/View/Instrument/InstrumentView.cpp
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
// ************************************************************************************************
#include "GUI/View/Instrument/InstrumentView.h"
#include "GUI/Model/Device/InstrumentItems.h"
#include "GUI/View/Instrument/DepthprobeInstrumentEditor.h"
#include "GUI/View/Instrument/GISASInstrumentEditor.h"
#include "GUI/View/Instrument/InstrumentListView.h"
#include "GUI/View/Instrument/OffspecInstrumentEditor.h"
#include "GUI/View/Instrument/SpecularInstrumentEditor.h"
#include "GUI/View/Widget/ApplicationSettings.h"
#include "GUI/View/Widget/GroupBoxes.h"
#include <QFormLayout>
#include <QLineEdit>
#include <QTextEdit>
Matthias Puchner
committed
InstrumentView::InstrumentView(QWidget* parent, ProjectDocument* document)
: QWidget(parent)
, m_document(document)
t.knopff
committed
m_instrumentListView = new InstrumentListView(document, this);
m_instrumentListView->setVisible(!document->singleInstrumentMode());
connect(m_document, &ProjectDocument::singleInstrumentModeChanged,
[this]() { m_instrumentListView->setVisible(!m_document->singleInstrumentMode()); });
connect(m_instrumentListView, &InstrumentListView::instrumentSelected, this,
&InstrumentView::createWidgetsForCurrentInstrument);
// Large widget: current instrument
m_scrollArea = new QScrollArea(this);
m_scrollArea->setWidgetResizable(true);
// m_scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// Top toolbar with action buttons "new ...instrument" etc
auto* toolbar = new StyledToolbar(this);
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
t.knopff
committed
toolbar->addActions(m_instrumentListView->toolbarActions());
Matthias Puchner
committed
// Overall layout
auto* horizontalLayout = new QHBoxLayout;
horizontalLayout->addWidget(m_instrumentListView);
horizontalLayout->addWidget(m_scrollArea, 1);
Matthias Puchner
committed
auto* mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
Van Herck, Walter
committed
void InstrumentView::showEvent(QShowEvent*)
{
// disconnect because when this view is visible, no other instance is modifying instruments. By
// disconnecting, no additional logic is necessary to avoid recursive calls (recursive since
// this view also causes instrumentChanged to be emitted).
disconnect(m_document->multiNotifier(), &MultiInstrumentNotifier::instrumentChanged, this,
&InstrumentView::onInstrumentChangedFromExternal);
}
void InstrumentView::hideEvent(QHideEvent*)
{
// when the instrument view gets hidden (meaning another view is shown), it's necessary to
// listen to changes (e.g. performed by the LinkInstrumentManager).
connect(m_document->multiNotifier(), &MultiInstrumentNotifier::instrumentChanged, this,
&InstrumentView::onInstrumentChangedFromExternal);
void InstrumentView::createWidgetsForCurrentInstrument()
{
auto* currentInstrument = m_instrumentListView->currentInstrumentItem();
Matthias Puchner
committed
if (!currentInstrument) {
m_scrollArea->setWidget(new QWidget(m_scrollArea)); // blank widget
Matthias Puchner
committed
return;
Matthias Puchner
committed
QWidget* w = new QWidget(m_scrollArea);
auto* layout = new QVBoxLayout(w);
//... Groupbox with instrument name and description (same layout for all instrument types)
auto title = QString("Summary (%1 instrument)").arg(currentInstrument->instrumentType());
auto* g = new CollapsibleGroupBox(title, m_scrollArea, currentInstrument->expandInfo);
g->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
auto* formLayout = new QFormLayout;
g->body()->setLayout(formLayout);
Matthias Puchner
committed
layout->addWidget(g);
auto* nameEdit = new QLineEdit(g);
nameEdit->setText(currentInstrument->instrumentName());
connect(nameEdit, &QLineEdit::textEdited, this, &InstrumentView::onInstrumentNameEdited);
formLayout->addRow("Name:", nameEdit);
Matthias Puchner
committed
auto* descriptionEdit = new QTextEdit(g);
descriptionEdit->setMinimumWidth(300);
descriptionEdit->setFixedHeight(60); // TODO replace by 2*line_height
descriptionEdit->setAcceptRichText(false);
descriptionEdit->setTabChangesFocus(true);
descriptionEdit->setPlainText(currentInstrument->description());

Wuttke, Joachim
committed
connect(descriptionEdit, &QTextEdit::textChanged, [this, descriptionEdit]() {
onInstrumentdescriptionEdited(descriptionEdit->toPlainText());
});
formLayout->addRow("Description:", descriptionEdit);
Matthias Puchner
committed
if (auto* ii = dynamic_cast<SpecularInstrumentItem*>(currentInstrument)) {
auto* editor = new SpecularInstrumentEditor(m_scrollArea, ii, ec);
Matthias Puchner
committed
connect(editor, &SpecularInstrumentEditor::dataChanged, this,
&InstrumentView::onInstrumentChangedByEditor);
layout->addWidget(editor);
} else if (auto* ii = dynamic_cast<OffspecInstrumentItem*>(currentInstrument)) {
auto* editor = new OffspecInstrumentEditor(m_scrollArea, ii, ec);
connect(editor, &OffspecInstrumentEditor::dataChanged, this,
Matthias Puchner
committed
&InstrumentView::onInstrumentChangedByEditor);
layout->addWidget(editor);
} else if (auto* ii = dynamic_cast<GISASInstrumentItem*>(currentInstrument)) {
auto* editor = new GISASInstrumentEditor(m_scrollArea, ii);
Matthias Puchner
committed
connect(editor, &GISASInstrumentEditor::dataChanged, this,
&InstrumentView::onInstrumentChangedByEditor);
layout->addWidget(editor);
} else if (auto* ii = dynamic_cast<DepthprobeInstrumentItem*>(currentInstrument)) {
auto* editor = new DepthprobeInstrumentEditor(m_scrollArea, ii, ec);
connect(editor, &DepthprobeInstrumentEditor::dataChanged, this,
Matthias Puchner
committed
&InstrumentView::onInstrumentChangedByEditor);
layout->addWidget(editor);
Matthias Puchner
committed
} else
Matthias Puchner
committed
m_scrollArea->setWidget(w);
}
Matthias Puchner
committed
void InstrumentView::onInstrumentNameEdited(const QString& newName)
auto* currentInstrument = m_instrumentListView->currentInstrumentItem();
Matthias Puchner
committed
if (currentInstrument && currentInstrument->instrumentName() != newName)
m_document->multiNotifier()->setInstrumentName(currentInstrument, newName);
Matthias Puchner
committed
}
Matthias Puchner
committed
void InstrumentView::onInstrumentdescriptionEdited(const QString& t)
{
auto* currentInstrument = m_instrumentListView->currentInstrumentItem();
Matthias Puchner
committed
if (currentInstrument && currentInstrument->description() != t) {
currentInstrument->setDescription(t);
onInstrumentChangedByEditor();
}
}
void InstrumentView::onInstrumentChangedByEditor()
Matthias Puchner
committed
{
// uses 'MultiInstrumentNotifier::instrumentChanged' signal for two purposes:
// 1) notify 'ProjectDocument' that user has changed data ==> mark project with '*'
// 2) notify 'LinkInstrumentManager' ==> unlink instrument from data if they are incompatible
m_document->multiNotifier()->notifyInstrumentChanged(
m_instrumentListView->currentInstrumentItem());
void InstrumentView::onInstrumentChangedFromExternal(const InstrumentItem* instrument)
{
if (instrument == m_instrumentListView->currentInstrumentItem())
createWidgetsForCurrentInstrument();
}
void InstrumentView::fillViewMenu(QMenu* menu)
{
auto* action = new QWidgetAction(menu);
auto* checkBox = new QCheckBox("Use single instrument", menu);
action->setDefaultWidget(checkBox);
action->setText("Use single instrument");
action->setCheckable(true);
checkBox->setChecked(m_document->singleInstrumentMode());
connect(checkBox, &QCheckBox::stateChanged, this,
&InstrumentView::onSingleInstrumentModeChanged);
menu->addAction(action);
menu->addSeparator();
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
const auto f = m_document->functionalities();
gisasCheck = new QCheckBox("GISAS instrument", menu);
gisasCheck->setChecked(f.testFlag(ProjectDocument::Gisas));
connect(gisasCheck, &QCheckBox::stateChanged, this, &InstrumentView::onFunctionalityChanged);
action = new QWidgetAction(menu);
action->setToolTip("GISAS instrument");
action->setDefaultWidget(gisasCheck);
menu->addAction(action);
offspecCheck = new QCheckBox("Off-specular instrument", menu);
offspecCheck->setChecked(f.testFlag(ProjectDocument::Offspec));
connect(offspecCheck, &QCheckBox::stateChanged, this, &InstrumentView::onFunctionalityChanged);
action = new QWidgetAction(menu);
action->setToolTip("Off-specular instrument");
action->setDefaultWidget(offspecCheck);
menu->addAction(action);
specularCheck = new QCheckBox("Specular instrument", menu);
specularCheck->setChecked(f.testFlag(ProjectDocument::Specular));
connect(specularCheck, &QCheckBox::stateChanged, this, &InstrumentView::onFunctionalityChanged);
action = new QWidgetAction(menu);
action->setToolTip("Specular instrument");
action->setDefaultWidget(specularCheck);
menu->addAction(action);
depthProbeCheck = new QCheckBox("Depth probe instrument", menu);
depthProbeCheck->setChecked(f.testFlag(ProjectDocument::Depthprobe));
connect(depthProbeCheck, &QCheckBox::stateChanged, this,
&InstrumentView::onFunctionalityChanged);
action = new QWidgetAction(menu);
action->setToolTip("Depth probe instrument");
action->setDefaultWidget(depthProbeCheck);
menu->addAction(action);
}
void InstrumentView::onSingleInstrumentModeChanged(bool newState)
{
if (newState) {
if (m_document->instrumentModel()->instrumentItems().size() > 1) {
QMessageBox::warning(this, "Select single instrument mode",
"This project already contains more than one instrument. Changing "
"this setting is not possible.");
return;
}
m_document->setSingleInstrumentMode(true);
} else
m_document->setSingleInstrumentMode(false);
appSettings->setDefaultIsSingleInstrumentMode(
}
}
ProjectDocument::Functionalities InstrumentView::functionalities() const
{
ProjectDocument::Functionalities f;
f.setFlag(ProjectDocument::Gisas, gisasCheck->isChecked());
f.setFlag(ProjectDocument::Offspec, offspecCheck->isChecked());
f.setFlag(ProjectDocument::Specular, specularCheck->isChecked());
f.setFlag(ProjectDocument::Depthprobe, depthProbeCheck->isChecked());
return f;
}
void InstrumentView::onFunctionalityChanged()
{
const auto f = functionalities();
if (f == ProjectDocument::None) {
QMessageBox::warning(this, "Select functionality",
"You have to select at least one functionality. Changing "
"this setting is not possible.");
const auto f = m_document->functionalities();
gisasCheck->setChecked(f.testFlag(ProjectDocument::Gisas));
offspecCheck->setChecked(f.testFlag(ProjectDocument::Offspec));
specularCheck->setChecked(f.testFlag(ProjectDocument::Specular));
depthProbeCheck->setChecked(f.testFlag(ProjectDocument::Depthprobe));
return;
}
m_document->setFunctionalities(f);
appSettings->setDefaultFunctionalities(toVariant(f));
}
}