MapModel, various cleanups. TODO/FIXME: QComboBox separator not working with custom models
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/model/MapModel.cpp Fri Apr 27 11:47:37 2012 +0200
@@ -0,0 +1,190 @@
+
+#include "MapModel.h"
+
+MapModel::MapInfo MapModel::mapInfoFromData(const QVariant data)
+{
+ MapInfo mapInfo;
+
+ mapInfo.type = Invalid;
+ mapInfo.name = "";
+ mapInfo.theme = "";
+ mapInfo.limit = 0;
+ mapInfo.scheme = "";
+ mapInfo.weapons = "";
+
+ if (data.isValid())
+ {
+ QList<QVariant> list = data.toList();
+ if (list.size() < 1) {
+ mapInfo.type = Invalid;
+ return mapInfo;
+ }
+ mapInfo.type = (MapType)list[0].toInt();
+ switch (mapInfo.type)
+ {
+ case GeneratedMap:
+ case GeneratedMaze:
+ case HandDrawnMap:
+ return mapInfo;
+
+ default:
+ mapInfo.name = list[1].toString();
+ mapInfo.theme = list[2].toString();
+ mapInfo.limit = list[3].toInt();
+ mapInfo.scheme = list[4].toString();
+ mapInfo.weapons = list[5].toString();
+ }
+ }
+
+ return mapInfo;
+}
+
+MapModel::MapModel(QObject *parent) :
+ QAbstractListModel(parent)
+{
+ m_data = QList<QMap<int, QVariant> >();
+}
+
+int MapModel::rowCount(const QModelIndex &parent) const
+{
+ if(parent.isValid())
+ return 0;
+ else
+ return m_data.size();
+}
+
+
+QVariant MapModel::data(const QModelIndex &index, int role) const
+{
+ if(index.column() > 0 || index.row() >= m_data.size())
+ return QVariant();
+ else
+ return m_data.at(index.row()).value(role, QVariant());
+}
+
+
+void MapModel::loadMaps()
+{
+ beginResetModel();
+
+
+ DataManager & datamgr = DataManager::instance();
+
+ QStringList maps =
+ datamgr.entryList("Maps", QDir::AllDirs | QDir::NoDotAndDotDot);
+
+ m_data.clear();
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ m_data.reserve(maps.size());
+#endif
+
+ QMap<int, QVariant> tmp;
+ QList<QVariant> mapInfo;
+
+ // TODO: icons for these
+ tmp.insert(Qt::DisplayRole, QComboBox::tr("generated map..."));
+ mapInfo.append(GeneratedMap);
+ tmp.insert(Qt::UserRole, mapInfo);
+ m_data.append(tmp);
+ tmp.insert(Qt::DisplayRole, QComboBox::tr("generated maze..."));
+ mapInfo.replace(0, GeneratedMaze);
+ tmp.insert(Qt::UserRole, mapInfo);
+ m_data.append(tmp);
+ tmp.insert(Qt::DisplayRole, QComboBox::tr("hand drawn map..."));
+ mapInfo.replace(0, HandDrawnMap);
+ tmp.insert(Qt::UserRole, mapInfo);
+ m_data.append(tmp);
+
+ m_nGenerators = 3;
+
+
+ m_nMissions = 0;
+
+ QFile mapLuaFile;
+ QFile mapCfgFile;
+
+ foreach (QString map, maps)
+ {
+ mapCfgFile.setFileName(
+ datamgr.findFileForRead(QString("Maps/%1/map.cfg").arg(map)));
+ mapLuaFile.setFileName(
+ datamgr.findFileForRead(QString("Maps/%1/map.lua").arg(map)));
+
+ QMap<int, QVariant> dataset;
+
+
+ if (mapCfgFile.open(QFile::ReadOnly))
+ {
+ QString theme;
+ quint32 limit = 0;
+ QString scheme;
+ QString weapons;
+ QList<QVariant> mapInfo;
+ bool isMission = mapLuaFile.exists();
+ int type = isMission?MissionMap:StaticMap;
+
+ QTextStream input(&mapCfgFile);
+ input >> theme;
+ input >> limit;
+ input >> scheme;
+ input >> weapons;
+ mapInfo.push_back(type);
+ mapInfo.push_back(map);
+ mapInfo.push_back(theme);
+ if (limit)
+ mapInfo.push_back(limit);
+ else
+ mapInfo.push_back(18);
+
+
+ if (scheme.isEmpty())
+ scheme = "locked";
+ scheme.replace("_", " ");
+
+ if (weapons.isEmpty())
+ weapons = "locked";
+ weapons.replace("_", " ");
+
+ mapInfo.push_back(scheme);
+ mapInfo.push_back(weapons);
+
+ if(isMission)
+ {
+ // TODO: icon
+ map = QComboBox::tr("Mission") + ": " + map;
+ m_nMissions++;
+ }
+
+ mapCfgFile.close();
+
+ // set name
+ dataset.insert(Qt::DisplayRole, map);
+
+ // TODO
+ // dataset.insert(Qt::DecorationRole, icon);
+
+ // set mapinfo
+ dataset.insert(Qt::UserRole, mapInfo);
+
+ if (isMission) // insert missions before regular maps
+ m_data.insert(m_nGenerators + m_nMissions, dataset);
+ else
+ m_data.append(dataset);
+
+ }
+
+ }
+
+ endResetModel();
+}
+
+int MapModel::generatorCount() const
+{
+ return m_nGenerators;
+}
+
+int MapModel::missionCount() const
+{
+ return m_nMissions;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/model/MapModel.h Fri Apr 27 11:47:37 2012 +0200
@@ -0,0 +1,88 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2006-2007 Igor Ulyanov <iulyanov@gmail.com>
+ * Copyright (c) 2007-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+/**
+ * @file
+ * @brief MapModel class definition
+ */
+
+#ifndef HEDGEWARS_MAPMODEL_H
+#define HEDGEWARS_MAPMODEL_H
+
+#include <QAbstractListModel>
+#include <QStringList>
+#include <QTextStream>
+#include <QMap>
+#include <QIcon>
+#include <QComboBox>
+
+#include "DataManager.h"
+
+/**
+ * @brief A model listing available themes
+ *
+ * @author sheepluva
+ * @since 0.9.18
+ */
+class MapModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ public:
+ enum MapType {
+ Invalid,
+ GeneratedMap,
+ GeneratedMaze,
+ HandDrawnMap,
+ MissionMap,
+ StaticMap
+ };
+
+ struct MapInfo
+ {
+ MapType type;
+ QString name;
+ QString theme;
+ quint32 limit;
+ QString scheme;
+ QString weapons;
+ };
+
+ static MapInfo mapInfoFromData(const QVariant data);
+
+ explicit MapModel(QObject *parent = 0);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ int generatorCount() const;
+ int missionCount() const;
+
+
+ public slots:
+ /// reloads the maps from the DataManager
+ void loadMaps();
+
+
+ private:
+ QList<QMap<int, QVariant> > m_data;
+ int m_nGenerators;
+ int m_nMissions;
+};
+
+#endif // HEDGEWARS_MAPMODEL_H
--- a/QTfrontend/ui/widget/mapContainer.cpp Thu Apr 26 16:15:37 2012 +0200
+++ b/QTfrontend/ui/widget/mapContainer.cpp Fri Apr 27 11:47:37 2012 +0200
@@ -68,11 +68,12 @@
chooseMap = new QComboBox(mapWidget);
chooseMap->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_mapModel = DataManager::instance().mapModel();
+ chooseMap->setModel(m_mapModel);
- loadMapList();
- connect(&DataManager::instance(), SIGNAL(updated()), this, SLOT(loadMapList()));
+ // update model views after model changes (to e.g. re-adjust separators)
+ connect(&DataManager::instance(), SIGNAL(updated()), this, SLOT(updateModelViews()));
- connect(chooseMap, SIGNAL(activated(int)), this, SLOT(mapChanged(int)));
mapLayout->addWidget(chooseMap, 1, 1);
QLabel * lblMap = new QLabel(tr("Map"), mapWidget);
@@ -172,6 +173,13 @@
setRandomSeed();
setRandomTheme();
+
+ chooseMap->setCurrentIndex(0);
+ m_mapInfo = MapModel::mapInfoFromData(chooseMap->itemData(0));
+ mapChanged(0);
+ connect(chooseMap, SIGNAL(activated(int)), this, SLOT(mapChanged(int)));
+
+ updateModelViews();
}
void HWMapContainer::setImage(const QImage newImage)
@@ -202,9 +210,11 @@
void HWMapContainer::mapChanged(int index)
{
- switch(index)
+ m_mapInfo = MapModel::mapInfoFromData(chooseMap->itemData(chooseMap->currentIndex()));
+
+ switch(m_mapInfo.type)
{
- case MAPGEN_REGULAR:
+ case MapModel::GeneratedMap:
mapgen = MAPGEN_REGULAR;
updatePreview();
gbThemes->show();
@@ -213,9 +223,9 @@
maze_size_label->hide();
cbMazeSize->hide();
emit mapChanged("+rnd+");
- emit themeChanged(chooseMap->itemData(index).toList()[1].toString());
+ emit themeChanged(m_mapInfo.theme);
break;
- case MAPGEN_MAZE:
+ case MapModel::GeneratedMaze:
mapgen = MAPGEN_MAZE;
updatePreview();
gbThemes->show();
@@ -224,9 +234,9 @@
maze_size_label->show();
cbMazeSize->show();
emit mapChanged("+maze+");
- emit themeChanged(chooseMap->itemData(index).toList()[1].toString());
+ emit themeChanged(m_mapInfo.theme);
break;
- case MAPGEN_DRAWN:
+ case MapModel::HandDrawnMap:
mapgen = MAPGEN_DRAWN;
updatePreview();
gbThemes->show();
@@ -235,7 +245,7 @@
maze_size_label->hide();
cbMazeSize->hide();
emit mapChanged("+drawn+");
- emit themeChanged(chooseMap->itemData(index).toList()[1].toString());
+ emit themeChanged(m_mapInfo.theme);
break;
default:
mapgen = MAPGEN_MAP;
@@ -245,7 +255,7 @@
cbTemplateFilter->hide();
maze_size_label->hide();
cbMazeSize->hide();
- emit mapChanged(chooseMap->itemData(index).toList()[0].toString());
+ emit mapChanged(m_mapInfo.name);
}
emit mapgenChanged(mapgen);
@@ -316,19 +326,17 @@
QString HWMapContainer::getCurrentMap() const
{
- if(chooseMap->currentIndex() < MAPGEN_MAP) return QString();
- return chooseMap->itemData(chooseMap->currentIndex()).toList()[0].toString();
+ return(m_mapInfo.name);
}
QString HWMapContainer::getCurrentTheme() const
{
- return chooseMap->itemData(chooseMap->currentIndex()).toList()[1].toString();
+ return(m_mapInfo.theme);
}
bool HWMapContainer::getCurrentIsMission() const
{
- if(!chooseMap->currentIndex()) return false;
- return chooseMap->itemData(chooseMap->currentIndex()).toList()[3].toBool();
+ return(m_mapInfo.type == MapModel::MissionMap);
}
int HWMapContainer::getCurrentHHLimit() const
@@ -338,12 +346,12 @@
QString HWMapContainer::getCurrentScheme() const
{
- return chooseMap->itemData(chooseMap->currentIndex()).toList()[4].toString();
+ return(m_mapInfo.scheme);
}
QString HWMapContainer::getCurrentWeapons() const
{
- return chooseMap->itemData(chooseMap->currentIndex()).toList()[5].toString();
+ return(m_mapInfo.weapons);
}
quint32 HWMapContainer::getTemplateFilter() const
@@ -367,7 +375,7 @@
void HWMapContainer::setSeed(const QString & seed)
{
intSetSeed(seed);
- if (chooseMap->currentIndex() < MAPGEN_DRAWN)
+ if ((m_mapInfo.type == MapModel::GeneratedMap) || (m_mapInfo.type == MapModel::GeneratedMaze))
updatePreview();
}
@@ -375,11 +383,15 @@
{
int id = 0;
for(int i = 0; i < chooseMap->count(); i++)
- if(!chooseMap->itemData(i).isNull() && chooseMap->itemData(i).toList()[0].toString() == map)
+ {
+ MapModel::MapInfo mapInfo = MapModel::mapInfoFromData(chooseMap->itemData(i));
+
+ if (mapInfo.name == map)
{
id = i;
break;
}
+ }
if(id > 0)
{
@@ -410,21 +422,23 @@
void HWMapContainer::setRandomMap()
{
setRandomSeed();
- switch(chooseMap->currentIndex())
+ switch(m_mapInfo.type)
{
- case MAPGEN_REGULAR:
- case MAPGEN_MAZE:
+ case MapModel::GeneratedMap:
+ case MapModel::GeneratedMaze:
setRandomTheme();
break;
- case MAPGEN_DRAWN:
+ case MapModel::HandDrawnMap:
emit drawMapRequested();
break;
- default:
- if(chooseMap->currentIndex() <= numMissions + MAPGEN_MAP + 1)
- setRandomMission();
- else
- setRandomStatic();
+ case MapModel::MissionMap:
+ setRandomMission();
break;
+ case MapModel::StaticMap:
+ setRandomStatic();
+ break;
+ case MapModel::Invalid:
+ Q_ASSERT(false);
}
}
@@ -444,11 +458,8 @@
void HWMapContainer::setRandomSeed()
{
- m_seed = QUuid::createUuid().toString();
- seedEdit->setText(m_seed);
+ setSeed(QUuid::createUuid().toString());
emit seedChanged(m_seed);
- if (chooseMap->currentIndex() < MAPGEN_MAP)
- updatePreview();
}
void HWMapContainer::setRandomTheme()
@@ -552,31 +563,29 @@
void HWMapContainer::updatePreview()
{
- int curIndex = chooseMap->currentIndex();
-
- switch(curIndex)
+ switch(m_mapInfo.type)
{
- case MAPGEN_REGULAR:
+ case MapModel::GeneratedMap:
askForGeneratedPreview();
break;
- case MAPGEN_MAZE:
+ case MapModel::GeneratedMaze:
askForGeneratedPreview();
break;
- case MAPGEN_DRAWN:
+ case MapModel::HandDrawnMap:
askForGeneratedPreview();
break;
default:
QPixmap mapImage;
QFile tmpfile;
- tmpfile.setFileName(cfgdir->absolutePath() + "/Data/Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png");
- if (!tmpfile.exists()) tmpfile.setFileName(datadir->absolutePath() + "/Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png");
+ tmpfile.setFileName(cfgdir->absolutePath() + "/Data/Maps/" + m_mapInfo.name + "/preview.png");
+ if (!tmpfile.exists()) tmpfile.setFileName(datadir->absolutePath() + "/Maps/" + m_mapInfo.name + "/preview.png");
if(!mapImage.load(QFileInfo(tmpfile).absoluteFilePath()))
{
imageButt->setIcon(QIcon());
return;
}
- hhLimit = chooseMap->itemData(curIndex).toList()[2].toInt();
+ hhLimit = m_mapInfo.limit;
addInfoToPreview(mapImage);
}
}
@@ -593,104 +602,20 @@
}
-void HWMapContainer::loadMapList()
+void HWMapContainer::updateModelViews()
{
- // TODO: convert to model
-
- // remember previous selection
- QString selMap = getCurrentMap();
-
- chooseMap->clear();
-
- chooseMap->addItem(
-// FIXME - need real icons. Disabling until then
-//QIcon(":/res/mapRandom.png"),
- QComboBox::tr("generated map..."));
- chooseMap->addItem(
-// FIXME - need real icons. Disabling until then
-//QIcon(":/res/mapMaze.png"),
- QComboBox::tr("generated maze..."));
-
- chooseMap->addItem(QComboBox::tr("hand drawn map..."));
-
- chooseMap->insertSeparator(chooseMap->count()); // separator between generators and missions
- chooseMap->insertSeparator(chooseMap->count()); // separator between generators and missions
+ numMissions = m_mapModel->missionCount();
- int missionindex = chooseMap->count();
- numMissions = 0;
- QFile mapLuaFile;
- QFile mapCfgFile;
-
- DataManager & dataMgr = DataManager::instance();
-
- QStringList mapList = dataMgr.entryList(
- QString("Maps"),
- QDir::Dirs | QDir::NoDotAndDotDot
- );
+ intSetMap(m_mapInfo.name);
- foreach (QString map, mapList)
- {
- mapCfgFile.setFileName(
- dataMgr.findFileForRead(QString("Maps/%1/map.cfg").arg(map)));
- mapLuaFile.setFileName(
- dataMgr.findFileForRead(QString("Maps/%1/map.lua").arg(map)));
-
- if (mapCfgFile.open(QFile::ReadOnly))
- {
- QString theme;
- quint32 limit = 0;
- QString scheme;
- QString weapons;
- QList<QVariant> mapInfo;
- bool isMission = mapLuaFile.exists();
+/*
+ int nGenMaps = m_mapModel->generatorCount();
- QTextStream input(&mapCfgFile);
- input >> theme;
- input >> limit;
- input >> scheme;
- input >> weapons;
- mapInfo.push_back(map);
- mapInfo.push_back(theme);
- if (limit)
- mapInfo.push_back(limit);
- else
- mapInfo.push_back(18);
-
-
- mapInfo.push_back(isMission);
-
- if (scheme.isEmpty())
- scheme = "locked";
- scheme.replace("_", " ");
-
- if (weapons.isEmpty())
- weapons = "locked";
- weapons.replace("_", " ");
+ // insert double separator after random maps/mazes/etc
+ chooseMap->insertSeparator(nGenMaps);
+ chooseMap->insertSeparator(nGenMaps);
- mapInfo.push_back(scheme);
- mapInfo.push_back(weapons);
-
- if(isMission)
- {
- chooseMap->insertItem(missionindex++,
-// FIXME - need real icons. Disabling until then
-//QIcon(":/res/mapMission.png"),
- QComboBox::tr("Mission") + ": " + map, mapInfo);
- numMissions++;
- }
- else
- chooseMap->addItem(
-// FIXME - need real icons. Disabling until then
-//QIcon(":/res/mapCustom.png"),
- map, mapInfo);
- mapCfgFile.close();
- }
- }
-
- chooseMap->insertSeparator(missionindex); // separator between missions and maps
-
- // if a map was selected already let's reselect it after reloading the map list
- if (!selMap.isEmpty()) {
- setMap(selMap);
- }
+ // separator between missions and regular maps
+ chooseMap->insertSeparator(nGenMaps + m_mapModel->missionCount());
+*/
}
--- a/QTfrontend/ui/widget/mapContainer.h Thu Apr 26 16:15:37 2012 +0200
+++ b/QTfrontend/ui/widget/mapContainer.h Fri Apr 27 11:47:37 2012 +0200
@@ -35,6 +35,7 @@
class QPushButton;
class IconedGroupBox;
class QListView;
+class SeparatorPainter;
class MapFileErrorException
{
@@ -71,6 +72,7 @@
void setMazeSize(int size);
void setDrawnMapData(const QByteArray & ar);
void setAllMapParameters(const QString & map, MapGenerator m, int mazesize, const QString & seed, int tmpl);
+ void updateModelViews();
signals:
void seedChanged(const QString & seed);
@@ -94,7 +96,6 @@
void themeSelected(const QModelIndex & current, const QModelIndex &);
void addInfoToPreview(QPixmap image);
void seedEdited();
- void loadMapList();
protected:
virtual void resizeEvent ( QResizeEvent * event );
@@ -103,6 +104,7 @@
QGridLayout mainLayout;
QPushButton* imageButt;
QComboBox* chooseMap;
+ MapModel * m_mapModel;
IconedGroupBox* gbThemes;
QListView* lvThemes;
ThemeModel * m_themeModel;
@@ -127,6 +129,8 @@
void intSetTemplateFilter(int);
void intSetMazeSize(int size);
void updatePreview();
+
+ MapModel::MapInfo m_mapInfo;
};
#endif // _HWMAP_CONTAINER_INCLUDED
--- a/QTfrontend/util/DataManager.cpp Thu Apr 26 16:15:37 2012 +0200
+++ b/QTfrontend/util/DataManager.cpp Fri Apr 27 11:47:37 2012 +0200
@@ -40,6 +40,7 @@
m_defaultData = new QDir(datadir->absolutePath());
+ m_mapModel = NULL;
m_themeModel = NULL;
}
@@ -117,6 +118,15 @@
return "";
}
+MapModel * DataManager::mapModel()
+{
+ if (m_mapModel == NULL) {
+ m_mapModel = new MapModel();
+ m_mapModel->loadMaps();
+ }
+ return m_mapModel;
+}
+
ThemeModel * DataManager::themeModel()
{
if (m_themeModel == NULL) {
@@ -128,6 +138,7 @@
void DataManager::reload()
{
+ m_mapModel->loadMaps();
m_themeModel->loadThemes();
emit updated();
}
--- a/QTfrontend/util/DataManager.h Thu Apr 26 16:15:37 2012 +0200
+++ b/QTfrontend/util/DataManager.h Fri Apr 27 11:47:37 2012 +0200
@@ -30,11 +30,13 @@
#include <QStringList>
+#include "MapModel.h"
#include "ThemeModel.h"
class QDir;
class QFile;
class QStringList;
+class MapModel;
class ThemeModel;
/**
@@ -94,11 +96,20 @@
QString findFileForWrite(const QString & relativeDataFilePath) const;
/**
+ * @brief Returns pointer to a model for the available maps.
+ *
+ * The model is kept up to date automatically.
+ *
+ * @return map model pointer.
+ */
+ MapModel * mapModel();
+
+ /**
* @brief Returns pointer to a model for the available themes.
*
* The model is kept up to date automatically.
*
- * @return theme model pointer
+ * @return theme model pointer.
*/
ThemeModel * themeModel();
@@ -130,7 +141,8 @@
QDir * m_defaultData; ///< directory of the installed data
QDir * m_userData; ///< directory of custom data in the user's directory
- ThemeModel * m_themeModel; ///< themes model instance
+ MapModel * m_mapModel; ///< map model instance
+ ThemeModel * m_themeModel; ///< theme model instance
};
#endif // HEDGEWARS_DATAMANAGER_H
--- a/project_files/hedgewars.pro Thu Apr 26 16:15:37 2012 +0200
+++ b/project_files/hedgewars.pro Fri Apr 27 11:47:37 2012 +0200
@@ -23,6 +23,7 @@
QT += webkit
HEADERS += ../QTfrontend/model/ThemeModel.h \
+ ../QTfrontend/model/MapModel.h \
../QTfrontend/model/ammoSchemeModel.h \
../QTfrontend/model/netserverslist.h \
../QTfrontend/model/hats.h \
@@ -104,6 +105,7 @@
../QTfrontend/ui/dialog/input_password.h
SOURCES += ../QTfrontend/model/ammoSchemeModel.cpp \
+ ../QTfrontend/model/MapModel.cpp \
../QTfrontend/model/ThemeModel.cpp \
../QTfrontend/model/hats.cpp \
../QTfrontend/model/netserverslist.cpp \