21 #ifdef STEPCORE_WITH_QT
29 #include <QDomDocument>
30 #include <QXmlStreamWriter>
40 class StepStreamWriter
43 StepStreamWriter(QIODevice* device);
44 bool writeWorld(
const World* world);
47 void saveProperties(
const Object* obj,
int first);
48 void saveObject(
const QString& tag,
const Object* obj);
50 QXmlStreamWriter _writer;
52 QHash<const Object*, int> _ids;
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);
70 _writer.writeTextElement(p->name(), QString::number(
id));
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());
85 _writer.writeAttribute(
"id", QString::number(_ids.value(obj, -1)));
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);
160 bool parse(QIODevice* device);
162 const QString& errorMsg()
const {
return _errorMsg; }
165 typedef QPair<QPair<Object*, const MetaProperty*>,
int> Link;
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);
178 const Factory* _factory;
179 QDomDocument _document;
184 QHash<int, Object*> _ids;
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)) {
199 QDomElement worldElement = _document.firstChildElement(
"world");
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;
215 QDomElement solverElement = world.firstChildElement(
"solver");
216 if (!solverElement.isNull()) {
217 Solver *solver = createSolver(solverElement);
218 if (!solver)
return false;
220 _world->setSolver(solver);
223 QDomElement collisionSolverElement = world.firstChildElement(
"collisionSolver");
224 if (!collisionSolverElement.isNull()) {
225 CollisionSolver *solver = createCollisionSolver(collisionSolverElement);
226 if (!solver)
return false;
228 _world->setCollisionSolver(solver);
231 QDomElement constraintSolverElement = world.firstChildElement(
"constraintSolver");
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)
244 QString className = element.attribute(
"class");
245 QScopedPointer<Item> item(_factory->newItem(className));
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)
265 QString className = element.attribute(
"class");
266 QScopedPointer<Solver> solver(_factory->newSolver(className));
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)
279 QString className = element.attribute(
"class");
280 QScopedPointer<CollisionSolver> solver(_factory->newCollisionSolver(className));
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)
293 QString className = element.attribute(
"class");
294 QScopedPointer<ConstraintSolver> solver(_factory->newConstraintSolver(className));
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)
307 QDomElement itemElement = element.firstChildElement(
"item");
308 while (!itemElement.isNull()) {
309 Item *item = createItem(itemElement);
310 if (!item)
return false;
312 parent->addItem(item);
313 itemElement = itemElement.nextSiblingElement(
"item");
319 bool StepDomDocument::parseObject(Object*
object,
const QDomElement& element)
321 int n = element.attribute(
"id").trimmed().toInt();
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());
334 _ids.insert(n,
object);
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();
348 QDomElement propertyElement = parent.firstChildElement(name);
349 if (propertyElement.isNull())
continue;
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));
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) {
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());
388 StepStreamWriter writer(
_device);
389 return writer.writeWorld(world);
394 StepDomDocument document(world, factory);
395 if (!document.parse(
_device)) {
404 #endif //STEPCORE_WITH_QT
CollisionSolver interface.
Item, Body, Force and Tool interfaces, World class.
static const char * NAMESPACE_URI
ConstraintSolver interface.
static const char * VERSION
std::vector< Item * > ItemList
List of pointers to Item.
static const char * DOCTYPE
bool save(const World *world)
Save world to XML file.
bool load(World *world, const Factory *factory)
Load world from XML file.