Commit ec9f761d authored by Samuel Jones's avatar Samuel Jones
Browse files

Re #24350 Semi-working review improvements and tests

parent 304bdaa7
......@@ -14,6 +14,11 @@ class DecoderFactory(object):
@classmethod
def find_decoder(cls, tag):
"""
This assumes that tag is present in a decoder and if it cannot find a decoder with the tag it raises ValueError
:param tag: String; The tag used for saving and thus to be reused for loading that encoder back.
:return: Decoder object; The object of a decoder for the tag that was passed.
"""
for decoder in cls.decoder_list:
if tag in decoder.tags:
return decoder()
......@@ -21,8 +26,9 @@ class DecoderFactory(object):
@classmethod
def register_decoder(cls, decoder):
for decoder_ in cls.decoder_list:
if decoder is decoder_:
# It's a duplicate
return
cls.decoder_list.append(decoder)
"""
Will register the decoder class with the factory
:param decoder: The Decoder class; to be registered with the Factory
"""
if decoder not in cls.decoder_list:
cls.decoder_list.append(decoder)
......@@ -10,14 +10,14 @@ from __future__ import (absolute_import, division, print_function, unicode_liter
class EncoderFactory(object):
encoder_list = []
encoder_list = set([])
@classmethod
def find_encoder(cls, obj):
"""
This assumes that obj is of a class that has an encode else it returns None
:param obj: The object for encoding
:return: Encoder or None; Returns the Encoder of the obj
:return: Encoder or None; Returns the Encoder of the obj or None.
"""
for encoder in cls.encoder_list:
if encoder().has_tag(obj.__class__.__name__):
......@@ -26,8 +26,8 @@ class EncoderFactory(object):
@classmethod
def register_encoder(cls, encoder):
for encoder_ in cls.encoder_list:
if encoder is encoder_:
# It's a duplicate
return
cls.encoder_list.append(encoder)
"""
This adds the passed encoder's class to the available encoders in the Factory
:param encoder: Class of Encoder; The class of the encoder to be added to the list.
"""
cls.encoder_list.add(encoder)
......@@ -62,16 +62,19 @@ class ProjectLoader(object):
# Load interfaces
if self.project_reader.interface_list is not None:
for interface in self.project_reader.interface_list:
# Find decoder
decoder = self.decoder_factory.find_decoder(interface["tag"])
# Decode and Show the interface
decoded_interface = decoder.decode(interface, directory)
decoded_interface.show()
self.load_interfaces(directory)
return workspace_success
def load_interfaces(self, directory):
for interface in self.project_reader.interface_list:
# Find decoder
decoder = self.decoder_factory.find_decoder(interface["tag"])
# Decode and Show the interface
decoded_interface = decoder.decode(interface, directory)
decoded_interface.show()
class ProjectReader(object):
def __init__(self, project_file_ext):
......
......@@ -8,15 +8,19 @@
#
from __future__ import (absolute_import, division, print_function, unicode_literals)
import unittest
from mantidqt.project.encoderfactory import EncoderFactory
from mantidqt.widgets.instrumentview.io import InstrumentViewEncoder
from mantidqt.widgets.instrumentview.presenter import InstrumentViewPresenter
from mantid.simpleapi import CreateSampleWorkspace
from mantid.api import AnalysisDataService as ADS
from mantidqt.utils.qt.test import GuiTest
class EncoderFactoryTest(unittest.TestCase):
class EncoderFactoryTest(GuiTest):
def setUp(self):
EncoderFactory.register_encoder(InstrumentViewEncoder())
EncoderFactory.register_encoder(InstrumentViewEncoder)
CreateSampleWorkspace(OutputWorkspace="ws")
self.instrument_view = InstrumentViewPresenter(ADS.retrieve("ws")).view
def test_find_encoder_can_find_an_encoder(self):
self.assertNotEqual(None, EncoderFactory.find_encoder("InstrumentView"))
self.assertNotEqual(None, EncoderFactory.find_encoder(self.instrument_view))
......@@ -149,6 +149,8 @@ class ProjectWriterTest(unittest.TestCase):
if os.path.isdir(working_directory):
rmtree(working_directory)
self.file_name = working_directory + "/" + os.path.basename(working_directory) + project_file_ext
def test_write_out_empty_workspaces(self):
workspace_list = []
plots_to_save = []
......@@ -156,15 +158,13 @@ class ProjectWriterTest(unittest.TestCase):
project_writer = projectsaver.ProjectWriter(save_location=working_directory, workspace_names=workspace_list,
project_file_ext=project_file_ext, plots_to_save=plots_to_save,
interfaces_to_save=interfaces_to_save)
file_name = working_directory + "/" + os.path.basename(working_directory) + project_file_ext
workspaces_string = "\"workspaces\": []"
plots_string = "\"plots\": []"
project_writer.write_out()
f = open(file_name, "r")
file_string = f.read()
with open(self.file_name, 'r') as f:
file_string = f.read()
self.assertTrue(workspaces_string in file_string)
self.assertTrue(plots_string in file_string)
......@@ -175,14 +175,12 @@ class ProjectWriterTest(unittest.TestCase):
project_writer = projectsaver.ProjectWriter(save_location=working_directory, workspace_names=workspace_list,
project_file_ext=project_file_ext, plots_to_save=plots_to_save,
interfaces_to_save=interfaces_to_save)
file_name = working_directory + "/" + os.path.basename(working_directory) + project_file_ext
workspaces_string = "\"workspaces\": [\"ws1\", \"ws2\", \"ws3\", \"ws4\"]"
plots_string = "\"plots\": []"
project_writer.write_out()
f = open(file_name, "r")
file_string = f.read()
with open(self.file_name, 'r') as f:
file_string = f.read()
self.assertTrue(workspaces_string in file_string)
self.assertTrue(plots_string in file_string)
......@@ -193,15 +191,13 @@ class ProjectWriterTest(unittest.TestCase):
project_writer = projectsaver.ProjectWriter(save_location=working_directory, workspace_names=workspace_list,
project_file_ext=project_file_ext, plots_to_save=plots_to_save,
interfaces_to_save=interfaces_to_save)
file_name = working_directory + "/" + os.path.basename(working_directory) + project_file_ext
workspaces_string = "\"workspaces\": []"
plots_string = "\"plots\": [{\"plots1\": {\"plot-information\": \"axes data\"}}]"
project_writer.write_out()
f = open(file_name, "r")
file_string = f.read()
with open(self.file_name, 'r') as f:
file_string = f.read()
self.assertTrue(workspaces_string in file_string)
self.assertTrue(plots_string in file_string)
......@@ -212,15 +208,13 @@ class ProjectWriterTest(unittest.TestCase):
project_writer = projectsaver.ProjectWriter(save_location=working_directory, workspace_names=workspace_list,
project_file_ext=project_file_ext, plots_to_save=plots_to_save,
interfaces_to_save=interfaces_to_save)
file_name = working_directory + "/" + os.path.basename(working_directory) + project_file_ext
workspaces_string = "\"workspaces\": [\"ws1\", \"ws2\", \"ws3\", \"ws4\"]"
plots_string = "\"plots\": [{\"plots1\": {\"plot-information\": \"axes data\"}}]"
project_writer.write_out()
f = open(file_name, "r")
file_string = f.read()
with open(self.file_name, 'r') as f:
file_string = f.read()
self.assertTrue(workspaces_string in file_string)
self.assertTrue(plots_string in file_string)
......@@ -231,16 +225,14 @@ class ProjectWriterTest(unittest.TestCase):
project_writer = projectsaver.ProjectWriter(save_location=working_directory, workspace_names=workspace_list,
project_file_ext=project_file_ext, plots_to_save=plots_to_save,
interfaces_to_save=interfaces_to_save)
file_name = working_directory + "/" + os.path.basename(working_directory) + project_file_ext
workspaces_string = "\"workspaces\": []"
plots_string = "\"plots\": []"
interface_string = "\"interfaces\": [{\"interface1\": {\"interface data\": \"data\"}}]"
project_writer.write_out()
f = open(file_name, "r")
file_string = f.read()
with open(self.file_name, 'r') as f:
file_string = f.read()
self.assertTrue(workspaces_string in file_string)
self.assertTrue(plots_string in file_string)
self.assertTrue(interface_string in file_string)
......
......@@ -35,10 +35,10 @@ class InstrumentViewDecoder(InstrumentViewAttributes):
def decode(self, obj_dic, project_path=None):
"""
:param obj_dic:
:param project_path:
:return:
Decode a InstrumentView Dictionary from project Save and return the object created
:param obj_dic: Dict; A dictionary containing the information for an InstrumentView
:param project_path: String; The location of the project save location
:return: InstrumentView's View; The View object with correct state is returned.
"""
load_mask = True
......@@ -51,14 +51,14 @@ class InstrumentViewDecoder(InstrumentViewAttributes):
# Make the widget
ws = ADS.retrieve(obj_dic["workspaceName"])
instrument_view_presenter = InstrumentViewPresenter(ws)
instrument_widget = instrument_view_presenter.view.cpp_widget
instrument_view = InstrumentViewPresenter(ws).view
instrument_widget = instrument_view.widget
# Then 'decode' set the values from the dictionary
self.widget_decoder.decode(obj_dic, instrument_widget, project_path, load_mask)
# Show the end result
return instrument_view_presenter.view
return instrument_view
@classmethod
def has_tag(cls, tag):
......@@ -71,6 +71,12 @@ class InstrumentViewEncoder(InstrumentViewAttributes):
self.widget_encoder = _InstrumentWidgetEncoder()
def encode(self, obj, project_path=None):
"""
Encode a InstrumentView object and return a dictionary containing it's state
:param obj: InstrumentView; The window object
:param project_path: String; The path to where the project is being saved
:return: Dict; Containing the details of the instrument view
"""
save_mask = True
if obj is None:
......
......@@ -14,34 +14,64 @@ from mantidqt.widgets.instrumentview.io import InstrumentViewEncoder, Instrument
from mantid.simpleapi import CreateSampleWorkspace
from mantidqt.utils.qt.test import GuiTest
import os
INSTRUMENT_VIEW_DICT = {u'workspaceName': u'ws',
u'tabs': {u'maskTab': {
u'activeType': {
u'roiOn': False, u'groupingOn': False, u'maskingOn': True},
u'activeTools': {u'ellipseButton': False, u'moveButton': True,
u'pointerButton': False, u'ringRectangleButton': False,
u'freeDrawButton': False, u'ringEllipseButton': False},
u'maskWorkspaceSaved': False},
u'renderTab': {u'displayWireframe': False, u'displayLighting': False,
u'labelPrecision': 1, u'useUCorrection': False, u'autoScaling': False,
u'colorBar': {u'max': u'40', u'scaleType': 0, u'power': u'2',
u'min': u'40'},
u'showLabels': True, u'flipView': False, u'displayDetectorsOnly': True,
u'displayAxes': False, u'axesView': 0, u'showRows': True,
u'useOpenGL': True, u'showRelativeIntensity': False},
u'treeTab': {u'expandedItems': []},
u'pickTab': {u'freeDraw': False, u'ringEllipse': False, u'edit': False,
u'tube': False, u'peakSelect': False, u'zoom': False, u'one': True,
u'ringRectangle': False, u'peak': False, u'ellipse': False,
u'rectangle': False}}, u'surfaceType': 0,
u'actor': {u'binMasks': [], u'fileName': u'viridis'},
u'energyTransfer': [0.0, 20000.0],
u'surface': {u'shapes': [], u'alignmentInfo': [], u'backgroundColor': {u'blue': 0,
u'alpha': 255,
u'green': 0,
u'red': 0}},
u'currentTab': 0}
if os.name == 'nt':
INSTRUMENT_VIEW_DICT = {u'workspaceName': u'ws',
u'tabs': {u'maskTab': {
u'activeType': {
u'roiOn': False, u'groupingOn': False, u'maskingOn': True},
u'activeTools': {u'ellipseButton': False, u'moveButton': True,
u'pointerButton': False, u'ringRectangleButton': False,
u'freeDrawButton': False, u'ringEllipseButton': False},
u'maskWorkspaceSaved': False},
u'renderTab': {u'displayWireframe': False, u'displayLighting': False,
u'labelPrecision': 2, u'useUCorrection': False, u'autoScaling': True,
u'colorBar': {u'max': u'40', u'scaleType': 0, u'power': u'2',
u'min': u'40'},
u'showLabels': True, u'flipView': False, u'displayDetectorsOnly': True,
u'displayAxes': True, u'axesView': 0, u'showRows': True,
u'useOpenGL': True, u'showRelativeIntensity': False},
u'treeTab': {u'expandedItems': []},
u'pickTab': {u'freeDraw': False, u'ringEllipse': False, u'edit': False,
u'tube': False, u'peakSelect': False, u'zoom': False, u'one': True,
u'ringRectangle': False, u'peak': False, u'ellipse': False,
u'rectangle': False}}, u'surfaceType': 0,
u'actor': {u'binMasks': [], u'fileName': u'viridis'},
u'energyTransfer': [0.0, 20000.0],
u'surface': {u'shapes': [], u'alignmentInfo': [], u'backgroundColor': {u'blue': 0,
u'alpha': 255,
u'green': 0,
u'red': 0}},
u'currentTab': 0}
else:
INSTRUMENT_VIEW_DICT = {u'workspaceName': u'ws',
u'tabs': {u'maskTab': {
u'activeType': {
u'roiOn': False, u'groupingOn': False, u'maskingOn': True},
u'activeTools': {u'ellipseButton': False, u'moveButton': True,
u'pointerButton': False, u'ringRectangleButton': False,
u'freeDrawButton': False, u'ringEllipseButton': False},
u'maskWorkspaceSaved': False},
u'renderTab': {u'displayWireframe': False, u'displayLighting': False,
u'labelPrecision': 1, u'useUCorrection': False, u'autoScaling': True,
u'colorBar': {u'max': u'40', u'scaleType': 0, u'power': u'2',
u'min': u'40'},
u'showLabels': True, u'flipView': False, u'displayDetectorsOnly': True,
u'displayAxes': False, u'axesView': 0, u'showRows': True,
u'useOpenGL': True, u'showRelativeIntensity': False},
u'treeTab': {u'expandedItems': []},
u'pickTab': {u'freeDraw': False, u'ringEllipse': False, u'edit': False,
u'tube': False, u'peakSelect': False, u'zoom': False, u'one': True,
u'ringRectangle': False, u'peak': False, u'ellipse': False,
u'rectangle': False}}, u'surfaceType': 0,
u'actor': {u'binMasks': [], u'fileName': u'viridis'},
u'energyTransfer': [0.0, 20000.0],
u'surface': {u'shapes': [], u'alignmentInfo': [], u'backgroundColor': {u'blue': 0,
u'alpha': 255,
u'green': 0,
u'red': 0}},
u'currentTab': 0}
class InstrumentViewEncoderTest(GuiTest):
......
......@@ -47,8 +47,6 @@ class InstrumentView(QWidget, ObservingView):
self.setWindowTitle(name)
self.setWindowFlags(Qt.Window)
self.cpp_widget = InstrumentWidget(name)
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.widget)
......
......@@ -39,7 +39,7 @@ public:
signals:
void shapeCreated();
protected:
private:
void decodeTabs(const QMap<QString, QVariant> &map, InstrumentWidget &obj);
void decodeMaskTab(const QMap<QString, QVariant> &map,
......
......@@ -17,6 +17,8 @@
#include "MantidQtWidgets/InstrumentView/MaskBinsData.h"
#include "MantidQtWidgets/InstrumentView/ProjectionSurface.h"
#include "MantidQtWidgets/InstrumentView/Shape2D.h"
#include "MantidQtWidgets/InstrumentView/Projection3D.h"
#include "MantidQtWidgets/InstrumentView/Viewport.h"
namespace MantidQt {
namespace MantidWidgets {
......@@ -54,13 +56,16 @@ private:
QMap<QString, QVariant> encodeBinMask(const BinMask &obj);
QMap<QString, QVariant> encodeSurface(const ProjectionSurface_sptr &obj);
QMap<QString, QVariant> encodeShape(Shape2D *obj);
QMap<QString, QVariant> encodeEllipse(Shape2DEllipse *obj);
QMap<QString, QVariant> encodeRectangle(Shape2DRectangle *obj);
QMap<QString, QVariant> encodeRing(Shape2DRing *obj);
QMap<QString, QVariant> encodeFree(Shape2DFree *obj);
QMap<QString, QVariant> encodeViewPort(const Viewport &obj);
QMap<QString, QVariant> encodeProjection3D(const Projection3D &obj);
QList<QVariant> encodeMaskShapes(Shape2DCollection &obj);
QMap<QString, QVariant> encodeShape(const Shape2D *obj);
QMap<QString, QVariant> encodeEllipse(const Shape2DEllipse *obj);
QMap<QString, QVariant> encodeRectangle(const Shape2DRectangle *obj);
QMap<QString, QVariant> encodeRing(const Shape2DRing *obj);
QMap<QString, QVariant> encodeFree(const Shape2DFree *obj);
QList<QVariant> encodeMaskShapes(const Shape2DCollection &obj);
QMap<QString, QVariant> encodeShapeProperties(const Shape2D *obj);
QList<QVariant> encodeAlignmentInfo(const ProjectionSurface_sptr &obj);
......
......@@ -79,6 +79,9 @@ protected:
bool m_wireframe;
Viewport m_viewport;
friend class InstrumentWidgetEncoder;
friend class InstrumentWidgetDecoder;
};
} // namespace MantidWidgets
......
......@@ -128,6 +128,7 @@ public:
static Shape2D *loadFromProject(const std::string &lines);
/// Save settings for the widget tab to a project file
virtual std::string saveToProject() const;
virtual std::string type() const { return "base"; }
// --- Properties. for gui interaction --- //
......@@ -218,6 +219,7 @@ public:
static Shape2D *loadFromProject(const std::string &lines);
/// Save state for the shape to a project file
virtual std::string saveToProject() const override;
std::string type() const override { return "ellipse"; }
protected:
void drawShape(QPainter &painter) const override;
......@@ -244,6 +246,7 @@ public:
static Shape2D *loadFromProject(const std::string &lines);
/// Save state for the shape to a project file
virtual std::string saveToProject() const override;
std::string type() const override { return "rectangle"; }
protected:
void drawShape(QPainter &painter) const override;
......@@ -280,6 +283,7 @@ public:
static Shape2D *loadFromProject(const std::string &lines);
/// Save state for the shape to a project file
virtual std::string saveToProject() const override;
std::string type() const override { return "ring"; }
protected:
void drawShape(QPainter &painter) const override;
......@@ -315,6 +319,7 @@ public:
static Shape2D *loadFromProject(const std::string &lines);
/// Save state for the shape to a project file
virtual std::string saveToProject() const override;
std::string type() const override { return "free"; }
protected:
void drawShape(QPainter &painter) const override;
......
......@@ -175,6 +175,9 @@ protected:
double m_yTrans;
/// Translation in z direction
mutable double m_zTrans;
friend class InstrumentWidgetEncoder;
friend class InstrumentWidgetDecoder;
};
} // namespace MantidWidgets
} // namespace MantidQt
......
......@@ -1265,7 +1265,6 @@ void InstrumentWidget::handleWorkspaceReplacement(
bool resetGeometry =
matrixWS->detectorInfo().size() != m_instrumentActor->ndetectors();
try {
// Will segfault if the
if (matrixWS == m_instrumentActor->getWorkspace() && !resetGeometry) {
m_instrumentActor->updateColors();
setupColorMap();
......
......@@ -71,6 +71,7 @@ void InstrumentWidgetDecoder::decodeTabs(const QMap<QString, QVariant> &map,
void InstrumentWidgetDecoder::decodeMaskTab(const QMap<QString, QVariant> &map,
InstrumentWidgetMaskTab *obj) {
connect(this, SIGNAL(shapeCreated()), obj, SLOT(shapeCreated()));
const auto activeTools = map[QString("activeTools")].toMap();
const auto activeType = map[QString("activeType")].toMap();
......@@ -145,7 +146,7 @@ void InstrumentWidgetDecoder::decodeTreeTab(const QMap<QString, QVariant> &map,
InstrumentWidgetTreeTab *obj) {
auto names = map[QString("expandedItems")].toList();
if (names.size() > 0) {
for (auto &name : names) {
for (const auto &name : names) {
auto index = obj->m_instrumentTree->findComponentByName(name.toString());
obj->m_instrumentTree->setExpanded(index, true);
}
......@@ -155,6 +156,7 @@ void InstrumentWidgetDecoder::decodeTreeTab(const QMap<QString, QVariant> &map,
void InstrumentWidgetDecoder::decodePickTab(const QMap<QString, QVariant> &map,
InstrumentWidgetPickTab *obj) {
connect(this, SIGNAL(shapeCreated()), obj, SLOT(shapeCreated()));
obj->m_zoom->setChecked(map[QString("zoom")].toBool());
obj->m_edit->setChecked(map[QString("edit")].toBool());
obj->m_ellipse->setChecked(map[QString("ellipse")].toBool());
......@@ -208,30 +210,32 @@ void InstrumentWidgetDecoder::decodeSurface(
void InstrumentWidgetDecoder::decodeMaskShapes(const QList<QVariant> &list,
Shape2DCollection &obj) {
connect(this, SIGNAL(shapeCreated()), &obj, SIGNAL(shapeCreated()));
for (const auto &shape : list) {
Shape2D *created_shape = this->decodeShape(shape.toMap());
auto created_shape = this->decodeShape(shape.toMap());
obj.m_shapes.push_back(created_shape);
emit shapeCreated();
}
std::cout << list.size() << " " << obj.m_shapes.size() << "/n";
}
Shape2D *
InstrumentWidgetDecoder::decodeShape(const QMap<QString, QVariant> &map) {
const auto type = map[QString("type")].toString().toStdString();
Shape2D *shape = nullptr;
if (type == "ellipse") {
shape = this->decodeEllipse(map[QString("subShapeMap")].toMap());
} else if (type == "rectangle") {
shape = this->decodeRectangle(map[QString("subShapeMap")].toMap());
} else if (type == "ring") {
shape = this->decodeRing(map[QString("subShapeMap")].toMap());
} else if (type == "free") {
shape = this->decodeFree(map[QString("subShapeMap")].toMap());
} else {
throw std::runtime_error("InstrumentView - Could not decode shape");
}
auto shape = [&]() {
if (type == "ellipse") {
return this->decodeEllipse(map[QString("subShapeMap")].toMap());
} else if (type == "rectangle") {
return this->decodeRectangle(map[QString("subShapeMap")].toMap());
} else if (type == "ring") {
return this->decodeRing(map[QString("subShapeMap")].toMap());
} else if (type == "free") {
return this->decodeFree(map[QString("subShapeMap")].toMap());
} else {
throw std::runtime_error("InstrumentView - Could not decode shape");
}
}();
shape->setScalable(map[QString("scalable")].toBool());
shape->edit(map[QString("editing")].toBool());
......
......@@ -257,8 +257,33 @@ InstrumentWidgetEncoder::encodeSurface(const ProjectionSurface_sptr &obj) {
return map;
}
QMap<QString, QVariant> InstrumentWidgetEncoder::encodeProjection3D(const Projection3D &obj){
QMap<QString, QVariant> map;
map.insert(QString("viewport"), QVariant(this->encodeViewPort(obj.m_viewport)));
return map;
}
QMap<QString, QVariant> InstrumentWidgetEncoder::encodeViewPort(const Viewport &obj){
QMap<QString, QVariant> map;
QMap<QString, QVariant> translationMap;
translationMap.insert(QString("xTrans"), QVariant(obj.m_xTrans));
translationMap.insert(QString("yTrans"), QVariant(obj.m_yTrans));
map.insert(QString("translation"), QVariant(translationMap));
map.insert(QString("Zoom"), QVariant(obj.m_zoomFactor));
QList<QVariant> rotation;
for(auto i = 0; i < 4; i++){
rotation.append(obj.m_quaternion[i]);
}
map.insert(QString("rotation"), QVariant(rotation));
return map;