Newer
Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
Gigg, Martyn Anthony
committed
//---------------------------
// Includes
//--------------------------
#include "MantidQtWidgets/Plugins/AlgorithmDialogs/CreateSampleShapeDialog.h"
#include "MantidQtWidgets/Common/AlgorithmInputHistory.h"
#include "MantidQtWidgets/Plugins/AlgorithmDialogs/MantidGLWidget.h"
#include "MantidQtWidgets/Plugins/AlgorithmDialogs/SampleShapeHelpers.h"
Gigg, Martyn Anthony
committed
#include "MantidGeometry/Objects/CSGObject.h"
#include "MantidGeometry/Objects/ShapeFactory.h"
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
#include <QLabel>
#include <QLineEdit>
Gigg, Martyn Anthony
committed
#include <QMessageBox>
Gigg, Martyn Anthony
committed
#include <QShortcut>
// Add this class to the list of specialised dialogs in this namespace
namespace MantidQt {
namespace CustomDialogs {
DECLARE_DIALOG(CreateSampleShapeDialog)
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
// Just to save writing this everywhere
Gigg, Martyn Anthony
committed
using namespace MantidQt::CustomDialogs;
//---------------------------------------
// Public member functions
//---------------------------------------
/**
* Constructor
*/
CreateSampleShapeDialog::CreateSampleShapeDialog(QWidget *parent)
: AlgorithmDialog(parent), m_shapeTree(nullptr), m_setup_map(),
m_details_map(), m_ops_map() {
Gigg, Martyn Anthony
committed
m_object_viewer = new MantidGLWidget;
Gigg, Martyn Anthony
committed
}
/**
* Destructor
*/
CreateSampleShapeDialog::~CreateSampleShapeDialog() {
// Delete the objects created. The shape details static counter is decremented
// when
Gigg, Martyn Anthony
committed
// its destructor is called
QMutableMapIterator<BinaryTreeWidgetItem *, ShapeDetails *> itr(
m_details_map);
while (itr.hasNext()) {
Gigg, Martyn Anthony
committed
itr.next();
ShapeDetails *obj = itr.value();
Gigg, Martyn Anthony
committed
itr.remove();
delete obj;
Gigg, Martyn Anthony
committed
}
QMutableMapIterator<BinaryTreeWidgetItem *, Operation *> itrb(m_ops_map);
while (itrb.hasNext()) {
Gigg, Martyn Anthony
committed
itrb.next();
Operation *obj = itrb.value();
itrb.remove();
delete obj;
}
Gigg, Martyn Anthony
committed
}
/**
* Set up the dialog
*/
void CreateSampleShapeDialog::initLayout() {
// The main setup function
Gigg, Martyn Anthony
committed
m_uiForm.setupUi(this);
// Create the map of instantiators. The keys defined here are used to generate
// the shape
Gigg, Martyn Anthony
committed
// menu items
Gigg, Martyn Anthony
committed
m_setup_map.clear();
m_setup_map["sphere"] = new ShapeDetailsInstantiator<SphereDetails>;
m_setup_map["cylinder"] = new ShapeDetailsInstantiator<CylinderDetails>;
m_setup_map["infinite cylinder"] =
new ShapeDetailsInstantiator<InfiniteCylinderDetails>();
m_setup_map["cylinder ring slice"] =
new ShapeDetailsInstantiator<SliceOfCylinderRingDetails>();
// m_setup_map["cone"] = new ShapeDetailsInstantiator<ConeDetails>();
// m_setup_map["infinite cone"] = new
// ShapeDetailsInstantiator<InfiniteConeDetails>();
m_setup_map["infinite plane"] =
new ShapeDetailsInstantiator<InfinitePlaneDetails>();
Gigg, Martyn Anthony
committed
m_setup_map["cuboid"] = new ShapeDetailsInstantiator<CuboidDetails>();
m_setup_map["hexahedron"] = new ShapeDetailsInstantiator<HexahedronDetails>();
Gigg, Martyn Anthony
committed
// m_setup_map["torus"] = new ShapeDetailsInstantiator<TorusDetails>();
Gigg, Martyn Anthony
committed
// The binary tree
Gigg, Martyn Anthony
committed
m_shapeTree = new BinaryTreeWidget(this);
m_shapeTree->setColumnCount(1);
m_shapeTree->setHeaderLabel("");
m_shapeTree->setContextMenuPolicy(Qt::CustomContextMenu);
m_shapeTree->setSelectionBehavior(QAbstractItemView::SelectItems);
Gigg, Martyn Anthony
committed
m_shapeTree->setSelectionMode(QAbstractItemView::SingleSelection);
connect(m_shapeTree, SIGNAL(customContextMenuRequested(const QPoint &)), this,
SLOT(handleTreeContextMenuRequest(const QPoint &)));
connect(m_shapeTree, SIGNAL(itemSelectionChanged()), this,
SLOT(setupDetailsBox()));
connect(m_shapeTree, SIGNAL(treeDataChange(BinaryTreeWidgetItem *, int)),
this, SLOT(changeTreeData(BinaryTreeWidgetItem *, int)));
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
QPushButton *view_shape_btn = new QPushButton("Update 3D view");
connect(view_shape_btn, SIGNAL(clicked()), this, SLOT(update3DView()));
Gigg, Martyn Anthony
committed
QHBoxLayout *bottom = new QHBoxLayout;
Gigg, Martyn Anthony
committed
bottom->addWidget(view_shape_btn);
Gigg, Martyn Anthony
committed
bottom->addStretch();
// Shape box layout
Gigg, Martyn Anthony
committed
QVBoxLayout *shape_box_layout = new QVBoxLayout;
shape_box_layout->addWidget(m_shapeTree);
shape_box_layout->addLayout(bottom);
m_uiForm.shape_box->setLayout(shape_box_layout);
Gigg, Martyn Anthony
committed
QShortcut *delete_key = new QShortcut(QKeySequence(Qt::Key_Delete), this);
connect(delete_key, SIGNAL(activated()), this, SLOT(handleDeleteRequest()));
Gigg, Martyn Anthony
committed
QVBoxLayout *view_box_layout = new QVBoxLayout;
view_box_layout->addWidget(m_object_viewer);
m_uiForm.view_box->setLayout(view_box_layout);
Gigg, Martyn Anthony
committed
// Check input workspace property. If there are available workspaces then
// these have been set as allowed values
std::vector<std::string> workspaces =
getAlgorithmProperty("InputWorkspace")->allowedValues();
for (std::vector<std::string>::const_iterator itr = workspaces.begin();
itr != workspaces.end(); ++itr) {
Gigg, Martyn Anthony
committed
m_uiForm.wksp_opt->addItem(QString::fromStdString(*itr));
}
Gigg, Martyn Anthony
committed
tie(m_uiForm.wksp_opt, "InputWorkspace", m_uiForm.bottomlayout);
Gigg, Martyn Anthony
committed
// Connect the help button
Gigg, Martyn Anthony
committed
connect(m_uiForm.helpButton, SIGNAL(clicked()), this, SLOT(helpClicked()));
Gigg, Martyn Anthony
committed
}
/**
* Retrieve the input from the dialog
*/
void CreateSampleShapeDialog::parseInput() {
Gigg, Martyn Anthony
committed
QString xml = constructShapeXML();
if (m_shapeTree->topLevelItemCount() > 0 && xml.isEmpty()) {
QMessageBox::information(this, "CreateSampleShapeDialog",
"An error occurred while parsing the shape tree.\n"
"Please check that each node has two children and "
"the lowest elements are primitive shapes.");
Gigg, Martyn Anthony
committed
return;
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
storePropertyValue("ShapeXML", xml);
Gigg, Martyn Anthony
committed
// Get workspace value
Gigg, Martyn Anthony
committed
storePropertyValue("InputWorkspace", m_uiForm.wksp_opt->currentText());
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Update the 3D widget with a new object
Gigg, Martyn Anthony
committed
*/
void CreateSampleShapeDialog::update3DView() {
Gigg, Martyn Anthony
committed
std::string shapexml = constructShapeXML().toStdString();
if (m_shapeTree->topLevelItemCount() > 0 && shapexml.empty()) {
QMessageBox::information(this, "CreateSampleShapeDialog",
"An error occurred while parsing the shape tree.\n"
"Please check that each node has two children and "
"the lowest elements are primitive shapes.");
Gigg, Martyn Anthony
committed
return;
}
// Testing a predefined complex shape PLEASE LEAVE FOR THE MOMENT
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// std::string shapexml = "<cuboid id=\"cuboid_1\" >\n"
// "<left-front-bottom-point x=\"-0.02\" y=\"-0.02\" z= \"0.0\" />\n"
// "<left-front-top-point x=\"-0.02\" y=\"0.05\" z= \"0.0\" />\n"
// "<left-back-bottom-point x=\"-0.02\" y=\"-0.02\" z= \"0.07\" />\n"
// "<right-front-bottom-point x=\"0.05\" y=\"-0.02\" z= \"0.0\" />\n"
// "</cuboid>\n"
// "<infinite-cylinder id=\"infcyl_1\" >"
// "<radius val=\"0.025\" />"
// "<centre x=\"0.015\" y=\"0.015\" z= \"0.07\" />"
// "<axis x=\"0.0\" y=\"0.0\" z= \"-0.001\" />"
// "</infinite-cylinder>\n"
// "<sphere id=\"sphere_1\">"
// "<centre x=\"0.015\" y=\"0.015\" z= \"0.035\" />"
// "<radius val=\"0.04\" />"
// "</sphere>\n"
// "<infinite-cylinder id=\"infcyl_3\" >"
// "<radius val=\"0.025\" />"
// "<centre x=\"0.015\" y=\"-0.02\" z= \"0.035\" />"
// "<axis x=\"0.0\" y=\"0.001\" z= \"0.0\" />"
// "</infinite-cylinder>\n"
// "<infinite-cylinder id=\"infcyl_2\" >"
// "<radius val=\"0.025\" />"
// "<centre x=\"-0.02\" y=\"0.015\" z= \"0.035\" />"
// "<axis x=\"0.001\" y=\"0.0\" z= \"0.0\" />"
// "</infinite-cylinder>\n"
// "<algebra val=\"((cuboid_1 sphere_1) (#
// (infcyl_1:(infcyl_2:infcyl_3))))\" />\n";
Gigg, Martyn Anthony
committed
Mantid::Geometry::ShapeFactory sFactory;
auto shape_sptr = sFactory.createShape(shapexml);
// std::cerr << "\n--------- XML String -----------\n" << shapexml <<
// "\n---------------------\n";
if (shape_sptr == boost::shared_ptr<Mantid::Geometry::CSGObject>())
return;
try {
Gigg, Martyn Anthony
committed
shape_sptr->initDraw();
} catch (...) {
QMessageBox::information(
this, "Create sample shape",
QString(
"An error occurred while attempting to initialize the shape.\n") +
"Please check that all objects intersect each other.");
Gigg, Martyn Anthony
committed
return;
}
m_object_viewer->setDisplayObject(shape_sptr);
}
Gigg, Martyn Anthony
committed
/**
* This slot is called when a context menu is requested inside the tree widget
Janik Zikovsky
committed
* @param pos :: The position of the mouse pointer when the menu was requested
Gigg, Martyn Anthony
committed
*/
void CreateSampleShapeDialog::handleTreeContextMenuRequest(const QPoint &pos) {
Gigg, Martyn Anthony
committed
QMenu *context_menu = new QMenu(m_shapeTree);
Gigg, Martyn Anthony
committed
QTreeWidgetItem *item = m_shapeTree->itemAt(pos);
QString op_text = "Insert child operation";
bool is_shape(false);
Gigg, Martyn Anthony
committed
QString displayText = item->text(0);
if (!displayText.startsWith("inter") && !displayText.startsWith("uni") &&
!displayText.startsWith("diff")) {
Gigg, Martyn Anthony
committed
is_shape = true;
// For a shape we need the option to mark it as a complement shape
Gigg, Martyn Anthony
committed
QAction *complement = new QAction("Complement", context_menu);
complement->setCheckable(true);
bool isChecked =
m_details_map.value(getSelectedItem())->getComplementFlag();
Gigg, Martyn Anthony
committed
complement->setChecked(isChecked);
connect(complement, SIGNAL(toggled(bool)), this,
SLOT(toggleShapeComplement(bool)));
Gigg, Martyn Anthony
committed
context_menu->addAction(complement);
context_menu->addSeparator();
op_text = "Insert operation above";
}
}
Gigg, Martyn Anthony
committed
QMenu *add_op = new QMenu(op_text);
Gigg, Martyn Anthony
committed
add_op->addAction(new QAction("intersection", add_op));
add_op->addAction(new QAction("union", add_op));
add_op->addAction(new QAction("difference", add_op));
connect(add_op, SIGNAL(triggered(QAction *)), this,
SLOT(addOperation(QAction *)));
Gigg, Martyn Anthony
committed
context_menu->addMenu(add_op);
if (!is_shape || m_shapeTree->topLevelItemCount() == 0) {
Gigg, Martyn Anthony
committed
QMenu *submenu = new QMenu("Insert child shape");
QStringList shapes = m_setup_map.keys();
QStringListIterator itr(shapes);
while (itr.hasNext()) {
Gigg, Martyn Anthony
committed
submenu->addAction(new QAction(itr.next(), submenu));
}
connect(submenu, SIGNAL(triggered(QAction *)), this,
SLOT(addShape(QAction *)));
Gigg, Martyn Anthony
committed
context_menu->addMenu(submenu);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
context_menu->addSeparator();
Gigg, Martyn Anthony
committed
QAction *remove = new QAction("Delete", context_menu);
connect(remove, SIGNAL(triggered()), this, SLOT(handleDeleteRequest()));
context_menu->addAction(remove);
Gigg, Martyn Anthony
committed
context_menu->popup(QCursor::pos());
}
void CreateSampleShapeDialog::toggleShapeComplement(bool state) {
Gigg, Martyn Anthony
committed
BinaryTreeWidgetItem *selected = getSelectedItem();
if (m_details_map.contains(selected)) {
Gigg, Martyn Anthony
committed
m_details_map.value(selected)->setComplementFlag(state);
}
Gigg, Martyn Anthony
committed
selected->setText(0, QString("# ") + selected->text(0));
Gigg, Martyn Anthony
committed
selected->setText(0, selected->text(0).section('#', 1).trimmed());
}
}
void CreateSampleShapeDialog::changeTreeData(BinaryTreeWidgetItem *item,
int data) {
if (m_ops_map.contains(item)) {
Gigg, Martyn Anthony
committed
m_ops_map.value(item)->binaryop = data;
}
}
BinaryTreeWidgetItem *CreateSampleShapeDialog::getSelectedItem() {
if (!m_shapeTree->selectedItems().isEmpty()) {
Gigg, Martyn Anthony
committed
/// Single selections are the only ones allowed
return dynamic_cast<BinaryTreeWidgetItem *>(
m_shapeTree->selectedItems()[0]);
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
// Check if tree is empty
if (m_shapeTree->topLevelItemCount() == 0) {
Gigg, Martyn Anthony
committed
// Give back the invisible root item
return m_shapeTree->root();
} else {
QMessageBox::information(this, "CreateSampleShape",
"Please select an item in the list as a parent.");
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Add a new child shape
Janik Zikovsky
committed
* @param shape :: The action that emitted the signal
Gigg, Martyn Anthony
committed
*/
void CreateSampleShapeDialog::addShape(QAction *shape) {
Gigg, Martyn Anthony
committed
// Get the selected item
BinaryTreeWidgetItem *parent = getSelectedItem();
if (parent && parent->childCount() == 2)
return;
Gigg, Martyn Anthony
committed
BinaryTreeWidgetItem *child =
new BinaryTreeWidgetItem(QStringList(shape->text()));
Gigg, Martyn Anthony
committed
child->setFlags(child->flags() & ~Qt::ItemIsEditable);
Gigg, Martyn Anthony
committed
if (m_shapeTree->topLevelItemCount() == 0) {
Gigg, Martyn Anthony
committed
m_shapeTree->insertTopLevelItem(0, child);
} else if (parent) {
Gigg, Martyn Anthony
committed
parent->addChildItem(child);
return;
}
Gigg, Martyn Anthony
committed
// This calls setupDetails
m_shapeTree->setCurrentItem(child);
m_shapeTree->expandAll();
}
Gigg, Martyn Anthony
committed
* Add operation node based on menu action
*/
void CreateSampleShapeDialog::addOperation(QAction *opt) {
// Get the selected item
Gigg, Martyn Anthony
committed
BinaryTreeWidgetItem *selected = getSelectedItem();
if (!selected)
return;
if (selected && selected->childCount() == 2)
return;
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
BinaryTreeWidgetItem *operation = new BinaryTreeWidgetItem;
QFont font = operation->font(0);
Gigg, Martyn Anthony
committed
font.setBold(true);
Gigg, Martyn Anthony
committed
operation->setFont(0, font);
operation->setData(0, Qt::DisplayRole, opt->text());
Gigg, Martyn Anthony
committed
int opcode(0);
if (opt->text().startsWith("u"))
opcode = 1;
else if (opt->text().startsWith("d"))
opcode = 2;
else
opcode = 0;
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
operation->setData(0, Qt::UserRole, opcode);
operation->setFlags(operation->flags() | Qt::ItemIsEditable);
if (m_shapeTree->topLevelItemCount() == 0) {
Gigg, Martyn Anthony
committed
m_shapeTree->insertTopLevelItem(0, operation);
} else {
if (m_ops_map.contains(selected)) {
Gigg, Martyn Anthony
committed
selected->addChildItem(operation);
} else if (selected->parent()) {
int index = selected->parent()->indexOfChild(selected);
Gigg, Martyn Anthony
committed
selected->parent()->insertChild(index, operation);
selected->parent()->removeChild(selected);
operation->addChildItem(selected);
Gigg, Martyn Anthony
committed
m_shapeTree->takeTopLevelItem(m_shapeTree->indexOfTopLevelItem(selected));
m_shapeTree->insertTopLevelItem(0, operation);
operation->addChildItem(selected);
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
m_ops_map.insert(operation, new Operation(opcode));
Gigg, Martyn Anthony
committed
// This calls setupDetails if necessary
Gigg, Martyn Anthony
committed
m_shapeTree->setCurrentItem(operation);
Gigg, Martyn Anthony
committed
m_shapeTree->expandAll();
Gigg, Martyn Anthony
committed
}
/**
* Handle a delete signal
*/
void CreateSampleShapeDialog::handleDeleteRequest() {
Gigg, Martyn Anthony
committed
BinaryTreeWidgetItem *item = getSelectedItem();
if (!item)
return;
Gigg, Martyn Anthony
committed
removeItem(item);
}
/**
* Remove an item and all children from the tree
*/
void CreateSampleShapeDialog::removeItem(BinaryTreeWidgetItem *item) {
if (!item)
return;
// Recursively remove children
if (item->childCount() > 0) {
while (item->childCount() > 0) {
if (item->leftChild())
removeItem(item->leftChild());
if (item->rightChild())
removeItem(item->rightChild());
Gigg, Martyn Anthony
committed
}
}
if (m_details_map.contains(item)) {
Gigg, Martyn Anthony
committed
ShapeDetails *obj = m_details_map.take(item);
delete obj;
} else if (m_ops_map.contains(item)) {
Gigg, Martyn Anthony
committed
Operation *obj = m_ops_map.take(item);
delete obj;
} else
return;
Gigg, Martyn Anthony
committed
if (item->parent()) {
Gigg, Martyn Anthony
committed
item->parent()->removeChild(item);
Gigg, Martyn Anthony
committed
m_shapeTree->takeTopLevelItem(m_shapeTree->indexOfTopLevelItem(item));
}
Gigg, Martyn Anthony
committed
}
/**
* 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;
Gigg, Martyn Anthony
committed
// Remove the current widget if one exists in the scroll area
if (m_uiForm.details_scroll->widget())
m_uiForm.details_scroll->takeWidget();
Gigg, Martyn Anthony
committed
BinaryTreeWidgetItem *item =
dynamic_cast<BinaryTreeWidgetItem *>(selection[0]);
if (!item)
return;
Gigg, Martyn Anthony
committed
QString shapename = item->text(0);
if (m_setup_map.contains(shapename)) {
ShapeDetails *obj = nullptr;
if (m_details_map.contains(item)) {
Gigg, Martyn Anthony
committed
obj = m_details_map.value(item);
Gigg, Martyn Anthony
committed
obj = createDetailsWidget(shapename);
Gigg, Martyn Anthony
committed
m_details_map.insert(item, obj);
}
// Set it as the currently displayed widget
m_uiForm.details_scroll->setWidget(obj);
Gigg, Martyn Anthony
committed
}
}
/**
Gigg, Martyn Anthony
committed
* Create the correct type of details box for the shape
* @param shapename :: The name of the shape for which to create a widget
Gigg, Martyn Anthony
committed
* @return A pointer to the details object
*/
ShapeDetails *
CreateSampleShapeDialog::createDetailsWidget(const QString &shapename) const {
if (m_setup_map.contains(shapename)) {
Gigg, Martyn Anthony
committed
return m_setup_map.value(shapename)->createInstance();
}
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
/**
* Construct the XML from the current tree
*/
QString CreateSampleShapeDialog::constructShapeXML() const {
if (m_shapeTree->topLevelItemCount() == 0 || m_details_map.isEmpty())
return QString();
Gigg, Martyn Anthony
committed
QString shapexml;
// First construct the XML that builds each separately defined shape
QMapIterator<BinaryTreeWidgetItem *, ShapeDetails *> detitr(m_details_map);
while (detitr.hasNext()) {
Gigg, Martyn Anthony
committed
detitr.next();
shapexml += detitr.value()->writeXML() + "\n";
}
QList<BinaryTreeWidgetItem *> postfix_exp;
// Build expression list
Gigg, Martyn Anthony
committed
m_shapeTree->traverseInPostOrder(m_shapeTree->root(), postfix_exp);
QListIterator<BinaryTreeWidgetItem *> expitr(postfix_exp);
Gigg, Martyn Anthony
committed
QStringList inter_results;
while (expitr.hasNext()) {
BinaryTreeWidgetItem *item = expitr.next();
if (m_details_map.contains(item)) {
Gigg, Martyn Anthony
committed
ShapeDetails *shape = m_details_map.value(item);
QString shapeID = shape->getShapeID();
if (shape->getComplementFlag()) {
shapeID = QString("#(") + shapeID + QString(")");
Gigg, Martyn Anthony
committed
}
inter_results.append(shapeID);
} else if (m_ops_map.contains(item)) {
Gigg, Martyn Anthony
committed
int rcount = inter_results.count();
if (inter_results.count() < 2) {
shapexml = "";
break;
Gigg, Martyn Anthony
committed
}
QString left = inter_results.at(rcount - 2);
QString right = inter_results.at(rcount - 1);
QString result = m_ops_map.value(item)->toString(left, right);
// Remove left result and replace the right with the result
inter_results.removeAt(rcount - 2);
// List has now been reduced in size by 1
Gigg, Martyn Anthony
committed
inter_results.replace(rcount - 2, result);
Gigg, Martyn Anthony
committed
shapexml = "";
break;
}
}
Gigg, Martyn Anthony
committed
// Something went wrong if the list hasn't compacted down to one entry
if (inter_results.size() != 1 || shapexml.isEmpty()) {
Gigg, Martyn Anthony
committed
return QString();
}
shapexml += "<algebra val=\"" + inter_results.at(0) + "\" />";
return shapexml;
}
Gigg, Martyn Anthony
committed
//=================================================================
//=================================================================
//------------------------------------------------
// BinaryTreeWidgetItem
//------------------------------------------------
/**
* Default constructor
Janik Zikovsky
committed
* @param type :: The type of the item
Gigg, Martyn Anthony
committed
*/
BinaryTreeWidgetItem::BinaryTreeWidgetItem(int type)
: QTreeWidgetItem(type), m_left_index(0), m_right_index(1) {}
Gigg, Martyn Anthony
committed
/**
* Construct an item with a string list of column texts to add
* @param strings :: A list of strings to appear as the column texts
* @param type :: Qt or User defined
Gigg, Martyn Anthony
committed
*/
BinaryTreeWidgetItem::BinaryTreeWidgetItem(const QStringList &strings, int type)
: QTreeWidgetItem(strings, type), m_left_index(0), m_right_index(1) {}
Gigg, Martyn Anthony
committed
/**
* Add a child item. This will only succeed if there are fewer than 2 children
* currently
Gigg, Martyn Anthony
committed
*/
bool BinaryTreeWidgetItem::addChildItem(BinaryTreeWidgetItem *child) {
bool tooManyChildren = childCount() >= 2;
if (!tooManyChildren)
this->addChild(child);
Gigg, Martyn Anthony
committed
// Call sub-class function
return !tooManyChildren;
Gigg, Martyn Anthony
committed
}
/**
* A pointer to the left child. It can be NULL
*/
BinaryTreeWidgetItem *BinaryTreeWidgetItem::leftChild() const {
return dynamic_cast<BinaryTreeWidgetItem *>(this->child(m_left_index));
Gigg, Martyn Anthony
committed
}
/**
* A pointer to the right child. It can be NULL
*/
BinaryTreeWidgetItem *BinaryTreeWidgetItem::rightChild() const {
return dynamic_cast<BinaryTreeWidgetItem *>(this->child(m_right_index));
Gigg, Martyn Anthony
committed
}
//------------------------------------------------
// BinaryTreeWidget
//------------------------------------------------
/**
* Default constructor
*/
BinaryTreeWidget::BinaryTreeWidget(QWidget *parent) : QTreeWidget(parent) {
Gigg, Martyn Anthony
committed
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));
Gigg, Martyn Anthony
committed
}
/**
* A recursive function that builds an expression from the binary tree by
* traversing it in a post order fashion
Janik Zikovsky
committed
* @param node :: The parent node
* @param expression :: The expression list to build
Gigg, Martyn Anthony
committed
*/
void BinaryTreeWidget::traverseInPostOrder(
BinaryTreeWidgetItem *node, QList<BinaryTreeWidgetItem *> &expression) {
if (!node)
return;
Gigg, Martyn Anthony
committed
// For the time begin just print the string that we get
if (node->leftChild())
traverseInPostOrder(node->leftChild(), expression);
if (node->rightChild())
traverseInPostOrder(node->rightChild(), expression);
Gigg, Martyn Anthony
committed
// Append this to the list
expression.append(node);
Gigg, Martyn Anthony
committed
}
void BinaryTreeWidget::dataChanged(const QModelIndex &topLeft,
const QModelIndex & /*bottomRight*/) {
#else
void BinaryTreeWidget::dataChanged(const QModelIndex &topLeft,
const QModelIndex & /*bottomRight*/,
const QVector<int> & /*roles*/) {
emit treeDataChange(
dynamic_cast<BinaryTreeWidgetItem *>(itemFromIndex(topLeft)),
topLeft.data(Qt::UserRole).toInt());
Gigg, Martyn Anthony
committed
}
Gigg, Martyn Anthony
committed
//------------------------------------------------
// ComboBoxDelegate
//------------------------------------------------
/**
* Default constructor
*/
ComboBoxDelegate::ComboBoxDelegate(QWidget *parent) : QItemDelegate(parent) {}
Gigg, Martyn Anthony
committed
Gigg, Martyn Anthony
committed
/**
* Create an editor for a tree item
Janik Zikovsky
committed
* @param parent :: The parent widget
* @param index :: unused argument
* @param option :: unused argument
Gigg, Martyn Anthony
committed
*/
QWidget *ComboBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem & /*option*/,
const QModelIndex & /*index*/) const {
Gigg, Martyn Anthony
committed
QComboBox *editor = new QComboBox(parent);
editor->addItem("intersection");
Gigg, Martyn Anthony
committed
editor->addItem("union");
Gigg, Martyn Anthony
committed
editor->addItem("difference");
Gigg, Martyn Anthony
committed
return editor;
}
Gigg, Martyn Anthony
committed
/**
* Set the data for the editor when it has been created
Janik Zikovsky
committed
* @param editor :: The editor in question
* @param index :: The model item in question
Gigg, Martyn Anthony
committed
*/
void ComboBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const {
Gigg, Martyn Anthony
committed
int value = index.model()->data(index, Qt::UserRole).toInt();
QComboBox *combo_box = qobject_cast<QComboBox *>(editor);
Gigg, Martyn Anthony
committed
combo_box->setCurrentIndex(value);
}
Gigg, Martyn Anthony
committed
/**
* Set the data for the model when editing is finished
Janik Zikovsky
committed
* @param editor :: The editor in question
* @param model :: The model in question
* @param index :: The index for the model given
Gigg, Martyn Anthony
committed
*/
Gigg, Martyn Anthony
committed
void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const {
QComboBox *combo_box = static_cast<QComboBox *>(editor);
Gigg, Martyn Anthony
committed
int boxitem = combo_box->currentIndex();
QString value = combo_box->itemText(boxitem);
Gigg, Martyn Anthony
committed
model->setData(index, boxitem, Qt::UserRole);
Gigg, Martyn Anthony
committed
model->setData(index, value, Qt::DisplayRole);
}
Gigg, Martyn Anthony
committed
/**
* Set the appropriate geometry for the widget
Janik Zikovsky
committed
* @param editor :: The editor in question
* @param option :: The style option
* @param index :: The index for the model given
Gigg, Martyn Anthony
committed
*/
void ComboBoxDelegate::updateEditorGeometry(
QWidget *editor, const QStyleOptionViewItem &option,
const QModelIndex & /*index*/) const {
Gigg, Martyn Anthony
committed
editor->setGeometry(option.rect);
}