File indexing completed on 2023-10-03 03:28:40

0001 /********************************************f*******************************
0002                              cmapzonemanager.cpp
0003                              -------------------
0004     begin                : Sat Aug 15, 2015
0005     copyright            : (C) 2015 Tomas Mecir
0006     email                : mecirt@gmail.com
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 "cmapzonemanager.h"
0019 
0020 #include <QStandardItemModel>
0021 #include <QDir>
0022 #include <QXmlStreamReader>
0023 #include <QXmlStreamWriter>
0024 #include <kdebug.h>
0025 #include <klocale.h>
0026 #include <kmessagebox.h>
0027 
0028 #include "cmapmanager.h"
0029 #include "cprofilemanager.h"
0030 
0031 struct CMapZoneManager::Private {
0032   QStandardItemModel zones;
0033   int sessId;
0034   CMapManager *manager;
0035   int currentZone;
0036 };
0037 
0038 
0039 CMapZoneManager::CMapZoneManager(int sessId, CMapManager *manager)
0040 {
0041   d = new Private;
0042   d->sessId = sessId;
0043   d->manager = manager;
0044   d->currentZone = -1;
0045   loadMapList();
0046 }
0047 
0048 CMapZoneManager::~CMapZoneManager()
0049 {
0050   for (int i = 0; i < d->zones.rowCount(); ++i)
0051     delete getZoneEntry(i);
0052 
0053   delete d;
0054 }
0055 
0056 
0057 QStandardItemModel *CMapZoneManager::zonesModel()
0058 {
0059   return &d->zones;
0060 }
0061 
0062 QString CMapZoneManager::getPath(int idx)
0063 {
0064   cZoneInformation *i = getZoneEntry(idx);
0065   if (!i) return QString();
0066 
0067   cProfileManager *pm = cProfileManager::self();
0068   if (!pm->settings(d->sessId)) return QString();
0069   
0070   QString path = pm->profilePath (d->sessId) + "/maps/";
0071   QDir dir = QDir (path);
0072   if (!dir.exists()) QDir::root().mkpath (dir.absolutePath());
0073   return path + "/" + i->file;
0074 }
0075 
0076 void CMapZoneManager::save(bool always)
0077 {
0078   // first save the current zone
0079   QString savePath = getPath (d->currentZone);
0080   if (!savePath.length()) return;
0081 
0082   CMapFileFilterBase *filter = d->manager->nativeFilter(false);
0083   if (filter && (always || (!d->manager->isClean())))
0084     d->manager->exportMap (savePath, filter);
0085 }
0086 
0087 void CMapZoneManager::loadZone(int idx)
0088 {
0089   if (d->currentZone == idx) return;
0090 
0091   save(true);
0092   
0093   // and load, replacing the existing data
0094   QString loadPath = getPath(idx);
0095   CMapFileFilterBase *filter = d->manager->nativeFilter(true);
0096   if (filter) {
0097     d->currentZone = idx;
0098     d->manager->importMap (loadPath, filter);
0099   }
0100 }
0101 
0102 void CMapZoneManager::deleteZone(int idx)
0103 {
0104   cZoneInformation *i = getZoneEntry(idx);
0105   if (!i) return;
0106 
0107   // wipe the data, if loaded
0108   if (idx == d->currentZone)
0109     d->manager->eraseMap();
0110 
0111   // wipe the file
0112   QString fName = getPath(idx);
0113   QFile f(fName);
0114   f.remove();
0115 
0116   // wipe the record and the model entry
0117   d->zones.removeRows(idx, 1);
0118   delete i;
0119 
0120   if (!d->zones.rowCount())
0121     createZone (i18n ("Map #1"));
0122 
0123   // and load whichever zone is next, if this one was the current one
0124   // TODO: won't this happen automatically?
0125   d->currentZone = -1;
0126   loadZone(0);
0127 
0128   saveMapList();
0129 }
0130 
0131 void CMapZoneManager::createZone(const QString &name, const QString &file)
0132 {
0133   // generate file name if needed
0134   QString fName = file;
0135   if (!fName.length()) {
0136     cProfileManager *pm = cProfileManager::self();
0137     if (!pm->settings(d->sessId)) fName = "map.xml";
0138     else
0139     {
0140       int id = 1;
0141       QString path = pm->profilePath (d->sessId) + "/maps/";
0142       do {
0143         QFile f(path + QString::number(id) + ".xml");
0144         if (!f.exists()) break;
0145         id++;
0146       } while (1);
0147       fName = QString::number(id) + ".xml";
0148     }
0149   }
0150 
0151   int id = createZoneEntry(name, fName);
0152   loadZone(id);
0153 
0154   saveMapList();
0155 }
0156 
0157 void CMapZoneManager::renameZone(int idx, const QString &name)
0158 {
0159   QStandardItem *item = d->zones.item(idx, 0);
0160   if (item && (item->text() != name)) item->setText(name);
0161   cZoneInformation *i = getZoneEntry(idx);
0162   if (i) i->name = name;
0163 }
0164 
0165 int CMapZoneManager::createZoneEntry(const QString &name, const QString &file)
0166 {
0167   cZoneInformation *i = new cZoneInformation;
0168   i->name = name;
0169   i->file = file;
0170 
0171   QStandardItem *item = new QStandardItem(name);
0172   item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
0173   item->setData(QVariant(qVariantFromValue((void *) i)), Qt::UserRole + 1);
0174 
0175   d->zones.appendRow(item);
0176   return d->zones.rowCount() - 1;
0177 }
0178 
0179 cZoneInformation *CMapZoneManager::getZoneEntry(int idx)
0180 {
0181   QModelIndex index = d->zones.index(idx, 0);
0182   if (!index.isValid()) return nullptr;
0183   cZoneInformation *i = static_cast<cZoneInformation*>(index.data(Qt::UserRole + 1).value<void *>());
0184   return i;
0185 }
0186 
0187 int CMapZoneManager::activeZone() {
0188   return d->currentZone;
0189 }
0190 
0191 void CMapZoneManager::loadMapList()
0192 {
0193   cProfileManager *pm = cProfileManager::self();
0194   if (!pm->settings(d->sessId)) return;
0195 
0196   d->zones.clear();
0197   QString path = pm->profilePath (d->sessId);
0198   QDir dir = QDir (path);
0199   if (!dir.exists()) QDir::root().mkpath (dir.absolutePath());
0200   QString fName = "maps.xml";
0201 
0202   QFile f (path + "/" + fName);
0203   if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
0204     kDebug() << "No " << fName << " file - nothing to do." << endl;
0205     return;
0206   }
0207 
0208   QXmlStreamReader *reader = new QXmlStreamReader (&f);
0209 
0210   reader->readNext ();  // read the document start
0211   reader->readNext ();
0212   if (reader->isStartElement ())
0213     if (reader->name() == "maps")
0214       if (reader->attributes().value ("version") == "1.0") {
0215         // all is well, we can start loading the list
0216         while (!reader->atEnd()) {
0217           reader->readNext ();
0218     
0219           if (reader->isEndElement() && (reader->name() == "maps")) break;
0220 
0221           if (reader->isStartElement () && (reader->name() == "map")) {
0222             QString name = reader->attributes().value ("name").toString();
0223             QString file = reader->attributes().value ("file").toString();
0224             createZoneEntry(name, file);
0225           }
0226         }
0227       }
0228       else
0229         reader->raiseError (i18n ("This file was created by a newer version of KMuddy, and this version is unable to open it."));
0230     else
0231       reader->raiseError (i18n ("This is not a KMuddy map list."));
0232   else if (!reader->hasError())
0233     reader->raiseError (i18n ("This file is corrupted."));
0234 
0235   if (reader->hasError()) {
0236     kDebug() << i18n ("Error at line %1, column %2: %3",
0237                             QString::number (reader->lineNumber()),
0238                             QString::number (reader->columnNumber()),
0239                             reader->errorString());
0240   }
0241 
0242   d->zones.sort(0);  // not perfect, we should sort on the go, but as this class operates by indexes, it'll have to do for now
0243 
0244   f.close ();
0245   delete reader;
0246 }
0247 
0248 
0249 void CMapZoneManager::saveMapList()
0250 {
0251   // save the list contents
0252   cProfileManager *pm = cProfileManager::self();
0253   if (!pm->settings(d->sessId)) return;
0254 
0255   QString path = pm->profilePath (d->sessId);
0256   QDir dir = QDir (path);
0257   if (!dir.exists()) QDir::root().mkpath (dir.absolutePath());
0258   QString fName = "maps.xml";
0259 
0260   dir.remove ("maps.backup");
0261   if (!QFile(path + "/" + fName).copy (path + "/" + "maps.backup")) {
0262     kDebug() << "Unable to backup " << fName << endl;  // not fatal, may simply not exist
0263   }
0264 
0265   QFile f (path + "/" + fName);
0266   if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
0267     kDebug() << "Unable to open " << (path + "/" + fName) << " for writing." << endl;
0268     return;  // problem
0269   }
0270 
0271   QXmlStreamWriter *writer = new QXmlStreamWriter (&f);
0272   writer->setAutoFormatting (true);  // make the generated XML more readable
0273 
0274   writer->writeStartDocument ();
0275   writer->writeStartElement ("maps");
0276   writer->writeAttribute ("version", "1.0");
0277 
0278   for (int i = 0; i < d->zones.rowCount(); ++i) {
0279     cZoneInformation *zi = getZoneEntry(i);
0280     if (!zi) continue;
0281 
0282     writer->writeStartElement ("map");
0283     writer->writeAttribute ("name", zi->name);
0284     writer->writeAttribute ("file", zi->file);
0285     writer->writeEndElement ();  // end the map element
0286   }
0287 
0288   writer->writeEndElement ();  // end the maps element
0289   writer->writeEndDocument ();
0290 
0291   f.close ();
0292   delete writer;
0293 }
0294