Mantid
Loading...
Searching...
No Matches
WorkspaceTreeWidgetSimple.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 +
12
14#include "MantidAPI/Axis.h"
22
23#include <QMenu>
24#include <QSignalMapper>
25
26using namespace Mantid::API;
27using namespace Mantid::Kernel;
28
29namespace {
30bool hasSingleValue(const MatrixWorkspace &ws) {
31 return (ws.getNumberHistograms() == 1 && ws.blocksize() == 1 && ws.getNumDims() == 0);
32}
33bool hasMultipleBins(const MatrixWorkspace &ws) {
34 try {
35 return (ws.blocksize() > 1);
36 } catch (...) {
37 const size_t numHist = ws.getNumberHistograms();
38 for (size_t i = 0; i < numHist; ++i) {
39 if (ws.y(i).size() > 1) {
40 return true;
41 }
42 }
43 }
44 return false;
45}
46} // namespace
47
49
51 : WorkspaceTreeWidget(new MantidTreeModel(), viewOnly, parent), m_plotSpectrum(new QAction("Spectrum...", this)),
52 m_plotBin(new QAction("Bin", this)), m_overplotSpectrum(new QAction("Overplot spectrum...", this)),
53 m_plotSpectrumWithErrs(new QAction("Spectrum with errors...", this)),
54 m_overplotSpectrumWithErrs(new QAction("Overplot spectrum with errors...", this)),
55 m_plotColorfill(new QAction("Colorfill", this)), m_sampleLogs(new QAction("Show Sample Logs", this)),
56 m_sliceViewer(new QAction("Show Slice Viewer", this)), m_showInstrument(new QAction("Show Instrument", this)),
57 m_showData(new QAction("Show Data", this)), m_showAlgorithmHistory(new QAction("Show History", this)),
58 m_showDetectors(new QAction("Show Detectors", this)), m_plotAdvanced(new QAction("Advanced...", this)),
59 m_plotSurface(new QAction("Surface", this)), m_plotWireframe(new QAction("Wireframe", this)),
60 m_plotContour(new QAction("Contour", this)), m_plotMDHisto1D(new QAction("Plot 1D MDHistogram...", this)),
61 m_overplotMDHisto1D(new QAction("Overplot 1D MDHistogram...", this)),
62 m_plotMDHisto1DWithErrs(new QAction("Plot 1D MDHistogram with errors...", this)),
63 m_overplotMDHisto1DWithErrs(new QAction("Overplot 1D MDHistogram with errors...", this)),
64 m_sampleMaterial(new QAction("Show Sample Material", this)),
65 m_sampleShape(new QAction("Show Sample Shape", this)), m_superplot(new QAction("Superplot...", this)),
66 m_superplotWithErrs(new QAction("Superplot with errors...", this)),
67 m_superplotBins(new QAction("Superplot bins...", this)),
68 m_superplotBinsWithErrs(new QAction("Superplot bins with errors...", this)),
69 m_showNewInstrumentView(new QAction("(Experimental) Show Instrument", this)), m_separator(new QAction()) {
70
71 // Replace the double click action on the MantidTreeWidget
72 m_tree->m_doubleClickAction = [&](const QString &wsName) { emit workspaceDoubleClicked(wsName); };
73
74 connect(m_plotSpectrum, SIGNAL(triggered()), this, SLOT(onPlotSpectrumClicked()));
75 // connect event m_plotMDHisto1D to signal slot onPlotMDHistoWorkspaceClicked
76 connect(m_plotMDHisto1D, SIGNAL(triggered()), this, SLOT(onPlotMDHistoWorkspaceClicked()));
77 connect(m_overplotMDHisto1D, SIGNAL(triggered()), this, SLOT(onOverPlotMDHistoWorkspaceClicked()));
78 connect(m_plotMDHisto1DWithErrs, SIGNAL(triggered()), this, SLOT(onPlotMDHistoWorkspaceWithErrorsClicked()));
79 connect(m_overplotMDHisto1DWithErrs, SIGNAL(triggered()), this, SLOT(onOverPlotMDHistoWorkspaceWithErrorsClicked()));
80
81 connect(m_plotBin, SIGNAL(triggered()), this, SLOT(onPlotBinClicked()));
82 connect(m_overplotSpectrum, SIGNAL(triggered()), this, SLOT(onOverplotSpectrumClicked()));
83 connect(m_plotSpectrumWithErrs, SIGNAL(triggered()), this, SLOT(onPlotSpectrumWithErrorsClicked()));
84 connect(m_overplotSpectrumWithErrs, SIGNAL(triggered()), this, SLOT(onOverplotSpectrumWithErrorsClicked()));
85 connect(m_plotColorfill, SIGNAL(triggered()), this, SLOT(onPlotColorfillClicked()));
86 connect(m_sampleLogs, SIGNAL(triggered()), this, SLOT(onSampleLogsClicked()));
87 connect(m_sliceViewer, SIGNAL(triggered()), this, SLOT(onSliceViewerClicked()));
88 connect(m_showInstrument, SIGNAL(triggered()), this, SLOT(onShowInstrumentClicked()));
89 connect(m_showData, SIGNAL(triggered()), this, SLOT(onShowDataClicked()));
90 connect(m_tree, SIGNAL(itemSelectionChanged()), this, SIGNAL(treeSelectionChanged()));
91 connect(m_showAlgorithmHistory, SIGNAL(triggered()), this, SLOT(onShowAlgorithmHistoryClicked()));
92 connect(m_showDetectors, SIGNAL(triggered()), this, SLOT(onShowDetectorsClicked()));
93 connect(m_plotAdvanced, SIGNAL(triggered()), this, SLOT(onPlotAdvancedClicked()));
94 connect(m_plotSurface, SIGNAL(triggered()), this, SLOT(onPlotSurfaceClicked()));
95 connect(m_plotWireframe, SIGNAL(triggered()), this, SLOT(onPlotWireframeClicked()));
96 connect(m_plotContour, SIGNAL(triggered()), this, SLOT(onPlotContourClicked()));
97 connect(m_sampleMaterial, SIGNAL(triggered()), this, SLOT(onSampleMaterialClicked()));
98 connect(m_sampleShape, SIGNAL(triggered()), this, SLOT(onSampleShapeClicked()));
99 connect(m_superplot, SIGNAL(triggered()), this, SLOT(onSuperplotClicked()));
100 connect(m_superplotWithErrs, SIGNAL(triggered()), this, SLOT(onSuperplotWithErrsClicked()));
101 connect(m_superplotBins, SIGNAL(triggered()), this, SLOT(onSuperplotBinsClicked()));
102 connect(m_superplotBinsWithErrs, SIGNAL(triggered()), this, SLOT(onSuperplotBinsWithErrsClicked()));
103 connect(m_showNewInstrumentView, SIGNAL(triggered()), this, SLOT(onShowNewInstrumentViewClicked()));
104 m_separator->setSeparator(true);
105}
106
108
110 m_overplotSpectrum->setDisabled(disabled);
111 m_overplotSpectrumWithErrs->setDisabled(disabled);
112}
113
116 QTreeWidgetItem *treeItem = m_tree->itemAt(m_menuPosition);
117 selectedWsName = "";
118 if (treeItem)
119 selectedWsName = treeItem->text(0);
120 else
121 m_tree->selectionModel()->clear();
122
123 QMenu *menu(nullptr);
124 if (selectedWsName.isEmpty()) {
125 // If no workspace is here then have load items
126 menu = m_loadMenu;
127 } else {
129 }
130
131 // Show the menu at the cursor's current position
132 menu->popup(QCursor::pos());
133}
134
138
140
144
148
152
156
158
160
164
166
170
174
178
180
184
186
187// Define signal
191
195
199
203
207
209
211
215
219
223
227
232QMenu *WorkspaceTreeWidgetSimple::createWorkspaceContextMenu(const QStringList &selectedWorkspaces) {
233 auto menu = new QMenu(this);
234 menu->setAttribute(Qt::WA_DeleteOnClose, true);
235 menu->setObjectName("WorkspaceContextMenu");
236
237 std::vector<Workspace_sptr> workspaces;
238 std::vector<MenuActions> actionVecs;
239 std::vector<MenuActions> plotMenuActionVecs;
240 std::vector<MenuActions> plotMenu3DActionVecs;
241 for (const auto &workspaceName : selectedWorkspaces) {
243 try {
244 workspace = AnalysisDataService::Instance().retrieve(workspaceName.toStdString());
245 } catch (Exception::NotFoundError &) {
246 continue;
247 }
248 workspaces.push_back(workspace);
249 if (auto matrixWS = std::dynamic_pointer_cast<MatrixWorkspace>(workspace)) {
250 auto [actions, plotActions] = createMatrixWorkspaceActions(*matrixWS);
251 actionVecs.push_back(actions);
252 plotMenuActionVecs.push_back(plotActions.plotActions);
253 plotMenu3DActionVecs.push_back(plotActions.plot3DActions);
254 } else if (auto tableWS = std::dynamic_pointer_cast<ITableWorkspace>(workspace)) {
255 actionVecs.push_back(createTableWorkspaceActions(*tableWS));
256 plotMenuActionVecs.push_back(MenuActions{});
257 plotMenu3DActionVecs.push_back(MenuActions{});
258 } else if (auto mdWS = std::dynamic_pointer_cast<IMDWorkspace>(workspace)) {
259 auto [actions, plotActions] = createMDWorkspaceActions(*mdWS);
260 actionVecs.push_back(actions);
261 plotMenuActionVecs.push_back(plotActions.plotActions);
262 plotMenu3DActionVecs.push_back(plotActions.plot3DActions);
263 } else if (auto wsGroup = std::dynamic_pointer_cast<WorkspaceGroup>(workspace)) {
264 auto [actions, plotActions] = createWorkspaceGroupActions(*wsGroup);
265 actionVecs.push_back(actions);
266 plotMenuActionVecs.push_back(plotActions.plotActions);
267 plotMenu3DActionVecs.push_back(plotActions.plot3DActions);
268 }
269 }
270
271 MenuActions combinedActions = intersectionOfActions(actionVecs);
272 MenuActions combinedPlotMenuActions = intersectionOfActions(plotMenuActionVecs);
273 MenuActions combined3DPlotMenuActions = intersectionOfActions(plotMenu3DActionVecs);
274
275 const auto it = std::find(combinedActions.cbegin(), combinedActions.cend(), m_showInstrument);
276 if (it != combinedActions.cend()) {
277 const auto showInstrumentViewCheck = [](const MatrixWorkspace_const_sptr &workspace) {
278 return workspace->getInstrument() && !workspace->getInstrument()->getName().empty() &&
279 workspace->getAxis(1)->isSpectra();
280 };
281 const bool enabled =
282 std::all_of(workspaces.cbegin(), workspaces.cend(), [&showInstrumentViewCheck](const Workspace_sptr &ws) {
283 if (const auto matrixWS = std::dynamic_pointer_cast<MatrixWorkspace>(ws)) {
284 return showInstrumentViewCheck(matrixWS);
285 }
286 return false;
287 });
288 m_showInstrument->setEnabled(enabled);
289 m_showNewInstrumentView->setEnabled(enabled);
290 }
291
292 if (!combinedPlotMenuActions.empty()) {
293 auto *plotSubMenu = new QMenu("Plot", menu);
294 for (const auto &action : combinedPlotMenuActions) {
295 plotSubMenu->addAction(action);
296 }
297 if (!combined3DPlotMenuActions.empty()) {
298 auto *plot3DMenu = new QMenu("3D", menu);
299 for (const auto &action : combined3DPlotMenuActions) {
300 plot3DMenu->addAction(action);
301 }
302 plotSubMenu->addMenu(plot3DMenu);
303 }
304 menu->addMenu(plotSubMenu);
305 }
306
307 for (const auto &action : combinedActions) {
308 menu->addAction(action);
309 }
310
311 // Add for all types
312 addGeneralWorkspaceActions(menu);
313
314 return menu;
315}
316
317MenuActions WorkspaceTreeWidgetSimple::intersectionOfActions(std::vector<MenuActions> actionVecs) {
318 if (actionVecs.empty()) {
319 return {};
320 }
321 std::sort(actionVecs.begin(), actionVecs.end(), [](const auto &a, const auto &b) { return a.size() > b.size(); });
322 MenuActions combinedActions = actionVecs.front();
323
324 std::erase_if(combinedActions, [&actionVecs](QAction *action) {
325 return (!std::all_of(actionVecs.cbegin() + 1, actionVecs.cend(), [&action](const MenuActions &actionVec) {
326 const auto it = std::find(actionVec.cbegin(), actionVec.cend(), action);
327 return it != actionVec.cend();
328 }));
329 });
330
331 return combinedActions;
332}
333
334std::tuple<MenuActions, PlotMenuActions>
335WorkspaceTreeWidgetSimple::createMatrixWorkspaceActions(const Mantid::API::MatrixWorkspace &workspace) {
336 MenuActions actions;
337 // Show just data for a single value.
338 if (hasSingleValue(workspace)) {
339 actions.push_back(m_showData);
340 return std::make_tuple(actions, PlotMenuActions());
341 }
342
343 auto plotActions = createMatrixWorkspacePlotMenu(hasMultipleBins(workspace));
344 actions.push_back(m_separator);
345 actions.push_back(m_showData);
346 actions.push_back(m_showAlgorithmHistory);
347 actions.push_back(m_showInstrument);
348 actions.push_back(m_sampleLogs);
349 actions.push_back(m_sliceViewer);
350 actions.push_back(m_showDetectors);
351 if (m_tree->selectedItems().size() == 1) {
352 actions.push_back(m_sampleMaterial);
353 actions.push_back(m_sampleShape);
354 }
355 actions.push_back(m_showNewInstrumentView);
356 return std::make_tuple(actions, plotActions);
357}
358
359MenuActions WorkspaceTreeWidgetSimple::createTableWorkspaceActions(const Mantid::API::ITableWorkspace &workspace) {
360 MenuActions actions;
361 actions.push_back(m_showData);
362 actions.push_back(m_showAlgorithmHistory);
363 if (dynamic_cast<const IPeaksWorkspace *>(&workspace)) {
364 actions.push_back(m_showDetectors);
365 }
366 return actions;
367}
368
369std::tuple<MenuActions, PlotMenuActions>
370WorkspaceTreeWidgetSimple::createMDWorkspaceActions(const Mantid::API::IMDWorkspace &workspace) {
371 MenuActions actions;
372 PlotMenuActions plotMenu;
373 actions.push_back(m_showAlgorithmHistory);
374 actions.push_back(m_sampleLogs);
375
376 // launch slice viewer or plot spectrum conditionally
377 bool addSliceViewer = false;
378 bool add1DPlot = false;
379
380 if (workspace.isMDHistoWorkspace()) {
381 // if the number of non-integral if the number of non-integrated
382 // dimensions is 1.
383 auto num_dims = workspace.getNumNonIntegratedDims();
384 if (num_dims == 1) {
385 // number of non-integral dimension is 1: show menu item to plot
386 // spectrum
387 add1DPlot = true;
388 } else if (num_dims > 1) {
389 // number of non-integral dimension is larger than 1: show menu item
390 // to launch slice view
391 addSliceViewer = true;
392 }
393 } else if (workspace.getNumDims() > 1) {
394 addSliceViewer = true;
395 }
396
397 if (addSliceViewer) {
398 actions.push_back(m_sliceViewer);
399 } else if (add1DPlot) {
400 plotMenu.plotActions = {m_plotMDHisto1D, m_overplotMDHisto1D, m_plotMDHisto1DWithErrs, m_overplotMDHisto1DWithErrs};
401 }
402 return std::make_tuple(actions, plotMenu);
403}
404
405std::tuple<MenuActions, PlotMenuActions>
406WorkspaceTreeWidgetSimple::createWorkspaceGroupActions(const Mantid::API::WorkspaceGroup &workspace) {
407 MenuActions actions;
408 PlotMenuActions plotMenu;
409 auto workspaces = workspace.getAllItems();
410 bool containsMatrixWorkspace{false};
411 bool containsPeaksWorkspace{false};
412 for (const auto &ws : workspaces) {
413 if (std::dynamic_pointer_cast<MatrixWorkspace>(ws)) {
414 containsMatrixWorkspace = true;
415 break;
416 } else if (std::dynamic_pointer_cast<IPeaksWorkspace>(ws)) {
417 containsPeaksWorkspace = true;
418 }
419 }
420
421 // Add plotting options if the group contains at least one matrix
422 // workspace.
423 if (containsMatrixWorkspace) {
424 plotMenu = createMatrixWorkspacePlotMenu(true);
425 actions.push_back(m_separator);
426 actions.push_back(m_showDetectors);
427 }
428
429 if (containsPeaksWorkspace) {
430 actions.push_back(m_showData);
431 actions.push_back(m_showDetectors);
432 }
433 return std::make_tuple(actions, plotMenu);
434}
435
436void WorkspaceTreeWidgetSimple::addGeneralWorkspaceActions(QMenu *menu) const {
437 menu->addSeparator();
438 menu->addAction(m_rename);
439 menu->addAction(m_saveNexus);
440 menu->addSeparator();
441 menu->addAction(m_delete);
442}
443
444PlotMenuActions WorkspaceTreeWidgetSimple::createMatrixWorkspacePlotMenu(bool hasMultipleBins) {
445 PlotMenuActions plotMenu;
446 if (hasMultipleBins) {
447 plotMenu.plotActions = {m_plotSpectrum, m_overplotSpectrum, m_plotSpectrumWithErrs, m_overplotSpectrumWithErrs,
448 m_plotAdvanced, m_superplot, m_superplotWithErrs, m_separator,
449 m_plotColorfill};
450 // 3D
451 plotMenu.plot3DActions = {m_plotSurface, m_plotWireframe, m_plotContour};
452 } else {
453 plotMenu.plotActions = {m_superplotBins, m_superplotBinsWithErrs, m_separator, m_plotColorfill};
454 }
455
456 return plotMenu;
457}
458
459} // namespace MantidQt::MantidWidgets
IPeaksWorkspace_sptr workspace
std::function< void(QString)> m_doubleClickAction
Action that is executed when a workspace in the tree is double clicked.
void overplotMDHistoClicked(const QStringList &workspaceNames)
void plotBinClicked(const QStringList &workspaceNames)
void sliceViewerClicked(const QStringList &workspaceName)
void superplotClicked(const QStringList &workspaceNames)
void plotAdvancedClicked(const QStringList &workspaceNames)
void superplotWithErrsClicked(const QStringList &workspaceNames)
std::tuple< MenuActions, PlotMenuActions > createMatrixWorkspaceActions(const Mantid::API::MatrixWorkspace &workspace)
void plotMDHistoWithErrorsClicked(const QStringList &workspaceNames)
void showAlgorithmHistoryClicked(const QStringList &workspaceNames)
void overplotSpectrumClicked(const QStringList &workspaceNames)
void superplotBinsClicked(const QStringList &workspaceNames)
void plotMDHistoClicked(const QStringList &workspaceNames)
void overplotSpectrumWithErrorsClicked(const QStringList &workspaceNames)
void showDataClicked(const QStringList &workspaceNames)
void workspaceDoubleClicked(const QString &workspaceName)
void overplotMDHistoWithErrorsClicked(const QStringList &workspaceNames)
void plotSurfaceClicked(const QStringList &workspaceNames)
MenuActions intersectionOfActions(std::vector< MenuActions > actionVecs)
void plotSpectrumClicked(const QStringList &workspaceNames)
MenuActions createTableWorkspaceActions(const Mantid::API::ITableWorkspace &workspace)
void sampleMaterialClicked(const QStringList &workspaceNames)
void superplotBinsWithErrsClicked(const QStringList &workspaceNames)
void showNewInstrumentViewClicked(const QStringList &workspaceNames)
void plotColorfillClicked(const QStringList &workspaceNames)
void sampleLogsClicked(const QStringList &workspaceName)
void plotWireframeClicked(const QStringList &workspaceNames)
void showInstrumentClicked(const QStringList &workspaceNames)
WorkspaceTreeWidgetSimple(bool viewOnly=false, QWidget *parent=nullptr)
std::tuple< MenuActions, PlotMenuActions > createWorkspaceGroupActions(const Mantid::API::WorkspaceGroup &workspace)
void showDetectorsClicked(const QStringList &workspaceNames)
QMenu * createWorkspaceContextMenu(const QStringList &selectedWorkspaces)
Create a new QMenu object filled with appropriate items for the given workspace The created object ha...
void plotContourClicked(const QStringList &workspaceNames)
std::tuple< MenuActions, PlotMenuActions > createMDWorkspaceActions(const Mantid::API::IMDWorkspace &workspace)
void sampleShapeClicked(const QStringList &workspaceNames)
void plotSpectrumWithErrorsClicked(const QStringList &workspaceNames)
Basic MD Workspace Abstract Class.
Interface to the class Mantid::DataObjects::PeaksWorkspace.
ITableWorkspace is an implementation of Workspace in which the data are organised in columns of same ...
Base MatrixWorkspace Abstract Class.
virtual std::size_t blocksize() const =0
Returns the size of each block of data returned by the dataY accessors.
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
size_t getNumDims() const override
const HistogramData::HistogramY & y(const size_t index) const
Class to hold a set of workspaces.
Exception for when an item is not found in a collection.
Definition Exception.h:145
std::vector< QAction * > MenuActions
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)