QTfrontend/model/MapModel.cpp
author unc0rr
Sun, 21 Oct 2012 00:34:14 +0400
branchphysfslayer
changeset 7776 e78eff243e25
parent 6983 ede55af89e78
child 8049 133e22b5c410
permissions -rw-r--r--
Workaround over QIcon failing to load from physfs

/*
 * Hedgewars, a free turn based strategy game
 * Copyright (c) 2004-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 implementation
 */

#include "MapModel.h"


void MapModel::loadMaps()
{
    // this method resets the contents of this model (important to know for views).
    beginResetModel();

    // we'll need the DataManager a few times, so let's get a reference to it
    DataManager & datamgr = DataManager::instance();

    // fetch list of available maps
    QStringList maps =
        datamgr.entryList("Maps", QDir::AllDirs | QDir::NoDotAndDotDot);

    // empty list, so that we can (re)fill it
    QStandardItemModel::clear();

    QList<QStandardItem *> genMaps;
    QList<QStandardItem *> missionMaps;
    QList<QStandardItem *> staticMaps;

    // add generated/handdrawn maps to list
    // TODO: icons for these

    genMaps.append(
        infoToItem(QIcon(), QComboBox::tr("generated map..."), GeneratedMap, "+rnd+"));
    genMaps.append(
        infoToItem(QIcon(), QComboBox::tr("generated maze..."), GeneratedMaze, "+maze+"));
    genMaps.append(
        infoToItem(QIcon(), QComboBox::tr("hand drawn map..."), HandDrawnMap, "+drawn+"));

    // only 2 map relate files are relevant:
    // - the cfg file that contains the settings/info of the map
    // - the lua file - if it exists it's a mission, otherwise it isn't
    QFile mapLuaFile;
    QFile mapCfgFile;

    // add mission/static maps to lists
    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)));


        if (mapCfgFile.open(QFile::ReadOnly))
        {
            QString caption;
            QString theme;
            quint32 limit = 0;
            QString scheme;
            QString weapons;
            // if there is a lua file for this map, then it's a mission
            bool isMission = mapLuaFile.exists();
            MapType type = isMission?MissionMap:StaticMap;

            // load map info from file
            QTextStream input(&mapCfgFile);
            input >> theme;
            input >> limit;
            if (isMission) { // scheme and weapons are only relevant for missions
                input >> scheme;
                input >> weapons;
            }
            mapCfgFile.close();

            // let's use some semi-sane hedgehog limit, rather than none
            if (limit == 0)
                limit = 18;


            // the default scheme/weaponset for missions.
            // if empty we assume the map sets these internally -> locked
            if (isMission)
            {
                if (scheme.isEmpty())
                    scheme = "locked";
                else
                    scheme.replace("_", " ");

                if (weapons.isEmpty())
                    weapons = "locked";
                else
                    weapons.replace("_", " ");
            }

            // add a mission caption prefix to missions
            if (isMission)
            {
                // TODO: icon
                caption = QComboBox::tr("Mission") + ": " + map;
            }
            else
                caption = map;

            // we know everything there is about the map, let's get am item for it
            QStandardItem * item = infoToItem(
                QIcon(), caption, type, map, theme, limit, scheme, weapons);

            // append item to the list
            if (isMission)
                missionMaps.append(item);
            else
                staticMaps.append(item);
        
        }

    }


    // define a separator item
    QStandardItem separator("---");
    separator.setData(QLatin1String("separator"), Qt::AccessibleDescriptionRole);
    separator.setFlags(separator.flags() & ~( Qt::ItemIsEnabled | Qt::ItemIsSelectable ) );

    // create list:
    // generated+handdrawn maps, 2 saperators, missions, 1 separator, static maps
    QList<QStandardItem * > items;
    items.append(genMaps);
    items.append(separator.clone());
    items.append(separator.clone());
    items.append(missionMaps);
    items.append(separator.clone());
    items.append(staticMaps);


    // create row-index lookup table

    m_mapIndexes.clear();

    int count = items.size();

    for (int i = 0; i < count; i++)
    {
        QStandardItem * si = items.at(i);
        QVariant v = si->data(Qt::UserRole + 1);
        if (v.canConvert<MapInfo>())
            m_mapIndexes.insert(v.value<MapInfo>().name, i);
    }


    // store start-index and count of relevant types

    m_typeLoc.insert(GeneratedMap, QPair<int,int>(0, 1));
    m_typeLoc.insert(GeneratedMaze, QPair<int,int>(1, 1));
    m_typeLoc.insert(HandDrawnMap, QPair<int,int>(2, 1));
    // mission maps
    int startIdx = genMaps.size() + 2; // start after genMaps and 2 separators
    count = missionMaps.size();
    m_typeLoc.insert(MissionMap, QPair<int,int>(startIdx, count));
    // static maps
    startIdx += count + 1; // start after missions and 2 separators
    count = staticMaps.size();
    m_typeLoc.insert(StaticMap, QPair<int,int>(startIdx, count));

    // store list contents in the item model
    QStandardItemModel::appendColumn(items);


    endResetModel();
}


int MapModel::randomMap(MapType type) const
{
    // return a random index for this type or -1 if none available
    QPair<int,int> loc = m_typeLoc.value(type, QPair<int,int>(-1,0));

    int startIdx = loc.first;
    int count = loc.second;

    if (count < 1)
        return -1;
    else
        return startIdx + (rand() % count);
}


QStandardItem * MapModel::infoToItem(
    const QIcon & icon,
    const QString caption,
    MapType type,
    QString name,
    QString theme,
    quint32 limit,
    QString scheme,
    QString weapons)
const
{
    QStandardItem * item = new QStandardItem(icon, caption);
    MapInfo mapInfo;
    QVariant qvar(QVariant::UserType);

    mapInfo.type = type;
    mapInfo.name = name;
    mapInfo.theme = theme;
    mapInfo.limit = limit;
    mapInfo.scheme = scheme;
    mapInfo.weapons = weapons;


    qvar.setValue(mapInfo);
    item->setData(qvar, Qt::UserRole + 1);

    return item;
}


int MapModel::indexOf(const QString & map) const
{
    return m_mapIndexes.value(map, -1);
}