BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SessionXML.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file GUI/coregui/Models/SessionXML.cpp
6 //! @brief Implements reader and writer classes for SessionModel
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
25 #include <QtCore/QXmlStreamWriter>
26 
27 namespace {
28 const QString bool_type_name = "bool";
29 const QString double_type_name = "double";
30 const QString int_type_name = "int";
31 const QString uint_type_name = "uint";
32 const QString qstring_type_name = "QString";
33 
34 void report_error(MessageService* messageService, SessionItem* item, const QString& message);
35 
36 SessionItem* createItem(SessionItem* item, const QString& modelType, const QString& tag);
37 } // namespace
38 
39 void SessionXML::writeTo(QXmlStreamWriter* writer, SessionItem* parent)
40 {
41  writer->writeStartElement(parent->model()->getModelTag());
42  writer->writeAttribute(SessionXML::ModelNameAttribute, parent->model()->getModelName());
43 
44  writeItemAndChildItems(writer, parent);
45 
46  writer->writeEndElement(); // m_model_tag
47 }
48 
49 void SessionXML::writeItemAndChildItems(QXmlStreamWriter* writer, const SessionItem* item)
50 {
51  if (item->parent()) {
52  writer->writeStartElement(SessionXML::ItemTag);
53  writer->writeAttribute(SessionXML::ModelTypeAttribute, item->modelType());
54  QString tag = item->parent()->tagFromItem(item);
55  writer->writeAttribute(SessionXML::TagAttribute, tag);
56  writer->writeAttribute(SessionXML::DisplayNameAttribute,
58  for (int role : item->getRoles()) {
59  if (role == Qt::DisplayRole || role == Qt::EditRole)
60  SessionXML::writeVariant(writer, item->value(), role);
61  }
62  }
63 
64  for (auto child : item->children())
65  writeItemAndChildItems(writer, child);
66 
67  QByteArray a = item->serializeBinaryData();
68  if (!a.isEmpty()) {
69  writer->writeStartElement(SessionXML::BinaryData);
70  writer->writeAttribute(SessionXML::Version, "1");
71  writer->writeCharacters(a.toBase64());
72  writer->writeEndElement();
73  }
74 
75  if (item->parent())
76  writer->writeEndElement(); // ItemTag
77 }
78 
79 void SessionXML::writeVariant(QXmlStreamWriter* writer, QVariant variant, int role)
80 {
81  if (variant.isValid()) {
82  writer->writeStartElement(SessionXML::ParameterTag);
83  QString type_name = variant.typeName();
84  writer->writeAttribute(SessionXML::ParameterTypeAttribute, type_name);
85  writer->writeAttribute(SessionXML::ParameterRoleAttribute, QString::number(role));
86 
87  if (type_name == double_type_name) {
88  writer->writeAttribute(SessionXML::ParameterValueAttribute,
89  QString::number(variant.toDouble(), 'e', 12));
90  } else if (type_name == int_type_name) {
91  writer->writeAttribute(SessionXML::ParameterValueAttribute,
92  QString::number(variant.toInt()));
93  } else if (type_name == uint_type_name) {
94  writer->writeAttribute(SessionXML::ParameterValueAttribute,
95  QString::number(variant.toUInt()));
96  } else if (type_name == bool_type_name) {
97  writer->writeAttribute(SessionXML::ParameterValueAttribute,
98  QString::number(variant.toBool()));
99  } else if (type_name == qstring_type_name) {
100  writer->writeAttribute(SessionXML::ParameterValueAttribute, variant.toString());
101  } else if (type_name == "ExternalProperty") {
102  ExternalProperty prop = variant.value<ExternalProperty>();
103  writer->writeAttribute(SessionXML::ExternalPropertyTextAtt, prop.text());
104 
105  QString tcol = prop.color().isValid() ? prop.color().name(QColor::HexArgb) : "";
106  writer->writeAttribute(SessionXML::ExternalPropertyColorAtt, tcol);
107  writer->writeAttribute(SessionXML::ExternalPropertyIdentifierAtt, prop.identifier());
108  } else if (type_name == "ComboProperty") {
109  ComboProperty combo = variant.value<ComboProperty>();
110  writer->writeAttribute(SessionXML::ParameterValueAttribute, combo.stringOfSelections());
111  writer->writeAttribute(SessionXML::ParameterExtAttribute, combo.stringOfValues());
112 
113  } else {
114  throw GUIHelpers::Error("SessionXML::writeVariant: Parameter type not supported "
115  + type_name);
116  }
117 
118  writer->writeEndElement(); // end ParameterTag
119  }
120 }
121 
122 void SessionXML::readItems(QXmlStreamReader* reader, SessionItem* parent, QString topTag,
123  MessageService* messageService)
124 {
125  ASSERT(parent);
126  const QString start_type = parent->model()->getModelTag();
127  while (!reader->atEnd()) {
128  reader->readNext();
129  if (reader->isStartElement()) {
130  if (reader->name() == SessionXML::ItemTag) {
131  const QString model_type =
132  reader->attributes().value(SessionXML::ModelTypeAttribute).toString();
133  QString tag = reader->attributes().value(SessionXML::TagAttribute).toString();
134  QString displayName =
135  reader->attributes().value(SessionXML::DisplayNameAttribute).toString();
136 
137  if (!topTag.isEmpty()) {
138  // to handle copying of item to another parent
139  tag = topTag;
140  topTag.clear();
141  }
142  auto newItem = createItem(parent, model_type, tag);
143  if (!newItem) {
144  QString message = QString("Error while parsing XML. Can't create item of "
145  "modelType '%1' for tag '%2', parent '%3'")
146  .arg(model_type, tag, parent->P_NAME);
147  report_error(messageService, parent, message);
148  // risky attempt to recover the rest of the project
149  reader->skipCurrentElement();
150  } else {
151  parent = newItem;
152  parent->setDisplayName(displayName);
153  }
154  } else if (reader->name() == SessionXML::ParameterTag) {
155  SessionXML::readProperty(reader, parent, messageService);
156  } else if (reader->name() == SessionXML::BinaryData) {
157  if (reader->attributes().value(SessionXML::Version).toInt() == 1) {
158  QString valueAsBase64 =
159  reader->readElementText(QXmlStreamReader::SkipChildElements);
160  const auto data = QByteArray::fromBase64(
161  valueAsBase64.toLatin1()); // #baimport add a unit test for this!
162  parent->deserializeBinaryData(data);
163  } else
165  }
166  } else if (reader->isEndElement()) {
167  if (reader->name() == SessionXML::ItemTag && parent)
168  parent = parent->parent();
169 
170  if (reader->name() == start_type)
171  break;
172  }
173  }
174 }
175 
176 QString SessionXML::readProperty(QXmlStreamReader* reader, SessionItem* item,
177  MessageService* messageService)
178 {
179  const QString parameter_name =
180  reader->attributes().value(SessionXML::ParameterNameAttribute).toString();
181  const QString parameter_type =
182  reader->attributes().value(SessionXML::ParameterTypeAttribute).toString();
183  const int role = reader->attributes().value(SessionXML::ParameterRoleAttribute).toInt();
184 
185  if (!item) {
186  QString message =
187  QString("Attempt to set property '%1' for non existing item").arg(parameter_name);
188  report_error(messageService, item, message);
189  return parameter_name;
190  }
191 
192  QVariant variant;
193  if (parameter_type == double_type_name) {
194  double parameter_value =
195  reader->attributes().value(SessionXML::ParameterValueAttribute).toDouble();
196  variant = parameter_value;
197  } else if (parameter_type == int_type_name) {
198  int parameter_value =
199  reader->attributes().value(SessionXML::ParameterValueAttribute).toInt();
200  variant = parameter_value;
201  } else if (parameter_type == uint_type_name) {
202  unsigned parameter_value =
203  reader->attributes().value(SessionXML::ParameterValueAttribute).toUInt();
204  variant = parameter_value;
205  } else if (parameter_type == bool_type_name) {
206  bool parameter_value =
207  reader->attributes().value(SessionXML::ParameterValueAttribute).toInt();
208  variant = parameter_value;
209  } else if (parameter_type == qstring_type_name) {
210  QString parameter_value =
211  reader->attributes().value(SessionXML::ParameterValueAttribute).toString();
212  variant = parameter_value;
213  } else if (parameter_type == "ExternalProperty") {
214  QString text = reader->attributes().value(SessionXML::ExternalPropertyTextAtt).toString();
215  QString colorName =
216  reader->attributes().value(SessionXML::ExternalPropertyColorAtt).toString();
217  QString identifier =
218  reader->attributes().value(SessionXML::ExternalPropertyIdentifierAtt).toString();
219 
220  ExternalProperty property;
221  property.setText(text);
222  property.setColor(QColor(colorName));
223  property.setIdentifier(identifier);
224  variant = property.variant();
225  } else if (parameter_type == "ComboProperty") {
226  QString selections =
227  reader->attributes().value(SessionXML::ParameterValueAttribute).toString();
228  QString values = reader->attributes().value(SessionXML::ParameterExtAttribute).toString();
229 
230  ComboProperty combo_property;
231  combo_property.setStringOfValues(values);
232  combo_property.setStringOfSelections(selections);
233 
234  variant = combo_property.variant();
235  } else {
236  QString message = QString("SessionModel::readProperty: parameter type not supported '"
237  + parameter_type + "'");
238  throw GUIHelpers::Error(message);
239  }
240 
241  if (variant.isValid()) {
242  item->setRoleProperty(role, variant);
243  }
244 
245  return parameter_name;
246 }
247 
248 namespace {
249 void report_error(MessageService* messageService, SessionItem* item, const QString& message)
250 {
251  if (messageService) {
252  messageService->send_warning(item->model(), message);
253  } else {
254  throw GUIHelpers::Error(QString("Warning: ") + message);
255  }
256 }
257 
258 SessionItem* createItem(SessionItem* item, const QString& modelType, const QString& tag)
259 {
260  SessionItem* result(nullptr);
261 
262  if (item->modelType() == "GroupProperty") {
263  if (auto groupItem = dynamic_cast<GroupItem*>(item))
264  result = groupItem->getItemOfType(modelType);
265  } else {
266  if (item->sessionItemTags()->isSingleItemTag(tag)) {
267  result = item->getItem(tag);
268  } else {
269  try {
270  result = item->model()->insertNewItem(modelType, item, -1, tag);
271  } catch (const std::exception&) {
272  result = nullptr; // error will be reported later
273  }
274  }
275  }
276  return result;
277 }
278 } // namespace
#define ASSERT(condition)
Definition: Assert.h:31
Defines class ComboProperty.
Defines class DeserializationException.
Defines class ExternalProperty.
Defines class GUIHelpers functions.
Defines class GroupItemController.
Defines class GroupItem.
Defines class ItemFactory.
Defines MessageService class.
Defines class SessionItemTags.
Defines class SessionModel.
Custom property to define list of string values with multiple selections.
Definition: ComboProperty.h:25
void setStringOfValues(const QString &values)
Sets values from the string containing delimeter ';'.
QString stringOfSelections() const
Return string with coma separated list of selected indices.
void setStringOfSelections(const QString &values)
Sets selected indices from string.
QString stringOfValues() const
Returns a single string containing values delimited with ';'.
QVariant variant() const
Constructs variant enclosing given ComboProperty.
static DeserializationException tooNew()
The ExternalProperty class defines custom QVariant property to carry the text, color and an identifie...
QString identifier() const
QString text() const
void setText(const QString &name)
QColor color() const
The service to collect messages from different senders.
void send_warning(QObject *sender, const QString &description)
bool isSingleItemTag(const QString &tagName)
SessionItemTags * sessionItemTags()
QVariant value() const
Get value.
QVector< int > getRoles() const
Returns vector of all present roles.
static const QString P_NAME
Definition: SessionItem.h:37
void setDisplayName(const QString &display_name)
Set display name.
SessionItem * parent() const
Returns parent of this item.
Definition: SessionItem.cpp:73
virtual void deserializeBinaryData(const QByteArray &data)
SessionModel * model() const
Returns model of this item.
Definition: SessionItem.cpp:66
virtual QByteArray serializeBinaryData() const
QVariant roleProperty(int role) const
Returns corresponding variant under given role, invalid variant when role is not present.
QVector< SessionItem * > children() const
Returns vector of all children.
QString modelType() const
Get model type.
QString tagFromItem(const SessionItem *item) const
Returns the tag name of given item when existing.
bool setRoleProperty(int role, const QVariant &value)
Set variant to role, create role if not present yet.
SessionItem * getItem(const QString &tag="", int row=0) const
Returns item in given row of given tag.
QString getModelName() const
Definition: SessionModel.h:196
QString getModelTag() const
Definition: SessionModel.h:191
SessionItem * insertNewItem(QString model_type, SessionItem *parent_item=nullptr, int row=-1, QString tag="")
const std::string bool_type_name
const std::string double_type_name
const std::string int_type_name
std::string model_type
Definition: types.h:23
const QString Version("Version")
const QString ParameterValueAttribute("ParValue")
const QString ParameterNameAttribute("ParName")
const QString BinaryData("BinaryData")
const QString TagAttribute("Tag")
const QString ParameterExtAttribute("ParExt")
void writeVariant(QXmlStreamWriter *writer, QVariant variant, int role)
Definition: SessionXML.cpp:79
const QString ParameterTag("Parameter")
const QString ModelTypeAttribute("ModelType")
const QString ExternalPropertyColorAtt("Color")
QString readProperty(QXmlStreamReader *reader, SessionItem *item, MessageService *messageService=nullptr)
Definition: SessionXML.cpp:176
const QString ParameterRoleAttribute("ParRole")
const QString DisplayNameAttribute("DisplayName")
void writeItemAndChildItems(QXmlStreamWriter *writer, const SessionItem *item)
Definition: SessionXML.cpp:49
void readItems(QXmlStreamReader *reader, SessionItem *parent, QString topTag="", MessageService *messageService=nullptr)
Definition: SessionXML.cpp:122
void writeTo(QXmlStreamWriter *writer, SessionItem *parent)
Definition: SessionXML.cpp:39
const QString ModelNameAttribute("Name")
const QString ItemTag("Item")
const QString ParameterTypeAttribute("ParType")
const QString ExternalPropertyIdentifierAtt("Identifier")
const QString ExternalPropertyTextAtt("Text")