Warning, file /games/kmuddy/plugins/mapper/filefilters/cmapfilefilterxml.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /*************************************************************************** 0002 cmapfilefilterxml.cpp 0003 ------------------- 0004 begin : Tue Nov 19 2002 0005 copyright : (C) 2002 by Kmud Developer Team 0006 email : kmud-devel@kmud.de 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 #include "cmapfilefilterxml.h" 0019 0020 #include <kmessagebox.h> 0021 #include <KLocalizedString> 0022 #include <kzip.h> 0023 0024 #include <qfile.h> 0025 #include <qdom.h> 0026 #include <qfileinfo.h> 0027 #include <QDebug> 0028 0029 #include <set> 0030 0031 #include "../cmaproom.h" 0032 #include "../cmappath.h" 0033 #include "../cmaptext.h" 0034 #include "../cmapmanager.h" 0035 #include "../cmaplevel.h" 0036 #include "../cmapelementutil.h" 0037 #include "../cmappluginbase.h" 0038 0039 CMapFileFilterXML::CMapFileFilterXML(CMapManager *manager) : CMapFileFilterBase(manager) 0040 { 0041 } 0042 0043 CMapFileFilterXML::~CMapFileFilterXML() 0044 { 0045 } 0046 0047 /** This returns name of the import/export filter. This should be kept small 0048 * @return The Name of the filter */ 0049 QString CMapFileFilterXML::getName(void) 0050 { 0051 return "KMuddy map xml filles (*.mapxml)"; 0052 } 0053 0054 /** This returns a discription of the import/export filter 0055 * @return The discription */ 0056 QString CMapFileFilterXML::getDescription(void) 0057 { 0058 return "KMuddy save/load filter"; 0059 } 0060 0061 /** This returns the extension of the filename that will be loaded,created 0062 * @return The exstension */ 0063 QString CMapFileFilterXML::getExtension(void) 0064 { 0065 return ".mapxml"; 0066 } 0067 0068 /** This returns the pattern extension of the filename that will be loaded,created 0069 * @return The exstension */ 0070 QString CMapFileFilterXML::getPatternExtension(void) 0071 { 0072 return "*" + getExtension(); 0073 } 0074 0075 #include <iostream> 0076 0077 /** This method should be reimplemented if this is a to be a export filter. It 0078 * is called to save the map data 0079 * @param url The url of the file to be saved 0080 * @return 0, The file was saved succesfully 0081 * @return -1, The file could not be created 0082 */ 0083 int CMapFileFilterXML::saveData(const QString &filename) 0084 { 0085 // Create the archive 0086 KZip zip(filename); 0087 if ( !zip.open( QIODevice::WriteOnly ) ) 0088 { 0089 0090 return -1; 0091 } 0092 0093 zip.setCompression(KZip::DeflateCompression); 0094 0095 // Create the xml map file 0096 QString result = saveXMLFile(); 0097 if (!result.isEmpty()) 0098 { 0099 qDebug() << "Write map.xml : " << result.size(); 0100 zip.writeFile("map.xml", result.toLocal8Bit()); 0101 qDebug() << "Done write"; 0102 0103 } 0104 0105 zip.close(); 0106 0107 return result.isEmpty() ? -1 : 0; 0108 } 0109 0110 QString CMapFileFilterXML::saveXMLFile() 0111 { 0112 for (CMapPluginBase *plugin : m_mapManager->getPluginList()) 0113 plugin->saveAboutToStart(); 0114 0115 // Create XML Document and add root node 0116 QDomDocument doc ("kmudmap"); 0117 QDomElement root = doc.createElement ("kmudmap"); 0118 doc.appendChild(root); 0119 0120 // Write version 0121 QDomElement version = doc.createElement("Version"); 0122 version.setAttribute("Major",1); 0123 version.setAttribute("Minor",0); 0124 root.appendChild(version); 0125 0126 // Write main header 0127 0128 // Write the zone 0129 CMapZone *rootZone = m_mapManager->getZone(); 0130 saveZone(&doc,&root,rootZone); 0131 0132 // Write Path Header 0133 QDomElement paths = doc.createElement("Paths"); 0134 root.appendChild(paths); 0135 0136 // Write Links Header 0137 QDomElement links = doc.createElement("Links"); 0138 root.appendChild(links); 0139 0140 // Write Paths 0141 saveZoneLinks(&doc,&paths,&links,m_mapManager->getZone()); 0142 0143 // Write Speedwalk list 0144 0145 // return the result 0146 return doc.toString(); 0147 } 0148 0149 /** 0150 * This method is used to save the zone and all of it's sub elements 0151 * @param doc The document being the elemnts are saved too 0152 * @param rootNode The XML node to save the zone to 0153 * @param zone The zone to save 0154 */ 0155 void CMapFileFilterXML::saveZone(QDomDocument *doc,QDomNode *rootNode,CMapZone *zone) 0156 { 0157 // Save Zone 0158 QDomElement zoneProperties = doc->createElement("Zone"); 0159 zone->saveQDomElement(doc,&zoneProperties); 0160 savePluginPropertiesForElement(zone,doc,&zoneProperties); 0161 0162 for (unsigned int idx = 0; idx < zone->levelCount(); ++idx) 0163 { 0164 CMapLevel *level = zone->getLevel(idx); 0165 QDomElement levelProperties = doc->createElement("Level"); 0166 levelProperties.setAttribute("ID",level->getLevelID()); 0167 levelProperties.setAttribute("Number",level->getNumber()); 0168 levelProperties.setAttribute("Name",level->getName()); 0169 levelProperties.setAttribute("NumRooms",level->getRoomList()->count()); 0170 levelProperties.setAttribute("NumTexts",level->getTextList()->count()); 0171 0172 // Save Rooms 0173 foreach (CMapRoom* room, *level->getRoomList()) 0174 { 0175 QDomElement roomProperties = doc->createElement("Room"); 0176 room->saveQDomElement(doc,&roomProperties); 0177 savePluginPropertiesForElement(room,doc,&roomProperties); 0178 levelProperties.appendChild(roomProperties); 0179 } 0180 0181 // Save Texts 0182 foreach (CMapText* text, *level->getTextList()) 0183 { 0184 QDomElement textProperties = doc->createElement("Text"); 0185 text->saveQDomElement(doc,&textProperties); 0186 savePluginPropertiesForElement(text,doc,&textProperties); 0187 levelProperties.appendChild(textProperties); 0188 } 0189 0190 zoneProperties.appendChild(levelProperties); 0191 } 0192 0193 rootNode->appendChild(zoneProperties); 0194 } 0195 0196 /** 0197 * This method is used to save all the paths in a zone 0198 * @param doc The document being the paths are saved too 0199 * @param rootNode The XML node to save the paths to 0200 * @param zone The zone to save 0201 */ 0202 void CMapFileFilterXML::saveZoneLinks(QDomDocument *doc,QDomElement *pathsNode,QDomElement *linksNode,CMapZone *zone) 0203 { 0204 if (zone == nullptr) 0205 return; 0206 0207 std::set<CMapPath *> saved; // this ensures that we don't save bi-dir paths twice 0208 for (unsigned int idx = 0; idx < zone->levelCount(); ++idx) 0209 { 0210 CMapLevel *level = zone->getLevel(idx); 0211 foreach (CMapRoom *room, *level->getRoomList()) 0212 { 0213 foreach (CMapPath *path, *room->getPathList()) 0214 { 0215 if (saved.count(path)) continue; 0216 QDomElement pathElement = doc->createElement("Path"); 0217 path->saveQDomElement(doc,&pathElement); 0218 savePluginPropertiesForElement(path,doc,&pathElement); 0219 pathsNode->appendChild(pathElement); 0220 saved.insert(path); 0221 } 0222 } 0223 0224 foreach (CMapText *text, *level->getTextList()) 0225 { 0226 CMapElement *element = text->getLinkElement(); 0227 if (element) 0228 { 0229 QDomElement linkElement = doc->createElement("Link"); 0230 0231 linkElement.setAttribute("SrcType",text->getElementType()); 0232 linkElement.setAttribute("SrcLevel",text->getLevel()->getLevelID()); 0233 linkElement.setAttribute("SrcID",text->getTextID()); 0234 linkElement.setAttribute("DestType",element->getElementType()); 0235 linkElement.setAttribute("DestLevel",element->getLevel()->getLevelID()); 0236 if (element->getElementType()==ROOM) 0237 { 0238 linkElement.setAttribute("DestID",((CMapRoom *)element)->getRoomID()); 0239 linkElement.setAttribute("LabelPos",(int)((CMapRoom *)element)->getLabelPosition()); 0240 } 0241 0242 linksNode->appendChild(linkElement); 0243 } 0244 } 0245 } 0246 } 0247 0248 /** This method should be reimplemeted if this is to be a import filter. It is 0249 * called to load the map data 0250 * @param url The url of the file to be loaded 0251 * @return 0 , The file was loaded without problems 0252 * -1 , Could not open the file 0253 * -2 , If the file is corrupt 0254 * -4 , Wrong version 0255 */ 0256 int CMapFileFilterXML::loadData(const QString &filename) 0257 { 0258 KZip zip(filename); 0259 if ( !zip.open( QIODevice::ReadOnly ) ) 0260 { 0261 return -1; 0262 } 0263 0264 int result = -1; 0265 const KArchiveDirectory* dir = zip.directory(); 0266 const KArchiveEntry *e = dir->entry("map.xml"); 0267 if (e->isFile()) 0268 { 0269 const KArchiveFile* mapFile = (KArchiveFile*)e; 0270 0271 if (mapFile) 0272 { 0273 QByteArray arr( mapFile->data() ); 0274 result = loadXMLData(arr); 0275 } 0276 } 0277 0278 zip.close(); 0279 0280 return result; 0281 } 0282 0283 /** This method should be reimplemeted if this is to be a import filter. It is 0284 * called to load the map data 0285 * @param url The url of the file to be loaded 0286 * @return 0 , The file was loaded without problems 0287 * -1 , Could not open the file 0288 * -2 , If the file is corrupt 0289 * -4 , Wrong version 0290 */ 0291 //int CMapFileFilterXML::loadXMLData(QString filename) 0292 int CMapFileFilterXML::loadXMLData(const QByteArray & buffer) 0293 { 0294 // TODO_jp : Make sure Zone ID and level ID max value is set corretly 0295 QDomDocument doc ("map"); 0296 0297 if (!doc.setContent( buffer)) 0298 { 0299 qDebug() << "Unable to open the map file, not a valid xml document"; 0300 // file.close(); 0301 return -1; 0302 } 0303 0304 for (CMapPluginBase *plugin : m_mapManager->getPluginList()) 0305 plugin->loadAboutToStart(); 0306 0307 QDomElement docElem = doc.documentElement(); 0308 0309 // Check that this version of the file can be loaded 0310 QDomElement e = readChildElement(&docElem,"Version"); 0311 if (!e.isNull()) 0312 { 0313 QString major = e.attribute("Major",""); 0314 QString minor = e.attribute("Minor",""); 0315 0316 if (major != "1" || minor != "0") 0317 { 0318 //TODO_jp : Output error message 0319 qDebug() << "This version can't be loaded"; 0320 return -4; 0321 } 0322 } 0323 else 0324 { 0325 //TODO_jp : Output error message 0326 qDebug() << "Unable to find version"; 0327 return -2; 0328 } 0329 0330 // Find Root Zone 0331 QDomElement rootZoneNode = readChildElement(&docElem,"Zone"); 0332 if (rootZoneNode.isNull()) 0333 { 0334 //TODO_jp : Output error message 0335 qDebug() << "Unable to find root zone"; 0336 return -2; 0337 } 0338 0339 // Load Root Zone 0340 int errorZone =loadZone(&rootZoneNode); 0341 0342 if (errorZone!=0) 0343 return errorZone; 0344 0345 // Find Paths 0346 QDomElement pathsNode = readChildElement(&docElem,"Paths"); 0347 if (pathsNode.isNull()) 0348 { 0349 //TODO_jp : Output error message 0350 qDebug() << "Unable to find paths"; 0351 return -2; 0352 } 0353 0354 // Load Paths 0355 int errorPath = loadPaths(&pathsNode); 0356 0357 if (errorPath!=0) 0358 { 0359 return errorPath; 0360 } 0361 0362 // Find Links 0363 QDomElement linksNode = readChildElement(&docElem,"Links"); 0364 if (pathsNode.isNull()) 0365 { 0366 //TODO_jp : Output error message 0367 qDebug() << "Unable to find links"; 0368 return -2; 0369 } 0370 0371 int errorLinks = loadLinks(&linksNode); 0372 if (errorLinks) 0373 return errorLinks; 0374 0375 // Return no error 0376 return 0; 0377 } 0378 0379 /** This method is used to load all of the links 0380 * @param pathsNode The XML node to load the links from 0381 * @return 0 , The file was loaded without problems 0382 * -2 , If the file is corrupt 0383 */ 0384 int CMapFileFilterXML::loadLinks(QDomElement *pathsNode) 0385 { 0386 QDomNode n = pathsNode->firstChild(); 0387 while (!n.isNull() ) 0388 { 0389 QDomElement e = n.toElement(); 0390 0391 if (e.isNull() ) 0392 { 0393 qDebug() << "Unable to find link element "; 0394 return -2; 0395 } 0396 0397 if (e.tagName()=="Link") 0398 { 0399 0400 int srcLevelID = e.attribute("SrcLevel","-2").toInt(); 0401 int destLevelID = e.attribute("DestLevel","-2").toInt(); 0402 0403 if (srcLevelID == -2 || destLevelID == -2) 0404 { 0405 qDebug() << "Unable to find link end points"; 0406 return -2; 0407 } 0408 0409 CMapLevel *srcLevel = m_mapManager->findLevel(srcLevelID); 0410 CMapLevel *destLevel = m_mapManager->findLevel(destLevelID); 0411 0412 0413 int textID = e.attribute("SrcID","-2").toInt(); 0414 int destID = e.attribute("DestID","-2").toInt(); 0415 int labelPos = e.attribute("LabelPos","0").toInt(); 0416 int srcTyp = e.attribute("SrcType","-2").toInt(); 0417 int destTyp = e.attribute("DestType","-2").toInt(); 0418 0419 0420 if (textID == -2 || destID == -2 || destTyp == -2 || srcTyp == -2) 0421 { 0422 qDebug() << "Unable to find link end points"; 0423 return -2; 0424 } 0425 0426 if (srcTyp == (int)TEXT) 0427 { 0428 CMapText *text = srcLevel->findText(textID); 0429 if (destTyp==(int)ROOM) 0430 { 0431 CMapRoom *destElement = destLevel->findRoom(destID); 0432 destElement->setLabelPosition((CMapRoom::labelPosTyp)labelPos,text); 0433 } 0434 } 0435 } 0436 0437 n = n.nextSibling(); 0438 } 0439 0440 return 0; 0441 } 0442 0443 0444 /** This method is used to load all of the paths 0445 * @param pathsNode The XML node to load the paths from 0446 * @return 0 , The file was loaded without problems 0447 * -2 , If the file is corrupt 0448 */ 0449 int CMapFileFilterXML::loadPaths(QDomElement *pathsNode) 0450 { 0451 bool first = true; 0452 QDomNode n; 0453 do { 0454 n = first ? pathsNode->firstChild() : n.nextSibling(); 0455 if (n.isNull()) break; 0456 first = false; 0457 QDomElement e = n.toElement(); 0458 0459 if (e.tagName() != "Path") continue; 0460 0461 int srcLevelID = e.attribute("SrcLevel","-2").toInt(); 0462 int destLevelID = e.attribute("DestLevel","-2").toInt(); 0463 0464 if (srcLevelID == -2 || destLevelID == -2) 0465 { 0466 qDebug() << "Unable to find path end points"; 0467 continue; 0468 } 0469 CMapLevel *srcLevel = m_mapManager->findLevel(srcLevelID); 0470 CMapLevel *destLevel = m_mapManager->findLevel(destLevelID); 0471 0472 int srcRoomID = e.attribute("SrcRoom","-2").toInt(); 0473 int destRoomID = e.attribute("DestRoom","-2").toInt(); 0474 0475 if (destRoomID == -2 || srcRoomID == -2) 0476 { 0477 qDebug() << "Unable to find path end points"; 0478 continue; 0479 } 0480 0481 CMapRoom *srcRoom = srcLevel->findRoom(srcRoomID); 0482 CMapRoom *destRoom = destLevel->findRoom(destRoomID); 0483 0484 if (srcRoom==nullptr || destRoom==nullptr) 0485 { 0486 qDebug() << "Src or Dest room is NULL while creating path"; 0487 continue; 0488 } 0489 0490 directionTyp srcDir = (directionTyp)e.attribute("SrcDir","0").toInt(); 0491 directionTyp destDir = (directionTyp)e.attribute("DestDir","0").toInt(); 0492 QString specialCmd = e.attribute("SpecialCmd", QString()); 0493 0494 if (srcRoom->getPathTarget(srcDir, specialCmd)) 0495 { 0496 qDebug() << "Duplicate path, ignoring"; 0497 continue; 0498 } 0499 0500 CMapPath *path = m_mapManager->createPath(srcRoom,srcDir,destRoom,destDir,false,false); 0501 path->loadQDomElement(&e); 0502 loadPluginPropertiesForElement(path,&e); 0503 } while (!n.isNull()); 0504 qDebug() << "loadPaths Here 4"; 0505 0506 return 0; 0507 } 0508 0509 /** 0510 * This method is used to load the zone and all of it's sub elememnts 0511 * @param zoneNode The XML node to load the zone from 0512 * @param intoLevel The level to create the zone in 0513 * @return 0 , The file was loaded without problems 0514 * -2 , If the file is corrupt 0515 */ 0516 int CMapFileFilterXML::loadZone(QDomElement *zoneNode) 0517 { 0518 // Wipe the default level. 0519 while (m_mapManager->getZone()->levelCount()) 0520 delete m_mapManager->getZone()->firstLevel(); 0521 0522 QDomNode n = zoneNode->firstChild(); 0523 while (!n.isNull() ) 0524 { 0525 QDomElement e = n.toElement(); 0526 0527 if (e.isNull() ) 0528 { 0529 qDebug() << "Unable to find element "; 0530 return -2; 0531 } 0532 0533 if (e.tagName()=="Level") 0534 { 0535 CMapLevel *level = m_mapManager->createLevel(UP); 0536 QString id = e.attribute("ID","-2"); 0537 if (id=="-2") 0538 { 0539 qDebug() << "Unable to find level ID"; 0540 return -2; 0541 } 0542 level->setLevelID(id.toInt()); 0543 level->setName(e.attribute("Name", "")); 0544 0545 QDomNode n2 = e.firstChild(); 0546 while (!n2.isNull() ) 0547 { 0548 QDomElement e2 = n2.toElement(); 0549 0550 if (e2.isNull() ) 0551 { 0552 qDebug() << "Unable to find element "; 0553 return -2; 0554 } 0555 0556 int x1 = e2.attribute("X",QString::number(-1)).toInt(); 0557 int y1 = e2.attribute("Y",QString::number(-1)).toInt(); 0558 0559 if (x1==-1 || y1==-1) 0560 { 0561 qDebug() << "Unable to find pos "; 0562 return -2; 0563 } 0564 0565 if (e2.tagName()=="Room") 0566 { 0567 CMapRoom *room = CMapElementUtil::createRoom(m_mapManager, QPoint(x1, y1),level); 0568 if (!room) { 0569 qWarning()<<"NO ROOM AT "<<x1<<"/"<<y1<<" on level "<<id<<" WHEN LOADING ROOM #"<<e2.attribute("RoomID",QString::number(-1)).toInt(); 0570 n2 = n2.nextSibling(); 0571 continue; 0572 } 0573 0574 room->loadQDomElement(&e2); 0575 loadPluginPropertiesForElement(room,&e2); 0576 } 0577 else if (e2.tagName()=="Text") 0578 { 0579 CMapText *text = CMapElementUtil::createText(m_mapManager, QPoint (x1,y1),level,""); 0580 if (!text) { 0581 qDebug() << "Unable to create text"; 0582 n2 = n2.nextSibling(); 0583 continue; 0584 } 0585 text->loadQDomElement(&e2); 0586 loadPluginPropertiesForElement(text,&e2); 0587 } 0588 else 0589 { 0590 qDebug() << "Unknown Type : " << e2.tagName(); 0591 } 0592 0593 n2 = n2.nextSibling(); 0594 } 0595 } 0596 0597 0598 n = n.nextSibling(); 0599 } 0600 0601 return 0; 0602 } 0603 0604 /** 0605 * This method is used to read a child XML object of a XML object 0606 * @param parent The parent XML object 0607 * @param key The name of the child 0608 * @return The child node 0609 */ 0610 QDomElement CMapFileFilterXML::readChildElement(QDomElement *parent,QString key) 0611 { 0612 QDomElement e; 0613 0614 // Find Root Zone 0615 QDomNode n = parent->namedItem(key); 0616 if (n.isNull()) 0617 { 0618 e.clear(); 0619 return e; 0620 } 0621 0622 e = n.toElement(); 0623 0624 return e; 0625 } 0626 0627 /** 0628 * This method is used to save element properties that are stored in plugins 0629 * @param element The element being saved 0630 * @param doc The XML document 0631 * @param elProperties The xml properties of the element 0632 */ 0633 void CMapFileFilterXML::savePluginPropertiesForElement(CMapElement *element,QDomDocument *doc,QDomElement *elProperties) 0634 { 0635 typedef QMap<QString, QString> EntryMap; 0636 0637 QDomElement pluginsNode = doc->createElement ("plugins"); 0638 0639 0640 for (CMapPluginBase *plugin : m_mapManager->getPluginList()) 0641 { 0642 QDomElement pNode = doc->createElement(plugin->tagName()); 0643 KMemConfig pluginProperties; 0644 plugin->saveElementProperties(element,&pluginProperties); 0645 0646 EntryMap entries = pluginProperties.entryMap("Properties"); 0647 for (EntryMap::ConstIterator it = entries.constBegin(); it != entries.constEnd(); ++it) 0648 { 0649 pNode.setAttribute(it.key(),it.value()); 0650 } 0651 0652 pluginsNode.appendChild(pNode); 0653 } 0654 0655 elProperties->appendChild(pluginsNode); 0656 } 0657 0658 /** 0659 * This method is used to load element properties that are stored in plugins 0660 * @param element The Element being loaded 0661 * @param elProperties the xml properties of the element 0662 */ 0663 void CMapFileFilterXML::loadPluginPropertiesForElement(CMapElement *element,QDomElement *elProperties) 0664 { 0665 QDomElement pluginsNode = readChildElement(elProperties,"plugins"); 0666 if (!pluginsNode.isNull()) 0667 { 0668 QDomNode n = pluginsNode.firstChild(); 0669 while (!n.isNull() ) 0670 { 0671 0672 QDomElement e = n.toElement(); 0673 0674 if (!e.isNull() ) 0675 { 0676 for (CMapPluginBase *plugin : m_mapManager->getPluginList()) 0677 { 0678 if (plugin->tagName()==e.tagName()) 0679 { 0680 KMemConfig pluginProperties; 0681 0682 QDomNamedNodeMap attribs = e.attributes(); 0683 0684 for (int i=0; i<attribs.length();i++) 0685 { 0686 QDomNode n2 = attribs.item(i); 0687 0688 qDebug() << "Attrib " << n2.nodeName() << " = " << n2.nodeValue(); 0689 pluginProperties.group("Properties").writeEntry(n2.nodeName(),n2.nodeValue()); 0690 0691 } 0692 0693 plugin->loadElementProperties(element,&pluginProperties); 0694 break; 0695 } 0696 } 0697 } 0698 0699 n = n.nextSibling(); 0700 } 0701 } 0702 }