QTfrontend/model/MapModel.cpp
author unc0rr
Sun, 02 Dec 2012 01:25:11 +0400
changeset 8178 8bd087478b48
parent 8049 133e22b5c410
child 8377 869f80966a77
permissions -rw-r--r--
Fix QSettings problems: - Reopen file in ReadOnly mode if it was open in ReadWrite mode and is being read. This is needed for stupid QSettings which opens file in ReadWrite mode just to call readAll() on it. - Implement setSize(0)

/*
 * 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(QString("physfs://Maps/%1/map.cfg").arg(map));
        mapLuaFile.setFileName(QString("physfs://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);
}