File indexing completed on 2024-12-01 06:51:46

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