#include "cell.hpp" #include #include #include #include #include #include #include #include #include #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" #include "../../model/world/refcollection.hpp" #include "../../model/world/cellcoordinates.hpp" #include "cellwater.hpp" #include "cellborder.hpp" #include "cellarrow.hpp" #include "cellmarker.hpp" #include "mask.hpp" #include "pathgrid.hpp" #include "terrainstorage.hpp" #include "object.hpp" bool CSVRender::Cell::removeObject (const std::string& id) { std::map::iterator iter = mObjects.find (Misc::StringUtils::lowerCase (id)); if (iter==mObjects.end()) return false; removeObject (iter); return true; } std::map::iterator CSVRender::Cell::removeObject ( std::map::iterator iter) { delete iter->second; mObjects.erase (iter++); return iter; } bool CSVRender::Cell::addObjects (int start, int end) { bool modified = false; const CSMWorld::RefCollection& collection = mData.getReferences(); for (int i=start; i<=end; ++i) { std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell); CSMWorld::RecordBase::State state = collection.getRecord (i).mState; if (cell==mId && state!=CSMWorld::RecordBase::State_Deleted) { std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); std::unique_ptr object (new Object (mData, mCellNode, id, false)); if (mSubModeElementMask & Mask_Reference) object->setSubMode (mSubMode); mObjects.insert (std::make_pair (id, object.release())); modified = true; } } return modified; } CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id, bool deleted) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mDeleted (deleted), mSubMode (0), mSubModeElementMask (0) { std::pair result = CSMWorld::CellCoordinates::fromId (id); if (result.second) mCoordinates = result.first; mCellNode = new osg::Group; rootNode->addChild(mCellNode); setCellMarker(); if (!mDeleted) { CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); int rows = references.rowCount(); addObjects (0, rows-1); const CSMWorld::IdCollection& land = mData.getLand(); int landIndex = land.searchId(mId); if (landIndex != -1) { const ESM::Land& esmLand = land.getRecord(mId).get(); if (esmLand.getLandData (ESM::Land::DATA_VHGT)) { mTerrain.reset(new Terrain::TerrainGrid(mCellNode, mCellNode, data.getResourceSystem().get(), new TerrainStorage(mData), Mask_Terrain)); mTerrain->loadCell(esmLand.mX, esmLand.mY); mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); mCellBorder->buildShape(esmLand); } } mPathgrid.reset(new Pathgrid(mData, mCellNode, mId, mCoordinates)); mCellWater.reset(new CellWater(mData, mCellNode, mId, mCoordinates)); } } CSVRender::Cell::~Cell() { for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) delete iter->second; mCellNode->getParent(0)->removeChild(mCellNode); } CSVRender::Pathgrid* CSVRender::Cell::getPathgrid() const { return mPathgrid.get(); } bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { bool modified = false; for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) if (iter->second->referenceableDataChanged (topLeft, bottomRight)) modified = true; return modified; } bool CSVRender::Cell::referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) { if (parent.isValid()) return false; bool modified = false; for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) if (iter->second->referenceableAboutToBeRemoved (parent, start, end)) modified = true; return modified; } bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (mDeleted) return false; CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id); int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); int stateColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Modification); // list IDs in cell std::map ids; // id, deleted state for (int i=topLeft.row(); i<=bottomRight.row(); ++i) { std::string cell = Misc::StringUtils::lowerCase (references.data ( references.index (i, cellColumn)).toString().toUtf8().constData()); if (cell==mId) { std::string id = Misc::StringUtils::lowerCase (references.data ( references.index (i, idColumn)).toString().toUtf8().constData()); int state = references.data (references.index (i, stateColumn)).toInt(); ids.insert (std::make_pair (id, state==CSMWorld::RecordBase::State_Deleted)); } } // perform update and remove where needed bool modified = false; std::map::iterator iter = mObjects.begin(); while (iter!=mObjects.end()) { if (iter->second->referenceDataChanged (topLeft, bottomRight)) modified = true; std::map::iterator iter2 = ids.find (iter->first); if (iter2!=ids.end()) { bool deleted = iter2->second; ids.erase (iter2); if (deleted) { iter = removeObject (iter); modified = true; continue; } } ++iter; } // add new objects for (std::map::iterator mapIter (ids.begin()); mapIter!=ids.end(); ++mapIter) { if (!mapIter->second) { mObjects.insert (std::make_pair ( mapIter->first, new Object (mData, mCellNode, mapIter->first, false))); modified = true; } } return modified; } bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end) { if (parent.isValid()) return false; if (mDeleted) return false; CSMWorld::IdTable& references = dynamic_cast ( *mData.getTableModel (CSMWorld::UniversalId::Type_References)); int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id); bool modified = false; for (int row = start; row<=end; ++row) if (removeObject (references.data ( references.index (row, idColumn)).toString().toUtf8().constData())) modified = true; return modified; } bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int end) { if (parent.isValid()) return false; if (mDeleted) return false; return addObjects (start, end); } void CSVRender::Cell::pathgridModified() { mPathgrid->recreateGeometry(); } void CSVRender::Cell::pathgridRemoved() { mPathgrid->removeGeometry(); } void CSVRender::Cell::setSelection (int elementMask, Selection mode) { if (elementMask & Mask_Reference) { for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) { bool selected = false; switch (mode) { case Selection_Clear: selected = false; break; case Selection_All: selected = true; break; case Selection_Invert: selected = !iter->second->getSelected(); break; } iter->second->setSelected (selected); } } if (elementMask & Mask_Pathgrid) { // Only one pathgrid may be selected, so some operations will only have an effect // if the pathgrid is already focused switch (mode) { case Selection_Clear: mPathgrid->clearSelected(); break; case Selection_All: if (mPathgrid->isSelected()) mPathgrid->selectAll(); break; case Selection_Invert: if (mPathgrid->isSelected()) mPathgrid->invertSelected(); break; } } } void CSVRender::Cell::selectAllWithSameParentId (int elementMask) { std::set ids; for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) { if (iter->second->getSelected()) ids.insert (iter->second->getReferenceableId()); } for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) { if (!iter->second->getSelected() && ids.find (iter->second->getReferenceableId())!=ids.end()) { iter->second->setSelected (true); } } } void CSVRender::Cell::setCellArrows (int mask) { for (int i=0; i<4; ++i) { CellArrow::Direction direction = static_cast (1< -1) { const CSMWorld::Record& cellRecord = mData.getCells().getRecord(cellIndex); cellExists = !cellRecord.isDeleted(); isInteriorCell = cellRecord.get().mData.mFlags & ESM::Cell::Interior; } if (!isInteriorCell) { mCellMarker.reset(new CellMarker(mCellNode, mCoordinates, cellExists)); } } CSMWorld::CellCoordinates CSVRender::Cell::getCoordinates() const { return mCoordinates; } bool CSVRender::Cell::isDeleted() const { return mDeleted; } std::vector > CSVRender::Cell::getSelection (unsigned int elementMask) const { std::vector > result; if (elementMask & Mask_Reference) for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) if (iter->second->getSelected()) result.push_back (iter->second->getTag()); if (elementMask & Mask_Pathgrid) if (mPathgrid->isSelected()) result.push_back(mPathgrid->getTag()); return result; } std::vector > CSVRender::Cell::getEdited (unsigned int elementMask) const { std::vector > result; if (elementMask & Mask_Reference) for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) if (iter->second->isEdited()) result.push_back (iter->second->getTag()); return result; } void CSVRender::Cell::setSubMode (int subMode, unsigned int elementMask) { mSubMode = subMode; mSubModeElementMask = elementMask; if (elementMask & Mask_Reference) for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) iter->second->setSubMode (subMode); } void CSVRender::Cell::reset (unsigned int elementMask) { if (elementMask & Mask_Reference) for (std::map::const_iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) iter->second->reset(); if (elementMask & Mask_Pathgrid) mPathgrid->resetIndicators(); }