21 #ifdef STEPCORE_WITH_QT
29 #include <QDomDocument>
30 #include <QXmlStreamWriter>
40 class StepStreamWriter
44 bool writeWorld(
const World* world);
47 void saveProperties(
const Object* obj,
int first);
48 void saveObject(
const QString& tag,
const Object* obj);
53 static const int INDENT = 4;
56 StepStreamWriter::StepStreamWriter(
QIODevice* device) : _device(device)
58 _writer.setAutoFormatting(
true);
59 _writer.setAutoFormattingIndent(INDENT);
62 void StepStreamWriter::saveProperties(
const Object* obj,
int first)
64 const MetaObject* metaObject = obj->metaObject();
65 for(
int i = first; i < metaObject->propertyCount(); ++i) {
66 const MetaProperty* p = metaObject->property(i);
68 if(p->userTypeId() == qMetaTypeId<Object*>()) {
69 int id = _ids.value(p->readVariant(obj).value<Object*>(), -1);
73 _writer.writeTextElement(p->name(), p->readString(obj));
79 void StepStreamWriter::saveObject(
const QString& tag,
const Object* obj)
81 Q_ASSERT(obj != NULL);
83 _writer.writeStartElement(tag);
84 _writer.writeAttribute(
"class", obj->metaObject()->className());
87 saveProperties(obj, 0);
89 if(obj->metaObject()->inherits<Item>()) {
90 const ObjectErrors* objErrors =
static_cast<const Item*
>(obj)->tryGetObjectErrors();
91 if(objErrors) saveProperties(objErrors, 1);
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);
102 _writer.writeEndElement();
105 bool StepStreamWriter::writeWorld(
const World* world)
107 Q_ASSERT(_device->isOpen() && _device->isWritable());
108 _writer.setDevice(_device);
111 _ids.insert(NULL, ++maxid);
112 _ids.insert(world, ++maxid);
115 const ItemList::const_iterator end0 = items.end();
116 for(ItemList::const_iterator it = items.begin(); it != end0; ++it)
117 _ids.insert(*it, ++maxid);
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);
123 _writer.writeStartDocument();
125 _writer.writeStartElement(
"world");
128 _writer.writeAttribute(
"id",
"1");
130 saveProperties(world, 0);
132 ItemList::const_iterator end = world->items().end();
133 for(ItemList::const_iterator it = world->items().begin(); it != end; ++it) {
134 saveObject(
"item", *it);
137 if(world->solver()) {
138 saveObject(
"solver", world->solver());
141 if(world->collisionSolver()) {
142 saveObject(
"collisionSolver", world->collisionSolver());
145 if(world->constraintSolver()) {
146 saveObject(
"constraintSolver", world->constraintSolver());
149 _writer.writeEndElement();
150 _writer.writeEndDocument();
155 class StepDomDocument
158 StepDomDocument(World* world,
const Factory* factory);
162 const QString& errorMsg()
const {
return _errorMsg; }
169 CollisionSolver* createCollisionSolver(
const QDomElement& element);
170 ConstraintSolver* createConstraintSolver(
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);
178 const Factory* _factory;
188 StepDomDocument::StepDomDocument(World* world,
const StepCore::Factory* factory) :
189 _world(world), _factory(factory), _errorLine(0), _errorCount(0)
193 bool StepDomDocument::parse(
QIODevice* device)
195 if (!_document.setContent(device, &_errorMsg, &_errorLine, &_errorCount)) {
200 if (worldElement.
isNull()) {
201 _errorMsg =
QObject::tr(
"The file is not a StepCoreXML file.");
205 return parseWorld(worldElement);
208 bool StepDomDocument::parseWorld(
const QDomElement& world)
210 _version = world.
attribute(
"version",
"1.0");
212 if (!parseObject(_world, world))
return false;
213 if (!parseItems(_world, world))
return false;
216 if (!solverElement.
isNull()) {
217 Solver *solver = createSolver(solverElement);
218 if (!solver)
return false;
220 _world->setSolver(solver);
224 if (!collisionSolverElement.
isNull()) {
225 CollisionSolver *solver = createCollisionSolver(collisionSolverElement);
226 if (!solver)
return false;
228 _world->setCollisionSolver(solver);
232 if (!constraintSolverElement.
isNull()) {
233 ConstraintSolver *solver = createConstraintSolver(constraintSolverElement);
234 if (!solver)
return false;
236 _world->setConstraintSolver(solver);
239 return connectLinks();
242 Item* StepDomDocument::createItem(
const QDomElement& element)
247 _errorMsg =
QObject::tr(
"Unknown item type \"%1\"").
arg(className);
251 if (!parseObject(item.data(), element))
return 0;
252 ObjectErrors *objErrors = item->objectErrors();
253 if (objErrors && !parseProperties(objErrors, element))
return 0;
255 if (item->metaObject()->inherits(
"ItemGroup")) {
256 ItemGroup *group =
static_cast<ItemGroup*
>(item.data());
257 if (!parseItems(group, element))
return 0;
263 Solver* StepDomDocument::createSolver(
const QDomElement& element)
268 _errorMsg =
QObject::tr(
"Unknown solver type \"%1\"").
arg(className);
272 if (!parseObject(solver.data(), element))
return 0;
274 return solver.take();
277 CollisionSolver* StepDomDocument::createCollisionSolver(
const QDomElement& element)
282 _errorMsg =
QObject::tr(
"Unknown collisionSolver type \"%1\"").
arg(className);
286 if (!parseObject(solver.data(), element))
return 0;
288 return solver.take();
291 ConstraintSolver* StepDomDocument::createConstraintSolver(
const QDomElement& element)
296 _errorMsg =
QObject::tr(
"Unknown constraint solver type \"%1\"").
arg(className);
300 if (!parseObject(solver.data(), element))
return 0;
302 return solver.take();
305 bool StepDomDocument::parseItems(ItemGroup* parent,
const QDomElement& element)
308 while (!itemElement.
isNull()) {
309 Item *item = createItem(itemElement);
310 if (!item)
return false;
312 parent->addItem(item);
319 bool StepDomDocument::parseObject(Object*
object,
const QDomElement& element)
324 _errorMsg =
QObject::tr(
"Wrong ID attribute value for %1")
325 .
arg(object->metaObject()->className());
328 if (_ids.contains(n)) {
329 _errorMsg =
QObject::tr(
"Non-unique ID attribute value for %1")
330 .
arg(object->metaObject()->className());
336 return parseProperties(
object, element);
339 bool StepDomDocument::parseProperties(Object*
object,
const QDomElement& parent)
341 int properties =
object->metaObject()->propertyCount();
342 for (
int n = 0; n < properties; ++n) {
343 const MetaProperty*
property =
object->metaObject()->property(n);
345 if (!property->isStored())
continue;
347 QString name =
property->name();
349 if (propertyElement.
isNull())
continue;
352 if (property->userTypeId() == qMetaTypeId<Object*>()) {
354 _links.push_back(qMakePair(qMakePair(
object, property), n));
356 else if (!property->writeString(
object, text)) {
357 _errorMsg =
QObject::tr(
"Property \"%1\" of \"%2\" has illegal value")
358 .
arg(name, object->metaObject()->className());
366 bool StepDomDocument::connectLinks()
368 foreach (
const Link& link, _links) {
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());
388 StepStreamWriter writer(
_device);
389 return writer.writeWorld(world);
394 StepDomDocument document(world, factory);
395 if (!document.parse(
_device)) {
404 #endif //STEPCORE_WITH_QT
QString attribute(const QString &name, const QString &defValue) const
QDomElement nextSiblingElement(const QString &tagName) const
QString tr(const char *sourceText, const char *disambiguation, int n)
CollisionSolver interface.
Item, Body, Force and Tool interfaces, World class.
QString number(int n, int base)
static const char * NAMESPACE_URI
QString & insert(int position, QChar ch)
int toInt(bool *ok, int base) const
ConstraintSolver interface.
static const char * VERSION
QVariant fromValue(const T &value)
std::vector< Item * > ItemList
List of pointers to Item.
static const char * DOCTYPE
QDomElement firstChildElement(const QString &tagName) const
bool save(const World *world)
Save world to XML file.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
bool load(World *world, const Factory *factory)
Load world from XML file.