From c808bf2b23a8297f6582c3eba82557dfa4a7eb74 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Jul 2013 15:05:28 +0200 Subject: [PATCH] updating region map on changes to region and cell records --- apps/opencs/model/world/regionmap.cpp | 338 +++++++++++++++++++++++--- apps/opencs/model/world/regionmap.hpp | 35 ++- 2 files changed, 337 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 5b28097f9d..fd278d2a6c 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -1,6 +1,8 @@ #include "regionmap.hpp" +#include + #include #include @@ -10,14 +12,20 @@ CSMWorld::RegionMap::CellDescription::CellDescription() : mDeleted (false) {} -std::pair CSMWorld::RegionMap::getIndex (const QModelIndex& index) const +CSMWorld::RegionMap::CellIndex CSMWorld::RegionMap::getIndex (const QModelIndex& index) const { return CellIndex (index.column()+mMin.first, index.row()+mMin.second); } -void CSMWorld::RegionMap::buildRegions (Data& data) +QModelIndex CSMWorld::RegionMap::getIndex (const CellIndex& index) const { - const IdCollection& regions = data.getRegions(); + // I hate you, Qt API naming scheme! + return QAbstractTableModel::index (index.second-mMin.second, index.first-mMin.first); +} + +void CSMWorld::RegionMap::buildRegions() +{ + const IdCollection& regions = mData.getRegions(); int size = regions.getSize(); @@ -31,14 +39,12 @@ void CSMWorld::RegionMap::buildRegions (Data& data) } } -void CSMWorld::RegionMap::buildMap (Data& data) +void CSMWorld::RegionMap::buildMap() { - const IdCollection& cells = data.getCells(); + const IdCollection& cells = mData.getCells(); int size = cells.getSize(); - mMin = mMax = std::make_pair (0, 0); - for (int i=0; i& cell = cells.getRecord (i); @@ -56,33 +62,237 @@ void CSMWorld::RegionMap::buildMap (Data& data) CellIndex index (cell2.mData.mX, cell2.mData.mY); - if (mMap.empty()) - { - mMin = index; - mMax = std::make_pair (mMin.first+1, mMin.second+1); - } - else - { - if (index.first=mMax.first) - mMax.first = index.first + 1; - - if (index.second=mMax.second) - mMax.second = index.second + 1; - } - mMap.insert (std::make_pair (index, description)); } } + + std::pair mapSize = getSize(); + + mMin = mapSize.first; + mMax = mapSize.second; +} + +void CSMWorld::RegionMap::addCell (const CellIndex& index, const CellDescription& description) +{ + std::map::iterator cell = mMap.find (index); + + if (cell!=mMap.end()) + { + cell->second = description; + } + else + { + updateSize(); + + mMap.insert (std::make_pair (index, description)); + } + + QModelIndex index2 = getIndex (index); + + dataChanged (index2, index2); +} + +void CSMWorld::RegionMap::addCells (int start, int end) +{ + const IdCollection& cells = mData.getCells(); + + for (int i=start; i<=end; ++i) + { + const Record& cell = cells.getRecord (i); + + const Cell& cell2 = cell.get(); + + if (cell2.isExterior()) + { + CellIndex index (cell2.mData.mX, cell2.mData.mY); + + CellDescription description; + + if (cell.isDeleted()) + description.mDeleted = true; + else + description.mRegion = cell2.mRegion; + + addCell (index, description); + } + } } -CSMWorld::RegionMap::RegionMap (Data& data) +void CSMWorld::RegionMap::removeCell (const CellIndex& index) { - buildRegions (data); - buildMap (data); + std::map::iterator cell = mMap.find (index); + + if (cell!=mMap.end()) + { + mMap.erase (cell); + + QModelIndex index2 = getIndex (index); + + dataChanged (index2, index2); + + updateSize(); + } +} + +void CSMWorld::RegionMap::addRegion (const std::string& region, unsigned int colour) +{ + mColours[Misc::StringUtils::lowerCase (region)] = colour; +} + +void CSMWorld::RegionMap::removeRegion (const std::string& region) +{ + std::map::iterator iter ( + mColours.find (Misc::StringUtils::lowerCase (region))); + + if (iter!=mColours.end()) + mColours.erase (iter); +} + +void CSMWorld::RegionMap::updateRegions (const std::vector& regions) +{ + std::vector regions2 (regions); + + std::for_each (regions2.begin(), regions2.end(), &Misc::StringUtils::lowerCase); + std::sort (regions2.begin(), regions2.end()); + + for (std::map::const_iterator iter (mMap.begin()); + iter!=mMap.end(); ++iter) + { + if (!iter->second.mRegion.empty() && + std::find (regions2.begin(), regions2.end(), + Misc::StringUtils::lowerCase (iter->second.mRegion))!=regions2.end()) + { + QModelIndex index = getIndex (iter->first); + + dataChanged (index, index); + } + } +} + +void CSMWorld::RegionMap::updateSize() +{ + std::pair size = getSize(); + + { + int diff = size.first.first - mMin.first; + + if (diff<0) + { + beginInsertColumns (QModelIndex(), 0, -diff-1); + mMin.first = size.first.first; + endInsertColumns(); + } + else if (diff>0) + { + beginRemoveColumns (QModelIndex(), 0, diff-1); + mMin.first = size.first.first; + endRemoveColumns(); + } + } + + { + int diff = size.first.second - mMin.second; + + if (diff<0) + { + beginInsertRows (QModelIndex(), 0, -diff-1); + mMin.second = size.first.second; + endInsertRows(); + } + else if (diff>0) + { + beginRemoveRows (QModelIndex(), 0, diff-1); + mMin.second = size.first.second; + endRemoveRows(); + } + } + + { + int diff = size.second.first - mMax.first; + + if (diff>0) + { + int columns = columnCount(); + beginInsertColumns (QModelIndex(), columns, columns+diff-1); + mMax.first = size.second.first; + endInsertColumns(); + } + else if (diff<0) + { + int columns = columnCount(); + beginRemoveColumns (QModelIndex(), columns+diff, columns-1); + mMax.first = size.second.first; + endRemoveColumns(); + } + } + + { + int diff = size.second.second - mMax.second; + + if (diff>0) + { + int rows = rowCount(); + beginInsertRows (QModelIndex(), rows, rows+diff-1); + mMax.second = size.second.second; + endInsertRows(); + } + else if (diff<0) + { + int rows = rowCount(); + beginRemoveRows (QModelIndex(), rows+diff, rows-1); + mMax.second = size.second.second; + endRemoveRows(); + } + } +} + +std::pair CSMWorld::RegionMap::getSize() + const +{ + const IdCollection& cells = mData.getCells(); + + int size = cells.getSize(); + + CellIndex min (0, 0); + CellIndex max (0, 0); + + for (int i=0; i& cell = cells.getRecord (i); + + const Cell& cell2 = cell.get(); + + if (cell2.isExterior()) + { + CellIndex index (cell2.mData.mX, cell2.mData.mY); + + if (min==max) + { + min = index; + max = std::make_pair (min.first+1, min.second+1); + } + else + { + if (index.first=max.first) + max.first = index.first + 1; + + if (index.second=max.second) + max.second = index.second + 1; + } + } + } + + return std::make_pair (min, max); +} + +CSMWorld::RegionMap::RegionMap (Data& data) : mData (data) +{ + buildRegions(); + buildMap(); QAbstractItemModel *regions = data.getTableModel (UniversalId (UniversalId::Type_Regions)); @@ -96,11 +306,11 @@ CSMWorld::RegionMap::RegionMap (Data& data) QAbstractItemModel *cells = data.getTableModel (UniversalId (UniversalId::Type_Cells)); connect (cells, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), - this, SLOT (regionsAboutToBeRemoved (const QModelIndex&, int, int))); + this, SLOT (cellsAboutToBeRemoved (const QModelIndex&, int, int))); connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), - this, SLOT (regionsInserted (const QModelIndex&, int, int))); + this, SLOT (cellsInserted (const QModelIndex&, int, int))); connect (cells, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), - this, SLOT (regionsChanged (const QModelIndex&, const QModelIndex&))); + this, SLOT (cellsChanged (const QModelIndex&, const QModelIndex&))); } int CSMWorld::RegionMap::rowCount (const QModelIndex& parent) const @@ -166,35 +376,95 @@ Qt::ItemFlags CSMWorld::RegionMap::flags (const QModelIndex& index) const void CSMWorld::RegionMap::regionsAboutToBeRemoved (const QModelIndex& parent, int start, int end) { + std::vector update; + const IdCollection& regions = mData.getRegions(); + for (int i=start; i<=end; ++i) + { + const Record& region = regions.getRecord (i); + + update.push_back (region.get().mId); + + removeRegion (region.get().mId); + } + + updateRegions (update); } void CSMWorld::RegionMap::regionsInserted (const QModelIndex& parent, int start, int end) { + std::vector update; + const IdCollection& regions = mData.getRegions(); + for (int i=start; i<=end; ++i) + { + const Record& region = regions.getRecord (i); + + if (!region.isDeleted()) + { + update.push_back (region.get().mId); + + addRegion (region.get().mId, region.get().mMapColor); + } + } + + updateRegions (update); } void CSMWorld::RegionMap::regionsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { + // Note: At this point an additional check could be inserted to see if there is any change to the + // columns we are interested in. If not we can exit the function here and avoid all updating. + std::vector update; + const IdCollection& regions = mData.getRegions(); + + for (int i=topLeft.row(); i<=bottomRight.column(); ++i) + { + const Record& region = regions.getRecord (i); + + update.push_back (region.get().mId); + + if (!region.isDeleted()) + addRegion (region.get().mId, region.get().mMapColor); + else + removeRegion (region.get().mId); + } + + updateRegions (update); } void CSMWorld::RegionMap::cellsAboutToBeRemoved (const QModelIndex& parent, int start, int end) { + const IdCollection& cells = mData.getCells(); + for (int i=start; i<=end; ++i) + { + const Record& cell = cells.getRecord (i); + const Cell& cell2 = cell.get(); + + if (cell2.isExterior()) + { + CellIndex index (cell2.mData.mX, cell2.mData.mY); + + removeCell (index); + } + } } void CSMWorld::RegionMap::cellsInserted (const QModelIndex& parent, int start, int end) { - - + addCells (start, end); } void CSMWorld::RegionMap::cellsChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { -; + // Note: At this point an additional check could be inserted to see if there is any change to the + // columns we are interested in. If not we can exit the function here and avoid all updating. + + addCells (topLeft.row(), bottomRight.row()); } \ No newline at end of file diff --git a/apps/opencs/model/world/regionmap.hpp b/apps/opencs/model/world/regionmap.hpp index c5f70b4908..0a20324c4c 100644 --- a/apps/opencs/model/world/regionmap.hpp +++ b/apps/opencs/model/world/regionmap.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -31,6 +32,7 @@ namespace CSMWorld CellDescription(); }; + Data& mData; std::map mMap; CellIndex mMin; ///< inclusive CellIndex mMax; ///< exclusive @@ -39,9 +41,38 @@ namespace CSMWorld CellIndex getIndex (const QModelIndex& index) const; ///< Translates a Qt model index into a cell index (which can contain negative components) - void buildRegions (Data& data); + QModelIndex getIndex (const CellIndex& index) const; - void buildMap (Data& data); + void buildRegions(); + + void buildMap(); + + void addCell (const CellIndex& index, const CellDescription& description); + ///< May be called on a cell that is already in the map (in which case an update is + // performed) + + void addCells (int start, int end); + + void removeCell (const CellIndex& index); + ///< May be called on a cell that is not in the map (in which case the call is ignored) + + void addRegion (const std::string& region, unsigned int colour); + ///< May be called on a region that is already listed (in which case an update is + /// performed) + /// + /// \note This function does not update the region map. + + void removeRegion (const std::string& region); + ///< May be called on a region that is not listed (in which case the call is ignored) + /// + /// \note This function does not update the region map. + + void updateRegions (const std::vector& regions); + ///< Update cells affected by the listed regions + + void updateSize(); + + std::pair getSize() const; public: