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 <QDesktopWidget>
17#include <QFileInfo>
18#include <QUrl>
19
20// Mantid
27
28using namespace Mantid::API;
29using namespace Mantid::Kernel;
31
33namespace {
36struct HoldFlag {
37 HoldFlag(bool &current, const bool holdValue) : initial(current), heldflag(current) { heldflag = holdValue; }
38 ~HoldFlag() { heldflag = initial; }
39 bool initial;
40 bool &heldflag;
41};
42} // namespace
43
44// Blocks signals sent to the load button for the duration
45// of it's lifetime.
47public:
49
51
52private:
54};
55
56// Declare the dialog. Name must match the class name
58
59//--------------------------------------------------------------------------
60// Public methods
61//---------------------------------------------------------------------------
62
63
64LoadDialog::LoadDialog(QWidget *parent)
65 : API::AlgorithmDialog(parent), m_form(), m_currentFiles(), m_initialHeight(0), m_populating(false) {
66 // We will handle parsing the input ourselves on startup
67 m_autoParseOnInit = false;
68}
69
70//--------------------------------------------------------------------------
71// Private methods (slot)
72//---------------------------------------------------------------------------
73
78 HoldFlag hold(m_populating, true);
79
80 m_form.fileWidget->blockSignals(true);
82 m_form.fileWidget->blockSignals(false);
83}
84
87 const auto loaderName = getAlgorithm()->getPropertyValue("LoaderName");
88 QString helpPage = (loaderName.empty()) ? QString("Load") : QString::fromStdString(loaderName);
90}
91
98 if (!m_form.workspaceEdit->isEnabled())
99 return;
100
101 // suggest ws name based on file name
102 QString fileSuggestion;
103 if (m_form.fileWidget->isValid()) {
104 if (m_form.fileWidget->getFilenames().size() == 1)
105 fileSuggestion = QFileInfo(m_form.fileWidget->getFirstFilename()).completeBaseName();
106 else
107 fileSuggestion = "MultiFiles";
108 }
109 m_form.workspaceEdit->setText(fileSuggestion);
110}
111
118 if (on) {
119 connect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(suggestWSName()));
120 } else {
121 disconnect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(suggestWSName()));
122 }
123}
124
125void LoadDialog::enableLoadRequests() { m_okButton->blockSignals(false); }
126
127void LoadDialog::disableLoadRequests() { m_okButton->blockSignals(true); }
128
133 // The file widget may have been edited but not lost focus so that the search
134 // wasn't attempted for the new contents. Force one here.
135 // The widget does nothing if the contents have not changed so it will be
136 // quick for this case
137 PreventLoadRequests preventLoadRequestsWhileAlive(*this);
138 m_form.fileWidget->findFiles();
139 while (m_form.fileWidget->isSearching() || m_populating)
140 QApplication::instance()->processEvents();
141
142 // Makes it so the dialog is still resizable if it is kept open
143 m_form.propertyLayout->setEnabled(true);
144
145 // Check that the file still exists just incase it somehow got removed
146 std::string errMess = getAlgorithm()->getPointerToProperty("Filename")->isValid();
147 if (!errMess.empty()) {
148 m_currentFiles = "";
150 } else
151 AlgorithmDialog::accept();
152}
153
154//--------------------------------------------------------------------------
155// Private methods (non-slot)
156//---------------------------------------------------------------------------
157
160 m_form.setupUi(this);
161
162 // Add the helpful summary message
163 if (isMessageAvailable())
164 m_form.instructions->setText(getOptionalMessage());
165
166 m_form.dialogLayout->addLayout(this->createDefaultButtonLayout());
167 m_form.fileWidget->readSettings("Mantid/Algorithms/Load");
168 m_initialHeight = this->height();
169
170 const std::string &outWsName = getAlgorithm()->getPropertyValue("OutputWorkspace");
171 if (!outWsName.empty()) {
172 // OutputWorkspace name suggestion received as parameter, just take it and
173 // don't change it
174 m_form.workspaceEdit->setText(QString::fromStdString(outWsName));
175 } else {
176 // Guess at an output workspace name but only if the user hasn't changed
177 // anything
179 connect(m_form.workspaceEdit, SIGNAL(textEdited(const QString &)), this, SLOT(enableNameSuggestion()));
180 }
181
182 // Connect the file finder's file found signal to the dynamic property create
183 // method.
184 // When the file text is set the Load algorithm finds the concrete loader and
185 // then we
186 // know what extra properties to create
187 connect(m_form.fileWidget, SIGNAL(filesFound()), this, SLOT(createDynamicWidgets()));
188 tieStaticWidgets(true);
189}
190
195 m_form.fileWidget->saveSettings("Mantid/Algorithms/Load");
196 AlgorithmDialog::saveInput();
197 // Ensure the filename is store as the full file
198 API::AlgorithmInputHistory::Instance().storeNewValue("Load", QPair<QString, QString>("Filename", m_currentFiles));
199}
200
205void LoadDialog::tieStaticWidgets(const bool readHistory) {
206 // If a workspace validator asterisk exists, remove it since the underlying
207 // AlgorithmDialog gets confused
208 if (m_form.workspaceLayout->count() == 3) {
209 QLayoutItem *validLbl = m_form.workspaceLayout->takeAt(2);
210 delete validLbl->widget();
211 delete validLbl;
212 }
213 tie(m_form.workspaceEdit, "OutputWorkspace", m_form.workspaceLayout, readHistory);
214 tie(m_form.fileWidget, "Filename", nullptr, readHistory);
215}
216
221void LoadDialog::removeOldInputWidgets(QVBoxLayout *layout) {
222 // Remove the old widgets if necessary
223 if (layout->count() > 2) {
224 int count = layout->count();
225 while (count > 2) {
226 QLayoutItem *child = layout->takeAt(count - 1);
227 if (QWidget *w = child->widget()) {
228 w->deleteLater();
229 } else if (QLayout *l = child->layout()) {
230 QLayoutItem *subChild(nullptr);
231 while ((subChild = l->takeAt(0)) != nullptr) {
232 subChild->widget()->deleteLater();
233 }
234 }
235 count = layout->count();
236 }
237 }
238}
239
244 // Disable the layout so that a widget cannot be interacted with while it may
245 // be being deleted
246 m_form.propertyLayout->setEnabled(false);
247
248 if (!m_form.fileWidget->isValid())
249 return;
250 // First step is the get the specific loader that is responsible
251 auto loadAlg = getAlgorithm();
252 const QString filenames = m_form.fileWidget->getUserInput().toString();
253 if (filenames == m_currentFiles)
254 return;
255 m_currentFiles = filenames;
256 removeOldInputWidgets(m_form.propertyLayout); // The new file might be invalid
257 try {
258 loadAlg->setPropertyValue("Filename", filenames.toStdString());
259 } catch (std::exception &exc) {
260 m_form.fileWidget->setFileProblem(QString::fromStdString(exc.what()));
261 m_form.propertyLayout->setEnabled(true);
262 m_form.propertyLayout->activate();
263 this->resize(this->width(), m_initialHeight + 15);
264
265 // Reset the algorithm pointer so that the base class re-reads the
266 // properties and drops links from
267 // old widgets meaning they are safe to remove
268 setAlgorithm(loadAlg);
269 tieStaticWidgets(false); // The ties are cleared when resetting the
270 // algorithm
271
272 return;
273 }
274 // Reset the algorithm pointer so that the base class re-reads the properties
275 // and drops links from
276 // old widgets meaning they are safe to remove
277 setAlgorithm(loadAlg);
278 tieStaticWidgets(false); // The ties are cleared when resetting the algorithm
279 // Add the new ones
280 const std::vector<Property *> &inputProps = loadAlg->getProperties();
281 int dialogHeight = m_initialHeight;
282 for (auto prop : inputProps) {
283 const QString propName = QString::fromStdString(prop->name());
284 if (propName == "OutputWorkspace" || propName == "Filename")
285 continue;
286 if (requiresUserInput(propName)) {
287 dialogHeight += createWidgetsForProperty(prop, m_form.propertyLayout, m_form.scrollAreaWidgetContents);
288 }
289 }
290 // Re-enable and recompute the size of the layout
291 m_form.propertyLayout->setEnabled(true);
292 m_form.propertyLayout->activate();
293
294 const int screenHeight = QApplication::desktop()->height();
295 // If the thing won't end up too big compared to the screen height,
296 // resize the scroll area so we don't get a scroll bar
297 if (dialogHeight < 0.8 * screenHeight)
298 this->resize(this->width(), dialogHeight + 20);
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
Definition: DeltaEMode.cpp:19
bool initial
Definition: LoadDialog.cpp:39
bool & heldflag
Definition: LoadDialog.cpp:40
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)
Definition: HelpWindow.cpp:50
void tieStaticWidgets(const bool readHistory)
Tie static widgets to their properties.
Definition: LoadDialog.cpp:205
void saveInput() override
Save the input history.
Definition: LoadDialog.cpp:194
int m_initialHeight
The initial height.
Definition: LoadDialog.h:94
int createWidgetsForProperty(const Mantid::Kernel::Property *prop, QVBoxLayout *propertyLayout, QWidget *parent)
Create the widgets for a given property.
Definition: LoadDialog.cpp:314
void helpClicked() override
Override the help button clicked method.
Definition: LoadDialog.cpp:86
void enableNameSuggestion(const bool on=false)
Connect/Disconnect the signal that updates the workspace name with a suggested value.
Definition: LoadDialog.cpp:117
void accept() override
Override accept() slot.
Definition: LoadDialog.cpp:132
void suggestWSName()
Suggest a workspace name from the file.
Definition: LoadDialog.cpp:97
void initLayout() override
Initialize the layout.
Definition: LoadDialog.cpp:159
bool m_populating
Flag to indicating if we are populating the dialog.
Definition: LoadDialog.h:96
void enableLoadRequests()
Accept requests to load until they are disabled.
Definition: LoadDialog.cpp:125
void createDynamicWidgets()
Create the widgets and layouts that are dynamic, i.e they depend on the specific load algorithm.
Definition: LoadDialog.cpp:77
void removeOldInputWidgets(QVBoxLayout *layout)
Clears all of the widgets from the old layout.
Definition: LoadDialog.cpp:221
void disableLoadRequests()
Ignore requests to load until they are re-enabled.
Definition: LoadDialog.cpp:127
QString m_currentFiles
The current file.
Definition: LoadDialog.h:92
A specialized class for dealing with file properties.
Definition: FileProperty.h:42
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:65
const std::string & name() const
Get the property's name.
Definition: Property.cpp:60
virtual std::vector< std::string > allowedValues() const
Returns the set of valid values for this property, if such a set exists.
Definition: Property.cpp:140
virtual std::string value() const =0
Returns the value of the property as a string.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...