diff --git a/Code/Mantid/DataHandling/inc/MantidDataHandling/CreateSampleShape.h b/Code/Mantid/DataHandling/inc/MantidDataHandling/CreateSampleShape.h new file mode 100644 index 0000000000000000000000000000000000000000..ea4d00eea4fc991f422e7912fd925f90915b83cf --- /dev/null +++ b/Code/Mantid/DataHandling/inc/MantidDataHandling/CreateSampleShape.h @@ -0,0 +1,68 @@ +#ifndef MANTID_DATAHANDLING_CREATESAMPLESHAPE_H_ +#define MANTID_DATAHANDLING_CREATESAMPLESHAPE_H_ + +//-------------------------------- +// Includes +//-------------------------------- +#include "MantidAPI/Algorithm.h" + +namespace Mantid +{ +namespace DataHandling +{ + +/** + This class allows the shape of the sample to be defined by using the allowed XML + expressions + + @author Martyn Gigg, Tessella Support Services plc + @date 13/03/2009 + + Copyright © 2009 STFC Rutherford Appleton Laboratories + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class CreateSampleShape : public Mantid::API::Algorithm +{ +public: + /// (Empty) Constructor + CreateSampleShape() : Mantid::API::Algorithm() {} + /// Virtual destructor + virtual ~CreateSampleShape() {} + /// Algorithm's name + virtual const std::string name() const { return "CreateSampleShape"; } + /// Algorithm's version + virtual const int version() const { return (1); } + /// Algorithm's category for identification + virtual const std::string category() const { return "General"; } + +private: + /// Initialisation code + void init(); + ///Execution code + void exec(); + + /// Static reference to the logger class + static Mantid::Kernel::Logger& g_log; +}; + +} +} + +#endif /* MANTID_DATAHANDLING_CREATESAMPLESHAPE_H_*/ diff --git a/Code/Mantid/DataHandling/src/CreateSampleShape.cpp b/Code/Mantid/DataHandling/src/CreateSampleShape.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ce21aa431d63f28e0db058b841081075f6c0811 --- /dev/null +++ b/Code/Mantid/DataHandling/src/CreateSampleShape.cpp @@ -0,0 +1,42 @@ +//-------------------------------- +// Includes +//-------------------------------- +#include "MantidDataHandling/CreateSampleShape.h" +#include "MantidGeometry/ShapeFactory.h" +#include "MantidAPI/MatrixWorkspace.h" + +namespace Mantid +{ +namespace DataHandling +{ + // Register the algorithm into the AlgorithmFactory + // DECLARE_ALGORITHM(CreateSampleShape) +} +} + +using namespace Mantid::DataHandling; + +// Get a reference to the logger. It is used to print out information, warning and error messages +Mantid::Kernel::Logger& CreateSampleShape::g_log = Mantid::Kernel::Logger::get("CreateSampleShape"); + + + +/** + * Initialize the algorithm + */ +void CreateSampleShape::init() +{ + using namespace Mantid::Kernel; + using namespace Mantid::API; + declareProperty(new WorkspaceProperty<MatrixWorkspace>("Workspace","",Direction::Input)); + declareProperty("ShapeXML","",new MandatoryValidator<std::string>()); +} + +/** + * Execute the algorithm + */ +void CreateSampleShape::exec() +{ + +} + diff --git a/Code/qtiplot/MantidQt/CustomDialogs/inc/CreateSampleShapeDialog.h b/Code/qtiplot/MantidQt/CustomDialogs/inc/CreateSampleShapeDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..621f08db1e1e749821e0083fc6bae076a29330a6 --- /dev/null +++ b/Code/qtiplot/MantidQt/CustomDialogs/inc/CreateSampleShapeDialog.h @@ -0,0 +1,188 @@ +#ifndef MANTIDQT_CUSTOMDIALOGS_CREATESAMPLESHAPEDIALOG_H_ +#define MANTIDQT_CUSTOMDIALOGS_CREATESAMPLESHAPEDIALOG_H_ + +//--------------------------- +// Includes +//-------------------------- +#include "MantidQtCustomDialogs/ui_CreateSampleShapeDialog.h" +#include "MantidQtAPI/AlgorithmDialog.h" + +#include <QTreeWidget> +#include <QItemDelegate> +#include <QPoint> +#include <QHash> +#include <QMap> +#include <QVector> + +//----------------------------------- +// Qt Forward declarations +//--------------------------------- + +namespace MantidQt +{ +namespace CustomDialogs +{ + +class BinaryTreeWidget; +class BinaryTreeWidgetItem; +class ShapeDetails; + +/** + This class gives specialised dialog for the sample shape definition + algorithm + + @author Martyn Gigg, Tessella Support Services plc + @date 13/03/2009 + + Copyright © 2009 STFC Rutherford Appleton Laboratories + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class CreateSampleShapeDialog : public MantidQt::API::AlgorithmDialog +{ + Q_OBJECT + +public: + + /// Default constructor + CreateSampleShapeDialog(QWidget *parent = 0); + /// Destructor + ~CreateSampleShapeDialog(); + +public slots: + ///Context menu request + void handleTreeContextMenuRequest(const QPoint & pos); + + ///Add a new child shape + void addChildShape(QAction *shape); + + // Setup the details box based currently selected item + void setupDetailsBox(); + +private: + + /// Initialize the layout + virtual void initLayout(); + + /// Get the input out of the dialog + virtual void parseInput(); + + /**@name Details setup functions */ + //@{ + /// Setup the box for a sphere + ShapeDetails* setupSphereDetails() const; + + /// Setup the box for a cylinder + ShapeDetails* setupCylinderDetails() const; + //@} + +private: + /// The form generated with Qt Designer + Ui::CreateSampleShapeDialog m_uiForm; + + /// A pointer to the model for the shape tree + BinaryTreeWidget *m_shapeTree; + + /// A map of shape names to function pointers + typedef ShapeDetails* (CreateSampleShapeDialog::*MemFuncGetter)() const; + QHash<QString, MemFuncGetter> m_setup_functions; + + ///A map of QTreeWidgetItem objects to their details objects + QMap<BinaryTreeWidgetItem*, ShapeDetails*> m_details_map; +}; + +/** + * A custom item to use in the BinaryTree widget + */ +class BinaryTreeWidgetItem : public QTreeWidgetItem +{ + +public: + /// Default Constructor + BinaryTreeWidgetItem(int type = QTreeWidgetItem::UserType); + + /// Constructor taking a string list and an optional type + BinaryTreeWidgetItem(const QStringList & strings, int type = QTreeWidgetItem::UserType); + + /// Add a child item + bool addChildItem(BinaryTreeWidgetItem *child); + + /// A pointer to the left child + BinaryTreeWidgetItem* leftChild() const; + + /// A pointer to the right child + BinaryTreeWidgetItem* rightChild() const; + +private: + /// The index of the left child (0 or 1) + int m_left_index; + /// The index of the right child (0 or 1) + int m_right_index; +}; + +/** + * A widget to implement a binary tree display. + */ +class BinaryTreeWidget : public QTreeWidget +{ + Q_OBJECT + +public: + /// Default constructor + BinaryTreeWidget(QWidget *parent = 0); + + /// Check that we have a full binary tree + bool isFullTree() const; + + //Return the root of the binary tree + BinaryTreeWidgetItem* root() const; + + /// Recurse through the tree in a pre-order + void traverseByPreorder(BinaryTreeWidgetItem* node); +}; + +/** + * A custom delegate class used for item editing + */ +class ComboBoxDelegate : public QItemDelegate +{ + Q_OBJECT + +public: + /// Default constructor + ComboBoxDelegate(QWidget *parent = 0); + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + void setEditorData(QWidget *editor, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const; + + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; + +private: + /// A custom data role + static int g_idata_role; +}; + +} +} + +#endif //MANTIDQT_CUSTOMDIALOGS_CREATESAMPLESHAPE_H_ diff --git a/Code/qtiplot/MantidQt/CustomDialogs/inc/CreateSampleShapeDialog.ui b/Code/qtiplot/MantidQt/CustomDialogs/inc/CreateSampleShapeDialog.ui new file mode 100644 index 0000000000000000000000000000000000000000..bd056d143ea73b0ba2d328c9e33c443be32867ef --- /dev/null +++ b/Code/qtiplot/MantidQt/CustomDialogs/inc/CreateSampleShapeDialog.ui @@ -0,0 +1,173 @@ +<ui version="4.0" > + <class>CreateSampleShapeDialog</class> + <widget class="QDialog" name="CreateSampleShapeDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>866</width> + <height>360</height> + </rect> + </property> + <property name="windowTitle" > + <string>Sample Shape Definition</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <layout class="QHBoxLayout" name="horizontalLayout" > + <item> + <widget class="QGroupBox" name="shape_box" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title" > + <string>Object Tree</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_3" /> + </widget> + </item> + <item> + <widget class="QGroupBox" name="details_box" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title" > + <string>Details</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2" > + <item> + <widget class="QScrollArea" name="details_scroll" > + <property name="frameShape" > + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow" > + <enum>QFrame::Raised</enum> + </property> + <property name="widgetResizable" > + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>256</width> + <height>264</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="three_d_box" > + <property name="sizePolicy" > + <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title" > + <string>3D View</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2" > + <item> + <spacer name="horizontalSpacer" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="createBtn" > + <property name="text" > + <string>Create</string> + </property> + <property name="default" > + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cancelBtn" > + <property name="text" > + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>createBtn</sender> + <signal>clicked()</signal> + <receiver>CreateSampleShapeDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>741</x> + <y>379</y> + </hint> + <hint type="destinationlabel" > + <x>438</x> + <y>201</y> + </hint> + </hints> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>CreateSampleShapeDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>827</x> + <y>379</y> + </hint> + <hint type="destinationlabel" > + <x>438</x> + <y>201</y> + </hint> + </hints> + </connection> + </connections> + <designerdata> + <property name="gridDeltaX" > + <number>10</number> + </property> + <property name="gridDeltaY" > + <number>10</number> + </property> + <property name="gridSnapX" > + <bool>false</bool> + </property> + <property name="gridSnapY" > + <bool>false</bool> + </property> + <property name="gridVisible" > + <bool>true</bool> + </property> + </designerdata> +</ui> diff --git a/Code/qtiplot/MantidQt/CustomDialogs/inc/SampleShapeHelpers.h b/Code/qtiplot/MantidQt/CustomDialogs/inc/SampleShapeHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..64e8a76ae847df21839d9d16a28f753c410a33f0 --- /dev/null +++ b/Code/qtiplot/MantidQt/CustomDialogs/inc/SampleShapeHelpers.h @@ -0,0 +1,161 @@ +#ifndef MANTIDQT_CUSTOMDIALOGS_SAMPLESHAPEHELPERS_H_ +#define MANTIDQT_CUSTOMDIALOGS_SAMPLESHAPEHELPERS_H_ + +//-------------------------------------- +// Includes +//-------------------------------------- +#include <QWidget> +#include <QGroupBox> + +//-------------------------------------- +// Qt forward declarations +//-------------------------------------- +class QLineEdit; +class QComboBox; +class QRadioButton; +class QLabel; + +/** + * The classes defined here encapuslate the layout and + * parameters of the individual shapes within Mantid. Each is + * a widget that is to be displayed within the CreateSampleShapeDialog. + * The base class exists so that they can be stored in a container. + */ +namespace MantidQt +{ +namespace CustomDialogs +{ + +/** + * A custom group box for a 3D point + */ +class PointGroupBox : public QGroupBox +{ + Q_OBJECT; + +public: + //Default constructor + PointGroupBox(QWidget* parent = 0); + + ///Write the element tag for a 3D point + QString write3DElement(const QString & elem_name) const; + +private slots: + // Switch to cartesian coordinates + void changeToCartesian(); + // Switch to spherical coordinates + void changeToSpherical(); + +private: + //Labels for fields + QLabel *m_xlabel, *m_ylabel, *m_zlabel; + // Edit fields (also used for r,theta,phi) if in spherical mode + QLineEdit *m_midx, *m_midy, *m_midz; + //Unit choice boxes (x is used for r in spherical mode) + QComboBox *m_xunits, *m_yunits, *m_zunits; + //Radio button selection for coordinates + QRadioButton *m_cartesian, *m_spherical; + //The current coordinate system (0 = cartesian, 1 = spherical) + int m_icoord; +}; + + +/** + * The base class for the details widgets + */ +class ShapeDetails : public QWidget +{ + Q_OBJECT + +public: + ///Constructor + ShapeDetails(QWidget *parent = 0) : QWidget(parent) {} + ///Constructor + virtual ~ShapeDetails() {} + + ///Write out the XML definition for this shape + virtual QString writeXML() const = 0; + + /// Get the id string + QString getShapeID() const + { + return m_idvalue; + } + + ///Create a new length units box + static QComboBox* createLengthUnitsCombo(); + // Units enum + enum Unit { millimetre = 0, centimetre = 1, metre = 2 }; + // Convert a string value from the given unit to metres + static QString convertToMetres(const QString & value, Unit start_unit); + +protected: + /// ID string of this object + QString m_idvalue; + +}; + +/** + * A widget to define a sphere + */ +class SphereDetails : public ShapeDetails +{ + Q_OBJECT + +private: + /// The number of objects that currently exist + static int g_nspheres; + +public: + ///Default constructor + SphereDetails(QWidget *parent = 0); + + ///Default destructor + ~SphereDetails() { --g_nspheres; } + + //Write the XML definition of a sphere + QString writeXML() const; + +private: + /// Line edit for radius value + QLineEdit *m_radius_box; + /// Radius unit choice + QComboBox *m_runits; + /// Centre point group box + PointGroupBox *m_centre; +}; + +/** + * A widget to define a cylinder + */ +class CylinderDetails : public ShapeDetails +{ + Q_OBJECT + +private: + /// The number of objects that currently exist + static int g_ncylinders; + +public: + ///Default constructor + CylinderDetails(QWidget *parent = 0); + + ///Default destructor + ~CylinderDetails() { --g_ncylinders; } + + //Write the XML definition of a sphere + QString writeXML() const; + +private: + /// Line edits to enter values + QLineEdit *m_radius_box, *m_height_box; + //Unit choice boxes + QComboBox *m_runits, *m_hunits; + /// Centre and axis point boxes + PointGroupBox *m_lower_centre, *m_axis; +}; + +} +} + +#endif // MANTIDQT_CUSTOMDIALOGS_SAMPLESHAPEHELPERS_H_ diff --git a/Code/qtiplot/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp b/Code/qtiplot/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0aecd5a31f14ae6e830a31fb0d62a2cc3528d9fe --- /dev/null +++ b/Code/qtiplot/MantidQt/CustomDialogs/src/CreateSampleShapeDialog.cpp @@ -0,0 +1,339 @@ +//--------------------------- +// Includes +//-------------------------- +#include "MantidQtCustomDialogs/CreateSampleShapeDialog.h" +#include "MantidQtAPI/AlgorithmInputHistory.h" +#include "MantidQtCustomDialogs/SampleShapeHelpers.h" + +#include <QMenu> +#include <QLabel> +#include <QLineEdit> +#include <QComboBox> + +#include <QMessageBox> +#include <iostream> + +//Add this class to the list of specialised dialogs in this namespace +namespace MantidQt +{ +namespace CustomDialogs +{ + DECLARE_DIALOG(CreateSampleShapeDialog); +} +} + +// Just to save writing this everywhere +using namespace MantidQt::CustomDialogs; + +//--------------------------------------- +// Public member functions +//--------------------------------------- +/** + * Constructor + */ +CreateSampleShapeDialog::CreateSampleShapeDialog(QWidget *parent) : + AlgorithmDialog(parent), m_setup_functions(), m_details_map() +{ +} + +/** + * Destructor + */ +CreateSampleShapeDialog::~CreateSampleShapeDialog() +{ + QMutableMapIterator<BinaryTreeWidgetItem*, ShapeDetails*> itr(m_details_map); + while( itr.hasNext() ) { + itr.next(); + ShapeDetails* obj = itr.value(); + itr.remove(); + delete obj; + } +} + +/** + * Set up the dialog + */ +void CreateSampleShapeDialog::initLayout() +{ + //The main setup function + m_uiForm.setupUi(this); + + //Setup the function pointer map + m_setup_functions.clear(); + m_setup_functions["sphere"] = &CreateSampleShapeDialog::setupSphereDetails; + m_setup_functions["cylinder"] = &CreateSampleShapeDialog::setupCylinderDetails; + + //The binary tree + m_shapeTree = new BinaryTreeWidget(this); + m_shapeTree->setColumnCount(1); + m_shapeTree->setHeaderLabel(""); + m_shapeTree->setContextMenuPolicy(Qt::CustomContextMenu); + m_shapeTree->insertTopLevelItem(0, new BinaryTreeWidgetItem(QStringList("complete-shape"))); + m_shapeTree->setSelectionBehavior(QAbstractItemView::SelectItems); + connect(m_shapeTree, SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(handleTreeContextMenuRequest(const QPoint &))); + connect(m_shapeTree, SIGNAL(itemSelectionChanged()), this, SLOT(setupDetailsBox())); + + m_uiForm.shape_box->layout()->addWidget(m_shapeTree); +} + +/** + * Retrieve the input from the dialog + */ +void CreateSampleShapeDialog::parseInput() +{ + BinaryTreeWidgetItem* root_item = m_shapeTree->root(); + m_shapeTree->traverseByPreorder(root_item); + +} + +/** + * This slot is called when a context menu is requested inside the tree widget + */ +void CreateSampleShapeDialog::handleTreeContextMenuRequest(const QPoint & pos) +{ + QMenu *context_menu = new QMenu(m_shapeTree); + //pos is in widget coordinates + QTreeWidgetItem *item = m_shapeTree->itemAt(pos); + if( !item ) return; + + QMenu *submenu = new QMenu("Add child shape"); + QStringList shapes = m_setup_functions.keys(); + QStringListIterator itr(shapes); + while( itr.hasNext() ) + { + submenu->addAction(new QAction(itr.next(), submenu)); + } + + connect(submenu, SIGNAL(triggered(QAction*)), this, SLOT(addChildShape(QAction*))); + + context_menu->addMenu(submenu); + context_menu->popup(QCursor::pos()); +} + +/** + * Add a new child shape + * @param shape The action that emitted the signal + */ +void CreateSampleShapeDialog::addChildShape(QAction *shape) +{ + //Get the selected item + BinaryTreeWidgetItem *parent = dynamic_cast<BinaryTreeWidgetItem*>(m_shapeTree->selectedItems()[0]); + if( parent->childCount() == 2 ) return; + + BinaryTreeWidgetItem *child = new BinaryTreeWidgetItem(QStringList(shape->text())); + //Bit-wise AND with negated value of Qt::ItemIsEditable i.e. disable editing + child->setFlags(parent->flags() & ~Qt::ItemIsEditable); + parent->addChildItem(child); + + //Reset properites of the parent to reflect the fact that it is not a primitive shape + QFont font = parent->font(0); + font.setBold(true); + parent->setFont(0, font); + parent->setData(0, Qt::DisplayRole, "intersection"); + parent->setData(0, Qt::UserRole, 0); + parent->setFlags(parent->flags() | Qt::ItemIsEditable); + + m_shapeTree->setCurrentItem(child); + m_shapeTree->expandAll(); +} + +/** + * Setup the layout for the details box based upon the item given + */ +void CreateSampleShapeDialog::setupDetailsBox() +{ + QList<QTreeWidgetItem*> selection = m_shapeTree->selectedItems(); + if( selection.isEmpty() ) return; + + // Remove the current widget if one exists in the scroll area + if( m_uiForm.details_scroll->widget() ) m_uiForm.details_scroll->takeWidget(); + + BinaryTreeWidgetItem *item = dynamic_cast<BinaryTreeWidgetItem*>(selection[0]); + QString shapename = item->text(0); + if( m_setup_functions.contains(shapename) ) + { + ShapeDetails *obj = NULL; + if( m_details_map.contains(item) ) + { + obj = m_details_map.value(item); + } + else + { + // MemFuncGetter is a typedef for a function pointer + MemFuncGetter details_func = m_setup_functions.value(shapename); + // The '->*' operator has low precedence, hence the need for brackets + obj = (this->*details_func)(); + m_details_map.insert(item, obj); + } + //Set it as the currently displayed widget + m_uiForm.details_scroll->setWidget(obj); + } + +} + +//--------------------------------------------- +// Details tab set up functions +//-------------------------------------------- +/** + * Setup the details box for a sphere + * @param item The sphere item in the list + * @return A pointer to the details object + */ +ShapeDetails* CreateSampleShapeDialog::setupSphereDetails() const +{ + return new SphereDetails; +} + +/** + * Setup the details box for a cylinder + * @param item The sphere item in the list + */ +ShapeDetails* CreateSampleShapeDialog::setupCylinderDetails() const +{ + return new CylinderDetails; +} + + +//================================================================= +//================================================================= + +//------------------------------------------------ +// BinaryTreeWidgetItem +//------------------------------------------------ +/** + * Default constructor + * @param type The type of the item + */ +BinaryTreeWidgetItem::BinaryTreeWidgetItem(int type) + : QTreeWidgetItem(type), m_left_index(0), m_right_index(1) +{ +} + +/** + * Construct an item with a string list of column texts to add + * @param A list of strings to appear as the column texts + * @param type Qt or User defined + */ +BinaryTreeWidgetItem::BinaryTreeWidgetItem(const QStringList & strings, int type) + : QTreeWidgetItem(strings, type), m_left_index(0), m_right_index(1) +{ +} + +/** + * Add a child item. This will only succeed if there are fewer than 2 children currently + */ +bool BinaryTreeWidgetItem::addChildItem(BinaryTreeWidgetItem* child) +{ + if( childCount() >= 2 ) return false; + + // Call sub-class function + this->addChild(child); + return true; +} + +/** + * A pointer to the left child. It can be NULL + */ +BinaryTreeWidgetItem* BinaryTreeWidgetItem::leftChild() const +{ + return dynamic_cast<BinaryTreeWidgetItem*>(this->child(m_left_index)); +} + +/** + * A pointer to the right child. It can be NULL + */ +BinaryTreeWidgetItem* BinaryTreeWidgetItem::rightChild() const +{ + return dynamic_cast<BinaryTreeWidgetItem*>(this->child(m_right_index)); +} + + + +//------------------------------------------------ +// BinaryTreeWidget +//------------------------------------------------ + +/** + * Default constructor + */ +BinaryTreeWidget::BinaryTreeWidget(QWidget *parent) : QTreeWidget(parent) +{ + ComboBoxDelegate *delegate = new ComboBoxDelegate(this); + setItemDelegate(delegate); +} + +/** + * Gets the root item for the tree + */ +BinaryTreeWidgetItem* BinaryTreeWidget::root() const +{ + return dynamic_cast<BinaryTreeWidgetItem*>(invisibleRootItem()->child(0)); +} + +/** + * Recurse through the tree in a pre-order manner + */ +void BinaryTreeWidget::traverseByPreorder(BinaryTreeWidgetItem* node) +{ + // For the time begin just print the string that we get + QString itext = node->text(0); + if( itext.startsWith("i") ) itext = "x"; + else if( itext.startsWith("u") ) itext = "+"; + else if( itext.startsWith("d") ) itext = "-"; + else {} + + std::cerr << itext.toStdString() << " "; + if( node->leftChild() ) traverseByPreorder(node->leftChild()); + if( node->rightChild() ) traverseByPreorder(node->rightChild()); +} + + +//------------------------------------------------ +// ComboBoxDelegate +//------------------------------------------------ +/// A user defined data type +int ComboBoxDelegate::g_idata_role = 100; + +/** + * Default constructor + */ +ComboBoxDelegate::ComboBoxDelegate(QWidget *parent) : QItemDelegate(parent) +{ +} + +QWidget *ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, + const QModelIndex &) const +{ + QComboBox *editor = new QComboBox(parent); + editor->addItem("union"); + editor->addItem("intersection"); + editor->addItem("difference"); + + return editor; +} + +void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + int value = index.model()->data(index, g_idata_role).toInt(); + + QComboBox *combo_box = qobject_cast<QComboBox*>(editor); + combo_box->setCurrentIndex(value); +} + +void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const +{ + QComboBox *combo_box = static_cast<QComboBox*>(editor); + int boxitem = combo_box->currentIndex(); + QString value = combo_box->itemText(boxitem); + + model->setData(index, boxitem, g_idata_role); + model->setData(index, value, Qt::DisplayRole); +} + +void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, + const QModelIndex &) const +{ + editor->setGeometry(option.rect); +} diff --git a/Code/qtiplot/MantidQt/CustomDialogs/src/SampleShapeHelpers.cpp b/Code/qtiplot/MantidQt/CustomDialogs/src/SampleShapeHelpers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2e2433cb4cdf691801c1823c8e3a1e1b0b3502a --- /dev/null +++ b/Code/qtiplot/MantidQt/CustomDialogs/src/SampleShapeHelpers.cpp @@ -0,0 +1,289 @@ +//------------------------------------------ +// Includes +//----------------------------------------- +#include "MantidQtCustomDialogs/SampleShapeHelpers.h" + +#include <QLabel> +#include <QLineEdit> +#include <QComboBox> +#include <QGridLayout> +#include <QRadioButton> + +using namespace MantidQt::CustomDialogs; + +//-----------------------------------------// +// PointGroupBox helper class +//----------------------------------------// +PointGroupBox::PointGroupBox(QWidget* parent) : QGroupBox(parent), m_icoord(0) +{ + QGridLayout *grid = new QGridLayout; + + // The line edit fields + m_midx = new QLineEdit; + m_midy = new QLineEdit; + m_midz = new QLineEdit; + + m_xunits = ShapeDetails::createLengthUnitsCombo(); + m_yunits = ShapeDetails::createLengthUnitsCombo(); + m_zunits = ShapeDetails::createLengthUnitsCombo(); + + // Radio selections + m_cartesian = new QRadioButton("Cartesian"); + m_cartesian->setChecked(true); + m_spherical = new QRadioButton("Spherical"); + + connect(m_cartesian, SIGNAL(clicked(bool)), this, SLOT(changeToCartesian())); + connect(m_spherical, SIGNAL(clicked(bool)), this, SLOT(changeToSpherical())); + + int row(0); + grid->addWidget(m_cartesian, row, 0, 1, 2); + grid->addWidget(m_spherical, row, 2, 1, 2); + ++row; + //labels + m_xlabel = new QLabel("x: "); + m_ylabel = new QLabel("y: "); + m_zlabel = new QLabel("z: "); + + // x + grid->addWidget(m_xlabel, row, 0, Qt::AlignRight); + grid->addWidget(m_midx, row, 1); + grid->addWidget(m_xunits, row, 2); + ++row; + // y + grid->addWidget(m_ylabel, row, 0);//, Qt::AlignRight); + grid->addWidget(m_midy, row, 1); + grid->addWidget(m_yunits, row, 2); + ++row; + // z + grid->addWidget(m_zlabel, row, 0, Qt::AlignRight); + grid->addWidget(m_midz, row, 1); + grid->addWidget(m_zunits, row, 2); + + setLayout(grid); +} + +// Switch to cartesian coordinates +void PointGroupBox::changeToCartesian() +{ + if( m_icoord == 0 ) return; + + m_xlabel->setText("x: "); + m_ylabel->setText("y: "); + m_zlabel->setText("z: "); + + m_yunits->setEnabled(true); + m_zunits->setEnabled(true); + + m_icoord = 0; +} + +// Switch to spherical coordinates +void PointGroupBox::changeToSpherical() +{ + if( m_icoord == 1 ) return; + + m_xlabel->setText("r: "); + m_ylabel->setText("theta: "); + m_zlabel->setText("phi: "); + + //Units are in degrees for theta and phi + m_yunits->setEnabled(false); + m_zunits->setEnabled(false); + + m_icoord = 1; +} + +/** + * Write the element tag for a 3D point. + * elem_name The name of the element + */ +QString PointGroupBox::write3DElement(const QString & elem_name) const +{ + QString valx("0.0"), valy("0.0"), valz("0.0"); + if( !m_midx->text().isEmpty() ) + { + valx = ShapeDetails::convertToMetres(m_midx->text(), ShapeDetails::Unit(m_xunits->currentIndex())); + } + if( !m_midy->text().isEmpty() ) + { + if( m_icoord == 0 ) + { + valy = ShapeDetails::convertToMetres(m_midy->text(), ShapeDetails::Unit(m_yunits->currentIndex())); + } + else + { + valy = m_midy->text(); + } + } + if( !m_midz->text().isEmpty() ) + { + if( m_icoord == 0 ) + { + valz = ShapeDetails::convertToMetres(m_midz->text(), ShapeDetails::Unit(m_zunits->currentIndex())); + } + else + { + valz = m_midz->text(); + } + } + QString tag; + if( m_icoord == 0 ) + { + tag = "<" + elem_name + " x=\"" + valx + "\" y=\"" + valy + "\" z= \"" + valz + "\" />\n"; + } + else + { + tag = "<" + elem_name + " r=\"" + valx + "\" t=\"" + valy + "\" p= \"" + valz + "\" />\n"; + } + return tag; +} + +//----------------------------------------------------// +// Base ShapeDetails +//---------------------------------------------------// +/** + * Create a QComboBox filled with length units (static) + */ +QComboBox* ShapeDetails::createLengthUnitsCombo() +{ + QComboBox *units = new QComboBox; + QStringList unit_labels("mm"); + unit_labels << "cm" << "m"; + units->addItems(unit_labels); + return units; +} + +/** Convert a string value from the given unit to metres (static) + * @param value The value to change + * @param start_unit Initial unit + * @returns A new string value in metres + */ +QString ShapeDetails::convertToMetres(const QString & value, Unit start_unit) +{ + QString converted; + switch( start_unit ) + { + case ShapeDetails::centimetre: + converted = QString::number(value.toDouble() / 100.0); + break; + case ShapeDetails::millimetre: + converted = QString::number(value.toDouble() / 1000.0); + break; + default: + converted = value; + } + return converted; +} + +//--------------------------------------------// +// Sphere +//--------------------------------------------// +/// Static counter +int SphereDetails::g_nspheres = 0; + +/// Default constructor +SphereDetails::SphereDetails(QWidget *parent) : ShapeDetails(parent) +{ + //Update number of sphere objects and the set the ID of this one + ++g_nspheres; + m_idvalue = "sphere-" + QString::number(g_nspheres); + + QVBoxLayout *main_layout = new QVBoxLayout(this); + //radius + m_radius_box = new QLineEdit; + m_runits = createLengthUnitsCombo(); + QHBoxLayout *rad_layout = new QHBoxLayout; + rad_layout->addWidget(new QLabel("Radius: ")); + rad_layout->addWidget(m_radius_box); + rad_layout->addWidget(m_runits); + + m_centre = new PointGroupBox; + m_centre->setTitle("Centre"); + + main_layout->addLayout(rad_layout); + main_layout->addWidget(m_centre); +} + +/** + * Write the XML definition + */ +QString SphereDetails::writeXML() const +{ + QString valr("0.0"); + if( !m_radius_box->text().isEmpty() ) + { + valr = convertToMetres(m_radius_box->text(), ShapeDetails::Unit(m_runits->currentIndex())); + } + QString xmldef = + "<sphere id=\"" + m_idvalue + "\" />\n" + m_centre->write3DElement("centre") + + "<radius val=\"" + valr + "\" />\n" + "</sphere>\n"; + return xmldef; +} + +//-----------------------------------------// +// Cylinder +//-----------------------------------------// +/// Static counter +int CylinderDetails::g_ncylinders = 0; + +/// Default constructor +CylinderDetails::CylinderDetails(QWidget *parent) : ShapeDetails(parent) +{ + /// Update number of sphere objects and the set the ID of this one + ++g_ncylinders; + m_idvalue = "cylinder-" + QString::number(g_ncylinders); + + QVBoxLayout *main_layout = new QVBoxLayout(this); + //radius + m_radius_box = new QLineEdit; + m_runits = createLengthUnitsCombo(); + QHBoxLayout *rad_layout = new QHBoxLayout; + rad_layout->addWidget(new QLabel("Radius: ")); + rad_layout->addWidget(m_radius_box); + rad_layout->addWidget(m_runits); + + //height + m_height_box = new QLineEdit; + m_hunits = createLengthUnitsCombo(); + QHBoxLayout *hgt_layout = new QHBoxLayout; + hgt_layout->addWidget(new QLabel("Height: ")); + hgt_layout->addWidget(m_height_box); + hgt_layout->addWidget(m_hunits); + + //Point boxes + m_lower_centre = new PointGroupBox; + m_lower_centre->setTitle("Bottom Base Centre"); + + m_axis = new PointGroupBox; + m_axis->setTitle("Axis"); + + main_layout->addLayout(rad_layout); + main_layout->addLayout(hgt_layout); + main_layout->addWidget(m_lower_centre); + main_layout->addWidget(m_axis); +} + +/** + * Write the XML definition + */ +QString CylinderDetails::writeXML() const +{ + QString valr("0.0"), valh("0.0"); + if( !m_radius_box->text().isEmpty() ) + { + valr = convertToMetres(m_radius_box->text(), ShapeDetails::Unit(m_runits->currentIndex())); + } + if( !m_height_box->text().isEmpty() ) + { + valh = convertToMetres(m_height_box->text(), ShapeDetails::Unit(m_hunits->currentIndex())); + } + QString xmldef = + "<cylinder id=\"" + m_idvalue + "\" />\n" + "<radius val=\"" + valr + "\" />\n" + "<height val=\"" + valh + "\" />\n" + + m_lower_centre->write3DElement("centre-of-bottom-base") + + m_axis->write3DElement("axis") + + "</cylinder>\n"; + return xmldef; +}