Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411#include "regionmap.hpp"
#include <algorithm>#include <iterator>#include <set>#include <sstream>
#include <QAbstractItemModel>#include <QAction>#include <QBrush>#include <QDropEvent>#include <QHeaderView>#include <QItemSelectionModel>#include <QMenu>#include <QTableView>
#include <apps/opencs/view/world/dragrecordtable.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/columns.hpp"#include "../../model/world/commandmacro.hpp"#include "../../model/world/commands.hpp"#include "../../model/world/data.hpp"#include "../../model/world/idtable.hpp"#include "../../model/world/regionmap.hpp"#include "../../model/world/tablemimedata.hpp"#include "../../model/world/universalid.hpp"
void CSVWorld::RegionMap::contextMenuEvent(QContextMenuEvent* event){ QMenu menu(this);
if (getUnselectedCells().size() > 0) menu.addAction(mSelectAllAction);
if (selectionModel()->selectedIndexes().size() > 0) menu.addAction(mClearSelectionAction);
if (getMissingRegionCells().size() > 0) menu.addAction(mSelectRegionsAction);
int selectedNonExistentCells = getSelectedCells(false, true).size();
if (selectedNonExistentCells > 0) { if (selectedNonExistentCells == 1) mCreateCellsAction->setText("Create one Cell"); else { std::ostringstream stream; stream << "Create " << selectedNonExistentCells << " cells"; mCreateCellsAction->setText(QString::fromUtf8(stream.str().c_str())); }
menu.addAction(mCreateCellsAction); }
if (getSelectedCells().size() > 0) { if (!mRegionId.empty()) { mSetRegionAction->setText(QString::fromUtf8(("Set Region to " + mRegionId).c_str())); menu.addAction(mSetRegionAction); }
menu.addAction(mUnsetRegionAction);
menu.addAction(mViewInTableAction); }
if (selectionModel()->selectedIndexes().size() > 0) menu.addAction(mViewAction);
menu.exec(event->globalPos());}
QModelIndexList CSVWorld::RegionMap::getUnselectedCells() const{ const QAbstractItemModel* model = QTableView::model();
int rows = model->rowCount(); int columns = model->columnCount();
QModelIndexList selected = selectionModel()->selectedIndexes(); std::sort(selected.begin(), selected.end());
QModelIndexList all;
for (int y = 0; y < rows; ++y) for (int x = 0; x < columns; ++x) { QModelIndex index = model->index(y, x); if (model->data(index, Qt::BackgroundRole) != QBrush(Qt::DiagCrossPattern)) all.push_back(index); }
std::sort(all.begin(), all.end());
QModelIndexList list;
std::set_difference(all.begin(), all.end(), selected.begin(), selected.end(), std::back_inserter(list));
return list;}
QModelIndexList CSVWorld::RegionMap::getSelectedCells(bool existent, bool nonExistent) const{ const QAbstractItemModel* model = QTableView::model();
QModelIndexList selected = selectionModel()->selectedIndexes();
QModelIndexList list;
for (QModelIndexList::const_iterator iter(selected.begin()); iter != selected.end(); ++iter) { bool exists = model->data(*iter, Qt::BackgroundRole) != QBrush(Qt::DiagCrossPattern);
if ((exists && existent) || (!exists && nonExistent)) list.push_back(*iter); }
return list;}
QModelIndexList CSVWorld::RegionMap::getMissingRegionCells() const{ const QAbstractItemModel* model = QTableView::model();
QModelIndexList selected = selectionModel()->selectedIndexes();
std::set<std::string> regions;
for (QModelIndexList::const_iterator iter(selected.begin()); iter != selected.end(); ++iter) { std::string_view region = model->data(*iter, CSMWorld::RegionMap::Role_Region).toString().toUtf8().constData();
if (!region.empty()) regions.emplace(region); }
QModelIndexList list;
QModelIndexList unselected = getUnselectedCells();
for (QModelIndexList::const_iterator iter(unselected.begin()); iter != unselected.end(); ++iter) { std::string region = model->data(*iter, CSMWorld::RegionMap::Role_Region).toString().toUtf8().constData();
if (!region.empty() && regions.find(region) != regions.end()) list.push_back(*iter); }
return list;}
void CSVWorld::RegionMap::setRegion(const std::string& regionId){ QModelIndexList selected = getSelectedCells();
QAbstractItemModel* regionModel = model();
CSMWorld::IdTable* cellsModel = &dynamic_cast<CSMWorld::IdTable&>(*mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Cells));
QString regionId2 = QString::fromUtf8(regionId.c_str());
CSMWorld::CommandMacro macro(mDocument.getUndoStack(), selected.size() > 1 ? tr("Set Region") : "");
for (QModelIndexList::const_iterator iter(selected.begin()); iter != selected.end(); ++iter) { std::string cellId = regionModel->data(*iter, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData();
QModelIndex index = cellsModel->getModelIndex(cellId, cellsModel->findColumnIndex(CSMWorld::Columns::ColumnId_Region));
macro.push(new CSMWorld::ModifyCommand(*cellsModel, index, regionId2)); }}
CSVWorld::RegionMap::RegionMap(const CSMWorld::UniversalId& universalId, CSMDoc::Document& document, QWidget* parent) : DragRecordTable(document, parent){ verticalHeader()->hide(); horizontalHeader()->hide();
setSelectionMode(QAbstractItemView::ExtendedSelection);
setModel(document.getData().getTableModel(universalId));
resizeColumnsToContents(); resizeRowsToContents();
mSelectAllAction = new QAction(tr("Select All"), this); connect(mSelectAllAction, &QAction::triggered, this, &RegionMap::selectAll); addAction(mSelectAllAction);
mClearSelectionAction = new QAction(tr("Clear Selection"), this); connect(mClearSelectionAction, &QAction::triggered, this, &RegionMap::clearSelection); addAction(mClearSelectionAction);
mSelectRegionsAction = new QAction(tr("Select Regions"), this); connect(mSelectRegionsAction, &QAction::triggered, this, &RegionMap::selectRegions); addAction(mSelectRegionsAction);
mCreateCellsAction = new QAction(tr("Create Cells Action"), this); connect(mCreateCellsAction, &QAction::triggered, this, &RegionMap::createCells); addAction(mCreateCellsAction);
mSetRegionAction = new QAction(tr("Set Region"), this); connect(mSetRegionAction, &QAction::triggered, this, qOverload<>(&RegionMap::setRegion)); addAction(mSetRegionAction);
mUnsetRegionAction = new QAction(tr("Unset Region"), this); connect(mUnsetRegionAction, &QAction::triggered, this, &RegionMap::unsetRegion); addAction(mUnsetRegionAction);
mViewAction = new QAction(tr("View Cells"), this); connect(mViewAction, &QAction::triggered, this, &RegionMap::view); addAction(mViewAction);
mViewInTableAction = new QAction(tr("View Cells in Table"), this); connect(mViewInTableAction, &QAction::triggered, this, &RegionMap::viewInTable); addAction(mViewInTableAction);
setAcceptDrops(true);
// Make columns square incase QSizeHint doesnt apply for (int column = 0; column < this->model()->columnCount(); ++column) this->setColumnWidth(column, this->rowHeight(0));}
void CSVWorld::RegionMap::selectAll(){ QModelIndexList unselected = getUnselectedCells();
for (QModelIndexList::const_iterator iter(unselected.begin()); iter != unselected.end(); ++iter) selectionModel()->select(*iter, QItemSelectionModel::Select);}
void CSVWorld::RegionMap::clearSelection(){ selectionModel()->clearSelection();}
void CSVWorld::RegionMap::selectRegions(){ QModelIndexList unselected = getMissingRegionCells();
for (QModelIndexList::const_iterator iter(unselected.begin()); iter != unselected.end(); ++iter) selectionModel()->select(*iter, QItemSelectionModel::Select);}
void CSVWorld::RegionMap::createCells(){ if (mEditLock) return;
QModelIndexList selected = getSelectedCells(false, true);
CSMWorld::IdTable* cellsModel = &dynamic_cast<CSMWorld::IdTable&>(*mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Cells));
CSMWorld::CommandMacro macro(mDocument.getUndoStack(), selected.size() > 1 ? tr("Create cells") : "");
for (QModelIndexList::const_iterator iter(selected.begin()); iter != selected.end(); ++iter) { std::string cellId = model()->data(*iter, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData();
macro.push(new CSMWorld::CreateCommand(*cellsModel, cellId)); }}
void CSVWorld::RegionMap::setRegion(){ if (mEditLock) return;
setRegion(mRegionId);}
void CSVWorld::RegionMap::unsetRegion(){ if (mEditLock) return;
setRegion("");}
void CSVWorld::RegionMap::view(){ std::ostringstream hint; hint << "c:";
QModelIndexList selected = selectionModel()->selectedIndexes();
bool first = true;
for (QModelIndexList::const_iterator iter(selected.begin()); iter != selected.end(); ++iter) { std::string cellId = model()->data(*iter, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData();
if (first) first = false; else hint << "; ";
hint << cellId; }
emit editRequest( CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Scene, ESM::Cell::sDefaultWorldspaceId.getValue()), hint.str());}
void CSVWorld::RegionMap::viewInTable(){ std::ostringstream hint; hint << "f:!or(";
QModelIndexList selected = getSelectedCells();
bool first = true;
for (QModelIndexList::const_iterator iter(selected.begin()); iter != selected.end(); ++iter) { std::string cellId = model()->data(*iter, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData();
if (first) first = false; else hint << ",";
hint << "string(ID,\"" << cellId << "\")"; }
hint << ")";
emit editRequest(CSMWorld::UniversalId::Type_Cells, hint.str());}
void CSVWorld::RegionMap::mouseMoveEvent(QMouseEvent* event){ startDragFromTable(*this, indexAt(event->position().toPoint()));}
std::vector<CSMWorld::UniversalId> CSVWorld::RegionMap::getDraggedRecords() const{ QModelIndexList selected(getSelectedCells(true, false)); std::vector<CSMWorld::UniversalId> ids; for (const QModelIndex& it : selected) { ids.emplace_back(CSMWorld::UniversalId::Type_Cell, model()->data(it, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData()); } selected = getSelectedCells(false, true); for (const QModelIndex& it : selected) { ids.emplace_back(CSMWorld::UniversalId::Type_Cell_Missing, model()->data(it, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData()); } return ids;}
void CSVWorld::RegionMap::dragMoveEvent(QDragMoveEvent* event){ const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*>(event->mimeData()); if (mime != nullptr && (mime->holdsType(CSMWorld::UniversalId::Type_Region))) { event->accept(); return; }
event->ignore();}
void CSVWorld::RegionMap::dropEvent(QDropEvent* event){ QModelIndex index = indexAt(event->position().toPoint());
bool exists = QTableView::model()->data(index, Qt::BackgroundRole) != QBrush(Qt::DiagCrossPattern); if (!index.isValid() || !exists) { return; }
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*>(event->mimeData()); if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped return;
if (mime->fromDocument(mDocument) && mime->holdsType(CSMWorld::UniversalId::Type_Region)) { CSMWorld::UniversalId record(mime->returnMatching(CSMWorld::UniversalId::Type_Region));
QAbstractItemModel* regionModel = model();
CSMWorld::IdTable* cellsModel = &dynamic_cast<CSMWorld::IdTable&>(*mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Cells));
std::string cellId(regionModel->data(index, CSMWorld::RegionMap::Role_CellId).toString().toUtf8().constData());
QModelIndex index2( cellsModel->getModelIndex(cellId, cellsModel->findColumnIndex(CSMWorld::Columns::ColumnId_Region)));
mDocument.getUndoStack().push( new CSMWorld::ModifyCommand(*cellsModel, index2, QString::fromUtf8(record.getId().c_str())));
mRegionId = record.getId(); }}