• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

step/stepcore

  • sources
  • kde-4.12
  • kdeedu
  • step
  • stepcore
xmlfile.cc
Go to the documentation of this file.
1 /* This file is part of StepCore library.
2  Copyright (C) 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
3 
4  StepCore library is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  StepCore library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with StepCore; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include "xmlfile.h"
20 
21 #ifdef STEPCORE_WITH_QT
22 
23 #include "world.h"
24 #include "solver.h"
25 #include "collisionsolver.h"
26 #include "constraintsolver.h"
27 #include "factory.h"
28 
29 #include <QDomDocument>
30 #include <QXmlStreamWriter>
31 
32 namespace StepCore {
33 
34 const char* XmlFile::DOCTYPE = "<!DOCTYPE StepCoreXML>";
35 const char* XmlFile::NAMESPACE_URI = "http://edu.kde.org/step/StepCoreXML";
36 const char* XmlFile::VERSION = "1.0";
37 
38 namespace {
39 
40 class StepStreamWriter
41 {
42 public:
43  StepStreamWriter(QIODevice* device);
44  bool writeWorld(const World* world);
45 
46 protected:
47  void saveProperties(const Object* obj, int first);
48  void saveObject(const QString& tag, const Object* obj);
49 
50  QXmlStreamWriter _writer;
51  QIODevice* _device;
52  QHash<const Object*, int> _ids;
53  static const int INDENT = 4;
54 };
55 
56 StepStreamWriter::StepStreamWriter(QIODevice* device) : _device(device)
57 {
58  _writer.setAutoFormatting(true);
59  _writer.setAutoFormattingIndent(INDENT);
60 }
61 
62 void StepStreamWriter::saveProperties(const Object* obj, int first)
63 {
64  const MetaObject* metaObject = obj->metaObject();
65  for(int i = first; i < metaObject->propertyCount(); ++i) {
66  const MetaProperty* p = metaObject->property(i);
67  if(p->isStored()) {
68  if(p->userTypeId() == qMetaTypeId<Object*>()) {
69  int id = _ids.value(p->readVariant(obj).value<Object*>(), -1);
70  _writer.writeTextElement(p->name(), QString::number(id));
71  }
72  else {
73  _writer.writeTextElement(p->name(), p->readString(obj));
74  }
75  }
76  }
77 }
78 
79 void StepStreamWriter::saveObject(const QString& tag, const Object* obj)
80 {
81  Q_ASSERT(obj != NULL);
82 
83  _writer.writeStartElement(tag);
84  _writer.writeAttribute("class", obj->metaObject()->className());
85  _writer.writeAttribute("id", QString::number(_ids.value(obj, -1)));
86 
87  saveProperties(obj, 0);
88 
89  if(obj->metaObject()->inherits<Item>()) {
90  const ObjectErrors* objErrors = static_cast<const Item*>(obj)->tryGetObjectErrors();
91  if(objErrors) saveProperties(objErrors, 1);
92  }
93 
94  if(obj->metaObject()->inherits<ItemGroup>()) {
95  const ItemGroup* group = static_cast<const ItemGroup*>(obj);
96  ItemList::const_iterator end = group->items().end();
97  for(ItemList::const_iterator it = group->items().begin(); it != end; ++it) {
98  saveObject("item", *it);
99  }
100  }
101 
102  _writer.writeEndElement();
103 }
104 
105 bool StepStreamWriter::writeWorld(const World* world)
106 {
107  Q_ASSERT(_device->isOpen() && _device->isWritable());
108  _writer.setDevice(_device);
109 
110  int maxid = -1;
111  _ids.insert(NULL, ++maxid);
112  _ids.insert(world, ++maxid);
113 
114  ItemList items = world->allItems();
115  const ItemList::const_iterator end0 = items.end();
116  for(ItemList::const_iterator it = items.begin(); it != end0; ++it)
117  _ids.insert(*it, ++maxid);
118 
119  if(world->solver()) _ids.insert(world->solver(), ++maxid);
120  if(world->collisionSolver()) _ids.insert(world->collisionSolver(), ++maxid);
121  if(world->constraintSolver()) _ids.insert(world->constraintSolver(), ++maxid);
122 
123  _writer.writeStartDocument();
124  _writer.writeDTD(XmlFile::DOCTYPE);
125  _writer.writeStartElement("world");
126  _writer.writeAttribute("xmlns", XmlFile::NAMESPACE_URI);
127  _writer.writeAttribute("version", XmlFile::VERSION);
128  _writer.writeAttribute("id", "1");
129 
130  saveProperties(world, 0);
131 
132  ItemList::const_iterator end = world->items().end();
133  for(ItemList::const_iterator it = world->items().begin(); it != end; ++it) {
134  saveObject("item", *it);
135  }
136 
137  if(world->solver()) {
138  saveObject("solver", world->solver());
139  }
140 
141  if(world->collisionSolver()) {
142  saveObject("collisionSolver", world->collisionSolver());
143  }
144 
145  if(world->constraintSolver()) {
146  saveObject("constraintSolver", world->constraintSolver());
147  }
148 
149  _writer.writeEndElement();
150  _writer.writeEndDocument();
151 
152  return true;
153 }
154 
155 class StepDomDocument
156 {
157 public:
158  StepDomDocument(World* world, const Factory* factory);
159 
160  bool parse(QIODevice* device);
161 
162  const QString& errorMsg() const { return _errorMsg; }
163 
164 private:
165  typedef QPair<QPair<Object*, const MetaProperty*>, int> Link;
166 
167  Item* createItem(const QDomElement& element);
168  Solver* createSolver(const QDomElement& element);
169  CollisionSolver* createCollisionSolver(const QDomElement& element);
170  ConstraintSolver* createConstraintSolver(const QDomElement& element);
171  bool parseWorld(const QDomElement& element);
172  bool parseItems(ItemGroup* parent, const QDomElement& element);
173  bool parseObject(Object* object, const QDomElement& element);
174  bool parseProperties(Object* object, const QDomElement& parent);
175  bool connectLinks();
176 
177  World* _world;
178  const Factory* _factory;
179  QDomDocument _document;
180  QString _errorMsg;
181  int _errorLine;
182  int _errorCount;
183  QString _version;
184  QHash<int, Object*> _ids;
185  QList<Link> _links;
186 };
187 
188 StepDomDocument::StepDomDocument(World* world, const StepCore::Factory* factory) :
189  _world(world), _factory(factory), _errorLine(0), _errorCount(0)
190 {
191 }
192 
193 bool StepDomDocument::parse(QIODevice* device)
194 {
195  if (!_document.setContent(device, &_errorMsg, &_errorLine, &_errorCount)) {
196  return false;
197  }
198 
199  QDomElement worldElement = _document.firstChildElement("world");
200  if (worldElement.isNull()) {
201  _errorMsg = QObject::tr("The file is not a StepCoreXML file.");
202  return false;
203  }
204 
205  return parseWorld(worldElement);
206 }
207 
208 bool StepDomDocument::parseWorld(const QDomElement& world)
209 {
210  _version = world.attribute("version", "1.0");
211 
212  if (!parseObject(_world, world)) return false;
213  if (!parseItems(_world, world)) return false;
214 
215  QDomElement solverElement = world.firstChildElement("solver");
216  if (!solverElement.isNull()) {
217  Solver *solver = createSolver(solverElement);
218  if (!solver) return false;
219 
220  _world->setSolver(solver);
221  }
222 
223  QDomElement collisionSolverElement = world.firstChildElement("collisionSolver");
224  if (!collisionSolverElement.isNull()) {
225  CollisionSolver *solver = createCollisionSolver(collisionSolverElement);
226  if (!solver) return false;
227 
228  _world->setCollisionSolver(solver);
229  }
230 
231  QDomElement constraintSolverElement = world.firstChildElement("constraintSolver");
232  if (!constraintSolverElement.isNull()) {
233  ConstraintSolver *solver = createConstraintSolver(constraintSolverElement);
234  if (!solver) return false;
235 
236  _world->setConstraintSolver(solver);
237  }
238 
239  return connectLinks();
240 }
241 
242 Item* StepDomDocument::createItem(const QDomElement& element)
243 {
244  QString className = element.attribute("class");
245  QScopedPointer<Item> item(_factory->newItem(className));
246  if (!item) {
247  _errorMsg = QObject::tr("Unknown item type \"%1\"").arg(className);
248  return 0;
249  }
250 
251  if (!parseObject(item.data(), element)) return 0;
252  ObjectErrors *objErrors = item->objectErrors();
253  if (objErrors && !parseProperties(objErrors, element)) return 0;
254 
255  if (item->metaObject()->inherits("ItemGroup")) {
256  ItemGroup *group = static_cast<ItemGroup*>(item.data());
257  if (!parseItems(group, element)) return 0;
258  }
259 
260  return item.take();
261 }
262 
263 Solver* StepDomDocument::createSolver(const QDomElement& element)
264 {
265  QString className = element.attribute("class");
266  QScopedPointer<Solver> solver(_factory->newSolver(className));
267  if (!solver) {
268  _errorMsg = QObject::tr("Unknown solver type \"%1\"").arg(className);
269  return 0;
270  }
271 
272  if (!parseObject(solver.data(), element)) return 0;
273 
274  return solver.take();
275 }
276 
277 CollisionSolver* StepDomDocument::createCollisionSolver(const QDomElement& element)
278 {
279  QString className = element.attribute("class");
280  QScopedPointer<CollisionSolver> solver(_factory->newCollisionSolver(className));
281  if (!solver) {
282  _errorMsg = QObject::tr("Unknown collisionSolver type \"%1\"").arg(className);
283  return 0;
284  }
285 
286  if (!parseObject(solver.data(), element)) return 0;
287 
288  return solver.take();
289 }
290 
291 ConstraintSolver* StepDomDocument::createConstraintSolver(const QDomElement& element)
292 {
293  QString className = element.attribute("class");
294  QScopedPointer<ConstraintSolver> solver(_factory->newConstraintSolver(className));
295  if (!solver) {
296  _errorMsg = QObject::tr("Unknown constraint solver type \"%1\"").arg(className);
297  return 0;
298  }
299 
300  if (!parseObject(solver.data(), element)) return 0;
301 
302  return solver.take();
303 }
304 
305 bool StepDomDocument::parseItems(ItemGroup* parent, const QDomElement& element)
306 {
307  QDomElement itemElement = element.firstChildElement("item");
308  while (!itemElement.isNull()) {
309  Item *item = createItem(itemElement);
310  if (!item) return false;
311 
312  parent->addItem(item);
313  itemElement = itemElement.nextSiblingElement("item");
314  }
315 
316  return true;
317 }
318 
319 bool StepDomDocument::parseObject(Object* object, const QDomElement& element)
320 {
321  int n = element.attribute("id").trimmed().toInt();
322 
323  if (!n) {
324  _errorMsg = QObject::tr("Wrong ID attribute value for %1")
325  .arg(object->metaObject()->className());
326  return false;
327  }
328  if (_ids.contains(n)) {
329  _errorMsg = QObject::tr("Non-unique ID attribute value for %1")
330  .arg(object->metaObject()->className());
331  return false;
332  }
333 
334  _ids.insert(n, object);
335 
336  return parseProperties(object, element);
337 }
338 
339 bool StepDomDocument::parseProperties(Object* object, const QDomElement& parent)
340 {
341  int properties = object->metaObject()->propertyCount();
342  for (int n = 0; n < properties; ++n) {
343  const MetaProperty* property = object->metaObject()->property(n);
344 
345  if (!property->isStored()) continue;
346 
347  QString name = property->name();
348  QDomElement propertyElement = parent.firstChildElement(name);
349  if (propertyElement.isNull()) continue;
350 
351  QString text = propertyElement.text();
352  if (property->userTypeId() == qMetaTypeId<Object*>()) {
353  int n = text.trimmed().toInt();
354  _links.push_back(qMakePair(qMakePair(object, property), n));
355  }
356  else if (!property->writeString(object, text)) {
357  _errorMsg = QObject::tr("Property \"%1\" of \"%2\" has illegal value")
358  .arg(name, object->metaObject()->className());
359  return false;
360  }
361  }
362 
363  return true;
364 }
365 
366 bool StepDomDocument::connectLinks()
367 {
368  foreach (const Link& link, _links) {
369  QVariant target = QVariant::fromValue(_ids.value(link.second, 0));
370  if (!link.first.second->writeVariant(link.first.first, target)) {
371  _errorMsg = QObject::tr("Property \"%1\" of \"%2\" has illegal value")
372  .arg(link.first.second->name(), link.first.first->metaObject()->className());
373  return false;
374  }
375  }
376 
377  return true;
378 }
379 } // namespace
380 
381 bool XmlFile::save(const World* world)
382 {
383  if(!_device->isOpen() || !_device-> isWritable()) {
384  _errorString = QObject::tr("File is not writable.");
385  return false;
386  }
387 
388  StepStreamWriter writer(_device);
389  return writer.writeWorld(world);
390 }
391 
392 bool XmlFile::load(World* world, const Factory* factory)
393 {
394  StepDomDocument document(world, factory);
395  if (!document.parse(_device)) {
396  _errorString = document.errorMsg();
397  return false;
398  }
399 
400  return true;
401 }
402 } // namespace StepCore
403 
404 #endif //STEPCORE_WITH_QT
405 
collisionsolver.h
CollisionSolver interface.
world.h
Item, Body, Force and Tool interfaces, World class.
StepCore::XmlFile::_device
QIODevice * _device
Definition: xmlfile.h:64
StepCore::XmlFile::NAMESPACE_URI
static const char * NAMESPACE_URI
Definition: xmlfile.h:69
StepCore::Factory
List of MetaObject.
Definition: factory.h:40
constraintsolver.h
ConstraintSolver interface.
StepCore::XmlFile::VERSION
static const char * VERSION
Definition: xmlfile.h:70
xmlfile.h
XmlFile class.
factory.h
Factory classes.
StepCore::XmlFile::_errorString
QString _errorString
Definition: xmlfile.h:65
solver.h
Solver interface.
StepCore::ItemList
std::vector< Item * > ItemList
List of pointers to Item.
Definition: world.h:298
StepCore::XmlFile::DOCTYPE
static const char * DOCTYPE
Definition: xmlfile.h:68
StepCore::XmlFile::save
bool save(const World *world)
Save world to XML file.
StepCore::XmlFile::load
bool load(World *world, const Factory *factory)
Load world from XML file.
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:43:06 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

step/stepcore

Skip menu "step/stepcore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal