Mantid
Loading...
Searching...
No Matches
LoadDialog.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//------------------------------------------------------------------------------
8// Includes
9//------------------------------------------------------------------------------
13// Qt
14#include <QCheckBox>
15#include <QComboBox>
16#include <QFileInfo>
17#include <QScreen>
18#include <QSettings>
19#include <QUrl>
20
21// Mantid
28
29using namespace Mantid::API;
30using namespace Mantid::Kernel;
32
34namespace {
37struct HoldFlag {
38 HoldFlag(bool &current, const bool holdValue) : initial(current), heldflag(current) { heldflag = holdValue; }
39 ~HoldFlag() { heldflag = initial; }
40 bool initial;
41 bool &heldflag;
42};
43} // namespace
44
45// Declare the dialog. Name must match the class name
46DECLARE_DIALOG(LoadDialog)
47
48//--------------------------------------------------------------------------
49// Public methods
50//---------------------------------------------------------------------------
51
52
53LoadDialog::LoadDialog(QWidget *parent)
54 : API::AlgorithmDialog(parent), m_form(), m_currentFiles(), m_initialHeight(0), m_populating(false),
55 m_userAccept(false) {
56 // We will handle parsing the input ourselves on startup
57 m_autoParseOnInit = false;
58}
59
60//--------------------------------------------------------------------------
61// Private methods (slot)
62//---------------------------------------------------------------------------
63
68 HoldFlag hold(m_populating, true);
69
70 m_form.fileWidget->blockSignals(true);
72 m_form.fileWidget->blockSignals(false);
73}
74
77 const auto loaderName = getAlgorithm()->getPropertyValue("LoaderName");
78 QString helpPage = (loaderName.empty()) ? QString("Load") : QString::fromStdString(loaderName);
80}
81
88 if (!m_form.workspaceEdit->isEnabled())
89 return;
90
91 // suggest ws name based on file name
92 QString fileSuggestion;
93 if (m_form.fileWidget->isValid()) {
94 if (m_form.fileWidget->getFilenames().size() == 1)
95 fileSuggestion = QFileInfo(m_form.fileWidget->getFirstFilename()).completeBaseName();
96 else
97 fileSuggestion = "MultiFiles";
98 }
99 m_form.workspaceEdit->setText(fileSuggestion);
100}
101
108 if (on) {
109 connect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(suggestWSName()));
110 } else {
111 disconnect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(suggestWSName()));
112 }
113}
114
119 // If the LoadDialog is already loading data, or is populating, then ignore the accept
120 if (m_form.fileWidget->isSearching() || m_populating) {
121 return;
122 }
123 m_userAccept = true;
124 m_form.fileWidget->findFiles();
125}
126
128 if (!m_userAccept) {
129 return;
130 }
131 m_userAccept = false;
132
133 // Makes it so the dialog is still resizable if it is kept open
134 m_form.propertyLayout->setEnabled(true);
135
136 // Check that the file still exists just incase it somehow got removed
137 std::string errMess = getAlgorithm()->getPointerToProperty("Filename")->isValid();
138 if (!errMess.empty()) {
139 m_currentFiles = "";
141 } else {
142 AlgorithmDialog::accept();
143 }
144}
145
146//--------------------------------------------------------------------------
147// Private methods (non-slot)
148//---------------------------------------------------------------------------
149
152 m_form.setupUi(this);
153
154 // Add the helpful summary message
155 if (isMessageAvailable())
156 m_form.instructions->setText(getOptionalMessage());
157
158 m_form.dialogLayout->addLayout(this->createDefaultButtonLayout());
159 QSettings settings;
160 settings.beginGroup("Mantid/Algorithms/Load");
161 m_form.fileWidget->restoreSettings(FileFinderWidget::readSettings(settings));
162 m_initialHeight = this->height();
163
164 const std::string &outWsName = getAlgorithm()->getPropertyValue("OutputWorkspace");
165 if (!outWsName.empty()) {
166 // OutputWorkspace name suggestion received as parameter, just take it and
167 // don't change it
168 m_form.workspaceEdit->setText(QString::fromStdString(outWsName));
169 } else {
170 // Guess at an output workspace name but only if the user hasn't changed
171 // anything
173 connect(m_form.workspaceEdit, SIGNAL(textEdited(const QString &)), this, SLOT(enableNameSuggestion()));
174 }
175
176 // Connect the file finder's file found signal to the dynamic property create
177 // method.
178 // When the file text is set the Load algorithm finds the concrete loader and
179 // then we
180 // know what extra properties to create
181 connect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(createDynamicWidgets()));
182 connect(m_form.fileWidget, SIGNAL(fileInspectionFinished()), this, SLOT(resultInspectionFinished()));
183
184 tieStaticWidgets(true);
185}
186
191 QSettings settings;
192 settings.beginGroup("Mantid/Algorithms/Load");
193 m_form.fileWidget->saveSettings(settings, m_form.fileWidget->captureSettings());
194 AlgorithmDialog::saveInput();
195 // Ensure the filename is store as the full file
196 API::AlgorithmInputHistory::Instance().storeNewValue("Load", std::pair<QString, QString>("Filename", m_currentFiles));
197}
198
203void LoadDialog::tieStaticWidgets(const bool readHistory) {
204 // If a workspace validator asterisk exists, remove it since the underlying
205 // AlgorithmDialog gets confused
206 if (m_form.workspaceLayout->count() == 3) {
207 QLayoutItem *validLbl = m_form.workspaceLayout->takeAt(2);
208 delete validLbl->widget();
209 delete validLbl;
210 }
211 tie(m_form.workspaceEdit, "OutputWorkspace", m_form.workspaceLayout, readHistory);
212 tie(m_form.fileWidget, "Filename", nullptr, readHistory);
213}
214
219void LoadDialog::removeOldInputWidgets(QVBoxLayout *layout) {
220 // Remove the old widgets if necessary
221 if (layout->count() > 2) {
222 int count = layout->count();
223 while (count > 2) {
224 QLayoutItem *child = layout->takeAt(count - 1);
225 if (QWidget *w = child->widget()) {
226 w->deleteLater();
227 } else if (QLayout *l = child->layout()) {
228 QLayoutItem *subChild(nullptr);
229 while ((subChild = l->takeAt(0)) != nullptr) {
230 subChild->widget()->deleteLater();
231 }
232 }
233 count = layout->count();
234 }
235 }
236}
237
242 // Disable the layout so that a widget cannot be interacted with while it may
243 // be being deleted
244 m_form.propertyLayout->setEnabled(false);
245
246 if (!m_form.fileWidget->isValid())
247 return;
248 // First step is the get the specific loader that is responsible
249 auto loadAlg = getAlgorithm();
250 const QString filenames = m_form.fileWidget->getUserInput().toString();
251 if (filenames == m_currentFiles)
252 return;
253 m_currentFiles = filenames;
254 removeOldInputWidgets(m_form.propertyLayout); // The new file might be invalid
255 try {
256 loadAlg->setPropertyValue("Filename", filenames.toStdString());
257 } catch (std::exception &exc) {
258 m_form.fileWidget->setFileProblem(QString::fromStdString(exc.what()));
259 m_form.propertyLayout->setEnabled(true);
260 m_form.propertyLayout->activate();
261 this->resize(this->width(), m_initialHeight + 15);
262
263 // Reset the algorithm pointer so that the base class re-reads the
264 // properties and drops links from
265 // old widgets meaning they are safe to remove
266 setAlgorithm(loadAlg);
267 tieStaticWidgets(false); // The ties are cleared when resetting the
268 // algorithm
269
270 return;
271 }
272 // Reset the algorithm pointer so that the base class re-reads the properties
273 // and drops links from
274 // old widgets meaning they are safe to remove
275 setAlgorithm(loadAlg);
276 tieStaticWidgets(false); // The ties are cleared when resetting the algorithm
277 // Add the new ones
278 const std::vector<Property *> &inputProps = loadAlg->getProperties();
279 int dialogHeight = m_initialHeight;
280 for (auto prop : inputProps) {
281 const QString propName = QString::fromStdString(prop->name());
282 if (propName == "OutputWorkspace" || propName == "Filename")
283 continue;
284 if (requiresUserInput(propName)) {
285 dialogHeight += createWidgetsForProperty(prop, m_form.propertyLayout, m_form.scrollAreaWidgetContents);
286 }
287 }
288 // Re-enable and recompute the size of the layout
289 m_form.propertyLayout->setEnabled(true);
290 m_form.propertyLayout->activate();
291
292 const auto screenSize = screen()->availableSize();
293 const auto screenGeometry = screen()->availableGeometry();
294 dialogHeight = std::min(dialogHeight, static_cast<int>(screenSize.height() * 0.65));
295 this->resize(this->width(), dialogHeight);
296 const auto xPos = screenGeometry.x() + (screenSize.width() - this->width()) / 2;
297 const auto yPos = screenGeometry.y() + (screenSize.height() - this->height()) / 2;
298 this->move(xPos, yPos);
299
300 // Make sure the OutputWorkspace value has been stored so that the validator
301 // is cleared appropriately
302 QString wsName(m_form.workspaceEdit->text());
303 if (!wsName.isEmpty())
304 storePropertyValue("OutputWorkspace", wsName);
305 setPropertyValues(QStringList("Filename"));
306}
307
314int LoadDialog::createWidgetsForProperty(const Mantid::Kernel::Property *prop, QVBoxLayout *propertyLayout,
315 QWidget *parent) {
316 QString propName = QString::fromStdString(prop->name());
317 QWidget *inputWidget(nullptr);
318 QHBoxLayout *widgetLayout(nullptr);
319 bool addValidator(true);
320
321 // Boolean properties use the name labels differently
322 if (const auto *fileType = dynamic_cast<const FileProperty *>(prop)) {
323 auto *fileFinder = new FileFinderWidget(parent);
324 inputWidget = fileFinder;
325 fileFinder->setLabelText(propName);
326 fileFinder->isForRunFiles(false);
327 fileFinder->isOptional(fileType->isOptional());
328 fileFinder->doMultiEntry(false);
329 addValidator = false;
330 propertyLayout->addWidget(inputWidget);
331 } else {
332 QLabel *nameLbl = new QLabel(propName, parent);
333 nameLbl->setToolTip(QString::fromStdString(prop->documentation()));
334 if (dynamic_cast<const PropertyWithValue<bool> *>(prop)) {
335 auto *checkBox = new QCheckBox(parent);
336 inputWidget = checkBox;
337 addValidator = false;
338 }
339 // Options box
340 else if (!prop->allowedValues().empty()) {
341 auto *optionsBox = new QComboBox(parent);
342 inputWidget = optionsBox;
343 std::vector<std::string> items = prop->allowedValues();
344 std::vector<std::string>::const_iterator vend = items.end();
345 for (std::vector<std::string>::const_iterator vitr = items.begin(); vitr != vend; ++vitr) {
346 optionsBox->addItem(QString::fromStdString(*vitr));
347 }
348 // Set current as visible
349 int index = optionsBox->findText(QString::fromStdString(prop->value()));
350 if (index >= 0)
351 optionsBox->setCurrentIndex(index);
352
353 addValidator = false;
354 }
355 // else render a text box
356 else {
357 auto *textBox = new QLineEdit(parent);
358 inputWidget = textBox;
359 if (dynamic_cast<const MaskedProperty<std::string> *>(prop)) {
360 textBox->setEchoMode(QLineEdit::Password);
361 }
362 }
363 nameLbl->setBuddy(inputWidget);
364 widgetLayout = new QHBoxLayout();
365 widgetLayout->addWidget(nameLbl);
366 widgetLayout->addWidget(inputWidget);
367 propertyLayout->addLayout(widgetLayout);
368 }
369
370 if (addValidator)
371 tie(inputWidget, propName, widgetLayout);
372 else
373 tie(inputWidget, propName, nullptr);
374
375 return inputWidget->geometry().height();
376}
377} // namespace MantidQt::CustomDialogs
#define DECLARE_DIALOG(classname)
double height
Definition GetAllEi.cpp:155
std::map< DeltaEMode::Type, std::string > index
bool initial
bool & heldflag
int count
counter
Definition Matrix.cpp:37
bool isMessageAvailable() const
Is there a message string available.
void setAlgorithm(const Mantid::API::IAlgorithm_sptr &)
The following methods were made public for testing in GenericDialogDemo.cpp.
bool setPropertyValues(const QStringList &skipList=QStringList())
Set properties on this algorithm by pulling values from the tied widgets.
bool requiresUserInput(const QString &propName) const
Return a true if the given property requires user input.
QLayout * createDefaultButtonLayout(const QString &helpText=QString("?"), const QString &loadText=QString("Run"), const QString &cancelText=QString("Close"), const QString &keepOpenText=QString("Keep Open"))
Create a row layout of buttons with specified text.
void storePropertyValue(const QString &name, const QString &value)
Adds a property (name,value) pair to the stored map.
QWidget * tie(QWidget *widget, const QString &property, QLayout *parent_layout=nullptr, bool readHistory=true)
Tie a widget to a property.
Mantid::API::IAlgorithm_sptr getAlgorithm() const
Get the algorithm pointer.
const QString & getOptionalMessage() const
Get the message string.
This class defines a widget for file searching.
static void showAlgorithm(const std::string &name=std::string(), const int version=-1)
This class gives specialised dialog for the Load algorithm.
Definition LoadDialog.h:47
void tieStaticWidgets(const bool readHistory)
Tie static widgets to their properties.
void resultInspectionFinished()
Accept the load dialog when user input is inspected and is valid.
void saveInput() override
Save the input history.
int m_initialHeight
The initial height.
Definition LoadDialog.h:90
int createWidgetsForProperty(const Mantid::Kernel::Property *prop, QVBoxLayout *propertyLayout, QWidget *parent)
Create the widgets for a given property.
void helpClicked() override
Override the help button clicked method.
void enableNameSuggestion(const bool on=false)
Connect/Disconnect the signal that updates the workspace name with a suggested value.
void accept() override
Override accept() slot.
bool m_userAccept
Flag to indicate the user accepted the load dialog.
Definition LoadDialog.h:94
void suggestWSName()
Suggest a workspace name from the file.
void initLayout() override
Initialize the layout.
bool m_populating
Flag to indicating if we are populating the dialog.
Definition LoadDialog.h:92
void createDynamicWidgets()
Create the widgets and layouts that are dynamic, i.e they depend on the specific load algorithm.
void removeOldInputWidgets(QVBoxLayout *layout)
Clears all of the widgets from the old layout.
QString m_currentFiles
The current file.
Definition LoadDialog.h:88
A specialized class for dealing with file properties.
A property class for masking the properties.
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:94
const std::string & documentation() const
Get the property's documentation string.
Definition Property.cpp:78
const std::string & name() const
Get the property's name.
Definition Property.cpp:63
virtual std::vector< std::string > allowedValues() const
Returns the set of valid values for this property, if such a set exists.
Definition Property.cpp:155
virtual std::string value() const =0
Returns the value of the property as a string.