BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
mainwindow.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/coregui/mainwindow/mainwindow.cpp
6 //! @brief Implements class MainWindow
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 
33 #include <QAction>
34 #include <QApplication>
35 #include <QBoxLayout>
36 #include <QButtonGroup>
37 #include <QCloseEvent>
38 #include <QMessageBox>
39 #include <QProgressBar>
40 #include <QPushButton>
41 #include <QSettings>
42 #include <QStackedLayout>
43 #include <QStatusBar>
44 #include <QToolButton>
45 
47 
49  : QMainWindow(nullptr)
50  , m_progressBar(new QProgressBar)
51  , m_viewSelectionButtons(new QButtonGroup(this))
52  , m_viewsStack(new QStackedLayout)
53  , m_viewSelectionButtonsLayout(new QVBoxLayout)
54  , m_statusBar(new QStatusBar)
55  , m_applicationModels(new ApplicationModels(this))
56  , m_linkManager(new LinkInstrumentManager(this))
57  , m_projectManager(new ProjectManager(this))
58  , m_actionManager(new ActionManager(this))
59  , m_toolTipDataBase(new ToolTipDataBase(this))
60  , m_updateNotifier(new UpdateNotifier(this))
61  , m_welcomeView(0)
62  , m_instrumentView(0)
63  , m_sampleView(0)
64  , m_importDataView(0)
65  , m_simulationView(0)
66  , m_jobView(0)
67  , m_sessionModelView(0)
68 {
69 
70  s_instance = this;
71 
73 
74  QWidget* centralWidget = new QWidget(this);
75  QHBoxLayout* mainLayout = new QHBoxLayout(centralWidget);
76  mainLayout->setMargin(0);
77  mainLayout->setSpacing(0);
78 
79  m_viewSelectionButtonsLayout->setMargin(0);
80  m_viewSelectionButtonsLayout->setSpacing(0);
81 
82  auto fillerButton = createViewSelectionButton();
83  fillerButton->setMinimumSize(5, 5);
84  fillerButton->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
85  fillerButton->setEnabled(false);
86  m_viewSelectionButtonsLayout->insertWidget(-1, fillerButton);
87 
88 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
89  connect(m_viewSelectionButtons, &QButtonGroup::idClicked, this, &MainWindow::setCurrentView);
90 #else
91  connect(m_viewSelectionButtons, QOverload<int>::of(&QButtonGroup::buttonClicked), this,
93 #endif
94 
95  m_statusBar->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
96 
97  QVBoxLayout* vlayout = new QVBoxLayout;
98  vlayout->setMargin(0);
99  vlayout->setSpacing(0);
100  vlayout->addLayout(m_viewsStack);
101  vlayout->addWidget(m_statusBar);
102 
103  mainLayout->addLayout(m_viewSelectionButtonsLayout);
104  mainLayout->addLayout(vlayout);
105 
106  setCentralWidget(centralWidget);
107 
108  m_statusBar->hide();
109 
110  initApplication();
111  readSettings();
112  initProgressBar();
113  initViews();
114  initConnections();
115 
116  ASSERT(m_viewSelectionButtons->button(ViewId::WELCOME) != nullptr);
117  m_viewSelectionButtons->button(ViewId::WELCOME)->setChecked(true);
118 
119  // m_applicationModels->createTestSample();
120  // m_applicationModels->createTestJob();
121  // m_applicationModels->createTestRealData();
122 }
123 
125 {
126  s_instance = nullptr;
127 }
128 
130 {
131  return s_instance;
132 }
133 
135 {
136  return models()->materialModel();
137 }
138 
140 {
141  return models()->instrumentModel();
142 }
143 
145 {
146  return models()->sampleModel();
147 }
148 
150 {
151  return models()->realDataModel();
152 }
153 
155 {
156  return models()->jobModel();
157 }
158 
160 {
161  return m_applicationModels;
162 }
163 
165 {
166  return m_linkManager;
167 }
168 
169 QProgressBar* MainWindow::progressBar()
170 {
171  return m_progressBar;
172 }
173 
175 {
176  return m_statusBar;
177 }
178 
180 {
181  return m_projectManager;
182 }
183 
185 {
186  return m_updateNotifier;
187 }
188 
189 QWidget* MainWindow::currentView() const
190 {
191  return m_viewsStack->currentWidget();
192 }
193 
195 {
196  if (m_viewsStack->currentIndex() != viewId) {
197  m_viewsStack->setCurrentIndex(viewId);
198  emit currentViewChanged(ViewId(viewId));
199  }
200 }
201 
203 {
204  m_viewSelectionButtons->button(index)->click();
205 }
206 
208 {
209  if (const QAction* action = qobject_cast<const QAction*>(sender())) {
210  QString file = action->data().value<QString>();
212  }
213 }
214 
216 {
217  // This clearFocus is needed for the propagation of the current editor value,
218  // since the runSimulation method will only change focus after finishing the simulation
219  if (auto widget = QApplication::focusWidget())
220  widget->clearFocus();
222 }
223 
224 //! Inserts/removes developers SessionModelView on the left tabbar.
226 {
227  auto btn = m_viewSelectionButtons->button(ViewId::SESSIONMODEL);
228  ASSERT(btn != nullptr);
229  if (btn == nullptr)
230  return;
231 
232  if (!isActive && m_viewsStack->currentIndex() == SESSIONMODEL)
233  m_viewSelectionButtons->buttons().first()->click();
234 
235  btn->setEnabled(isActive);
236  btn->setVisible(isActive);
237 }
238 
239 void MainWindow::closeEvent(QCloseEvent* event)
240 {
241  if (jobModel()->hasUnfinishedJobs()) {
242  QMessageBox::warning(this, "Can't quit the application.",
243  "Can't quit the application while jobs are running.\n"
244  "Cancel running jobs or wait until they are completed.");
245  event->ignore();
246  return;
247  }
249  writeSettings();
250  event->accept();
251  } else {
252  event->ignore();
253  }
254 }
255 
257 {
258  QCoreApplication::setApplicationName(QLatin1String(Constants::APPLICATION_NAME));
259  QCoreApplication::setApplicationVersion(GUIHelpers::getBornAgainVersionString());
260  QCoreApplication::setOrganizationName(QLatin1String(Constants::APPLICATION_NAME));
261 
263  QApplication::setWindowIcon(QIcon(":/images/BornAgain.ico"));
264 
265  setDockNestingEnabled(true);
266  setAcceptDrops(true);
267 
268  setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
269  setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
270 }
271 
273 {
274  m_progressBar->hide();
275  m_progressBar->setTextVisible(false);
276  m_progressBar->setFixedHeight(QApplication::fontMetrics().boundingRect("M").height());
277  m_progressBar->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
279 }
280 
282 {
283  m_welcomeView = new WelcomeView(this);
284  m_instrumentView = new InstrumentView(this);
285  m_sampleView = new SampleView(this);
286  m_importDataView = new ImportDataView(this);
287  m_simulationView = new SimulationView(this);
288  m_jobView = new JobView(this);
290 
291  addView(ViewId::WELCOME, QIcon(":/images/main_welcomeview.svg"), "Welcome",
292  "Switch to Welcome View", m_welcomeView);
293 
294  addView(ViewId::INSTRUMENT, QIcon(":/images/main_instrumentview.svg"), "Instrument",
295  "Define the beam and the detector", m_instrumentView);
296 
297  addView(ViewId::SAMPLE, QIcon(":/images/main_sampleview.svg"), "Sample", "Build the sample",
298  m_sampleView);
299 
300  addView(ViewId::IMPORT, QIcon(":/images/main_importview.svg"), "Data",
301  "Import intensity data to fit", m_importDataView);
302 
303  addView(ViewId::SIMULATION, QIcon(":/images/main_simulationview.svg"), "Simulation",
304  "Run simulation", m_simulationView);
305 
306  addView(ViewId::JOB, QIcon(":/images/main_jobview.svg"), "Jobs",
307  "Switch to see job results, tune parameters real time,\nfit the data", m_jobView);
308 
309  addView(ViewId::SESSIONMODEL, QIcon(":/images/main_sessionmodel.svg"), "Models", "",
311 
312  // enabling technical view
313  QSettings settings;
314  settings.beginGroup(Constants::S_SESSIONMODELVIEW);
315  onSessionModelViewActive(settings.value(Constants::S_VIEWISACTIVE, false).toBool());
316  settings.endGroup();
317 }
318 
320 {
321  QSettings settings;
322  if (settings.childGroups().contains(Constants::S_MAINWINDOW)) {
323  settings.beginGroup(Constants::S_MAINWINDOW);
324  resize(settings.value(Constants::S_WINDOWSIZE, QSize(400, 400)).toSize());
325  move(settings.value(Constants::S_WINDOWPOSITION, QPoint(200, 200)).toPoint());
326  settings.endGroup();
327  }
329 }
330 
332 {
333  QSettings settings;
334  settings.beginGroup(Constants::S_MAINWINDOW);
335  settings.setValue(Constants::S_WINDOWSIZE, size());
336  settings.setValue(Constants::S_WINDOWPOSITION, pos());
337  settings.endGroup();
339  settings.sync();
340 }
341 
343 {
345 }
346 
347 void MainWindow::addView(ViewId id, const QIcon& icon, const QString& title, const QString& tooltip,
348  QWidget* view)
349 {
350  QToolButton* btn = createViewSelectionButton();
351  m_viewSelectionButtonsLayout->insertWidget(id, btn);
352 
353  btn->setText(title);
354  btn->setToolTip(tooltip);
355  btn->setIcon(icon);
356  m_viewSelectionButtons->addButton(btn, id);
357 
359 
360  m_viewsStack->insertWidget(id, view);
361 }
362 
364 {
365  if (m_viewSelectionButtons->buttons().isEmpty())
366  return;
367 
368  const QFontMetrics fontMetrics = m_viewSelectionButtons->buttons().first()->fontMetrics();
369 
370  // Find the maximum text extents
371  int maxTextWidth = 0;
372  int maxTextHeight = 0;
373  for (auto b : m_viewSelectionButtons->buttons()) {
374  const auto r = fontMetrics.boundingRect(b->text());
375  maxTextWidth = std::max(maxTextWidth, r.width());
376  maxTextHeight = std::max(maxTextHeight, r.height());
377  }
378 
379  // calculate the button extent by width (width == height!). Ensure an extent of 70 for normal
380  // DPI devices (legacy value)
381  const int margin = fontMetrics.boundingRect("M").width();
382  const int buttonExtent = std::max(70, maxTextWidth + 2 * margin);
383 
384  // calculate the icon extent by height (width == height!)
385  const int iconExtent = buttonExtent - margin - maxTextHeight;
386 
387  // set new values in all buttons
388  for (auto b : m_viewSelectionButtons->buttons()) {
389  b->setFixedSize(buttonExtent, buttonExtent);
390  b->setIconSize({iconExtent, iconExtent});
391  }
392  // set fixed width in filler and progress bar
393  auto filler = m_viewSelectionButtonsLayout->itemAt(m_viewSelectionButtons->buttons().size());
394  if (filler)
395  if (auto fillerBtn = dynamic_cast<QToolButton*>(filler->widget()); fillerBtn)
396  fillerBtn->setFixedWidth(buttonExtent);
397 
398  m_progressBar->setFixedWidth(buttonExtent);
399 }
400 
402 {
403 
404  const QString viewSelectionButtonStyle =
405  "QToolButton { border: none; color: white; background-color: qlineargradient(x1: 0, "
406  "y1: 0, x2: 1, y2: 0, stop : 0 #153b4c, stop : 1 #347a9c);} "
407  "QToolButton:pressed { "
408  " color: black; background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 "
409  "#97a8b0, stop: "
410  "1 #dae7ed); }"
411  "QToolButton:hover { "
412  " color: white; background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 "
413  "#254b5c, stop: 1 #448aac); }"
414  "QToolButton:checked { "
415  " color: black; background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 "
416  "#97a8b0, stop: "
417  "1 #dae7ed);"
418  "} ";
419 
420  QToolButton* btn = new QToolButton;
421  btn->setCheckable(true);
422  btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
423  btn->setStyleSheet(viewSelectionButtonStyle);
424  return btn;
425 }
Defines class holding all application models.
#define ASSERT(condition)
Definition: Assert.h:31
Defines class GUIHelpers functions.
Defines class ActionManager.
Defines class MainWindow.
Defines class ProjectManager.
Defines class ImportDataView.
Defines class InstrumentView.
Defines class JobModel.
Defines class JobView.
Defines class LinkInstrumentManager.
Defines class SampleView.
Defines class SessionModelView.
Defines class SimulationView.
Implements class UpdateNotifier.
Defines class WelcomeView.
Class to handle MainWindow's menu and corresponding actions.
Definition: actionmanager.h:28
SampleModel * sampleModel()
RealDataModel * realDataModel()
MaterialModel * materialModel()
InstrumentModel * instrumentModel()
static bool isMacHost()
Definition: hostosinfo.h:69
The ImportDataView class is a main view for importing experimental data.
The JobView class is a main view to show list of jobs, job results and widgets for real time and fitt...
Definition: JobView.h:35
void focusRequest(int)
The LinkInstrumentManager class provides communication between InstrumentModel and RealDataModel.
void setModels(InstrumentModel *instrumentModel, RealDataModel *realDataModel)
Sets models and builds initial links.
void readSettings()
Definition: mainwindow.cpp:319
SimulationView * m_simulationView
Definition: mainwindow.h:120
@ SESSIONMODEL
Definition: mainwindow.h:51
WelcomeView * m_welcomeView
Definition: mainwindow.h:116
SessionModelView * m_sessionModelView
Definition: mainwindow.h:122
void setCurrentView(int viewId)
Definition: mainwindow.cpp:194
QButtonGroup * m_viewSelectionButtons
Definition: mainwindow.h:104
InstrumentView * m_instrumentView
Definition: mainwindow.h:117
LinkInstrumentManager * m_linkManager
Definition: mainwindow.h:110
QWidget * currentView() const
Definition: mainwindow.cpp:189
UpdateNotifier * updateNotifier()
Definition: mainwindow.cpp:184
void writeSettings()
Definition: mainwindow.cpp:331
void closeEvent(QCloseEvent *event)
Definition: mainwindow.cpp:239
static MainWindow * instance()
Returns the one and only instance of this class.
Definition: mainwindow.cpp:129
void onSessionModelViewActive(bool isActive)
Inserts/removes developers SessionModelView on the left tabbar.
Definition: mainwindow.cpp:225
ProjectManager * m_projectManager
Definition: mainwindow.h:111
ImportDataView * m_importDataView
Definition: mainwindow.h:119
InstrumentModel * instrumentModel()
Definition: mainwindow.cpp:139
void onFocusRequest(int index)
Definition: mainwindow.cpp:202
LinkInstrumentManager * linkInstrumentManager()
Definition: mainwindow.cpp:164
void addView(ViewId id, const QIcon &icon, const QString &title, const QString &tooltip, QWidget *view)
Definition: mainwindow.cpp:347
UpdateNotifier * m_updateNotifier
Definition: mainwindow.h:114
void onRunSimulationShortcut()
Definition: mainwindow.cpp:215
QStackedLayout * m_viewsStack
Definition: mainwindow.h:105
void openRecentProject()
Definition: mainwindow.cpp:207
void initViews()
Definition: mainwindow.cpp:281
QStatusBar * m_statusBar
Definition: mainwindow.h:107
void initProgressBar()
Definition: mainwindow.cpp:272
ApplicationModels * m_applicationModels
Definition: mainwindow.h:109
QProgressBar * progressBar()
Definition: mainwindow.cpp:169
ApplicationModels * models()
Definition: mainwindow.cpp:159
QVBoxLayout * m_viewSelectionButtonsLayout
Definition: mainwindow.h:106
SampleModel * sampleModel()
Definition: mainwindow.cpp:144
JobModel * jobModel()
Definition: mainwindow.cpp:154
QProgressBar * m_progressBar
Definition: mainwindow.h:103
MaterialModel * materialModel()
Definition: mainwindow.cpp:134
void currentViewChanged(ViewId newView)
ProjectManager * projectManager()
Definition: mainwindow.cpp:179
void initApplication()
Definition: mainwindow.cpp:256
RealDataModel * realDataModel()
Definition: mainwindow.cpp:149
QToolButton * createViewSelectionButton() const
Definition: mainwindow.cpp:401
void initConnections()
Definition: mainwindow.cpp:342
static MainWindow * s_instance
Holds the one and only instance of this class.
Definition: mainwindow.h:125
JobView * m_jobView
Definition: mainwindow.h:121
QStatusBar * statusBar()
Definition: mainwindow.cpp:174
void updateViewSelectionButtonsGeometry() const
Recalculate the size of the view selection buttons to show complete button text.
Definition: mainwindow.cpp:363
SampleView * m_sampleView
Definition: mainwindow.h:118
Handles activity related to opening/save projects.
bool closeCurrentProject()
Processes close current project request.
void readSettings()
Reads settings of ProjectManager from global settings.
void openProject(QString fileName="")
Opens existing project. If fileName is empty, will popup file selection dialog.
void writeSettings()
Saves settings of ProjectManager in global settings.
The RealDataModel class is a model to store all imported RealDataItem's.
Definition: RealDataModel.h:26
Main model to hold sample items.
Definition: SampleModel.h:24
The SessionModelView is a technical view which shows the content all current application models.
void onRunSimulationShortcut()
The MaterialEditor is the main class to access materials.
Defines Utils namespace.
Defines namespace Constants.
const char S_SESSIONMODELVIEW[]
const char APPLICATION_NAME[]
const char S_VIEWISACTIVE[]
const char S_WINDOWPOSITION[]
const char S_WINDOWSIZE[]
const char S_MAINWINDOW[]
QString getBornAgainVersionString()
Definition: GUIHelpers.cpp:130
void warning(QWidget *parent, const QString &title, const QString &text, const QString &detailedText)
Definition: GUIHelpers.cpp:74
Defines class ToolTipDataBase.