# HG changeset patch # User sheepluva # Date 1335520057 -7200 # Node ID 217ed62e872c47b11112b5fa7ef4a355c551045d # Parent 7f77fa908a4e6c27a5050ea82849d0e47b537b1b MapModel, various cleanups. TODO/FIXME: QComboBox separator not working with custom models diff -r 7f77fa908a4e -r 217ed62e872c QTfrontend/model/MapModel.cpp --- /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 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 >(); +} + +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 tmp; + QList 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 dataset; + + + if (mapCfgFile.open(QFile::ReadOnly)) + { + QString theme; + quint32 limit = 0; + QString scheme; + QString weapons; + QList 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; +} diff -r 7f77fa908a4e -r 217ed62e872c QTfrontend/model/MapModel.h --- /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 + * Copyright (c) 2007-2012 Andrey Korotaev + * + * 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 +#include +#include +#include +#include +#include + +#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 > m_data; + int m_nGenerators; + int m_nMissions; +}; + +#endif // HEDGEWARS_MAPMODEL_H diff -r 7f77fa908a4e -r 217ed62e872c QTfrontend/ui/widget/mapContainer.cpp --- 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 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()); +*/ } diff -r 7f77fa908a4e -r 217ed62e872c QTfrontend/ui/widget/mapContainer.h --- 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 diff -r 7f77fa908a4e -r 217ed62e872c QTfrontend/util/DataManager.cpp --- 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(); } diff -r 7f77fa908a4e -r 217ed62e872c QTfrontend/util/DataManager.h --- 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 +#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 diff -r 7f77fa908a4e -r 217ed62e872c project_files/hedgewars.pro --- 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 \