void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& messages) { mMessages = &messages; mId = mData.getScripts().getId (stage); try { mFile = mData.getScripts().getRecord (stage).get().mId; std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText); Compiler::Scanner scanner (*this, input, mContext.getExtensions()); Compiler::FileParser parser (*this, mContext); scanner.scan (parser); } catch (const Compiler::SourceException&) { // error has already been reported via error handler } catch (const std::exception& error) { std::ostringstream stream; CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); stream << id.toString() << "|Critical compile error: " << error.what(); messages.push_back (stream.str()); } mMessages = 0; }
void CSMTools::RaceCheckStage::performFinal (std::vector<std::string>& messages) { CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races); if (!mPlayable) messages.push_back (id.toString() + "|No playable race"); }
void CSVWorld::Table::dropEvent(QDropEvent *event) { QModelIndex index = indexAt (event->pos()); if (!index.isValid()) { 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)) { CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display> (mModel->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); if (mime->holdsType (display)) { CSMWorld::UniversalId record (mime->returnMatching (display)); std::auto_ptr<CSMWorld::ModifyCommand> command (new CSMWorld::ModifyCommand (*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str())))); mDocument.getUndoStack().push (command.release()); } } //TODO handle drops from different document }
CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory() { for (int i=0; i<CSMWorld::UniversalId::NumberOfTypes; ++i) { CSMWorld::UniversalId id (static_cast<CSMWorld::UniversalId::Type> (i)); DataDisplayDelegateFactory::add (id.getType(), QString::fromUtf8 (id.getTypeName().c_str()), QString::fromUtf8 (id.getIcon().c_str())); } }
bool CSMDoc::Blacklist::isBlacklisted (const CSMWorld::UniversalId& id) const { std::map<CSMWorld::UniversalId::Type, std::vector<std::string> >::const_iterator iter = mIds.find (id.getType()); if (iter==mIds.end()) return false; return std::binary_search (iter->second.begin(), iter->second.end(), Misc::StringUtils::lowerCase (id.getId())); }
CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id) { QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins (QMargins (0, 0, 0, 0)); layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id, this), 0); QHBoxLayout *layout2 = new QHBoxLayout; layout2->setContentsMargins (QMargins (0, 0, 0, 0)); SceneToolbar *toolbar = new SceneToolbar (48, this); if (id.getId()=="sys::default") mScene = new CSVRender::PagedWorldspaceWidget (this); else mScene = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this); SceneToolMode *navigationTool = mScene->makeNavigationSelector (toolbar); toolbar->addTool (navigationTool); SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); toolbar->addTool (lightingTool); layout2->addWidget (toolbar, 0); layout2->addWidget (mScene, 1); layout->insertLayout (0, layout2, 1); CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this); layout->insertWidget (0, filterBox); QWidget *widget = new QWidget; widget->setLayout (layout); setWidget (widget); mScene->selectDefaultNavigationMode(); connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest())); }
CSVWorld::RefIdTypeDelegateFactory::UidTypeList CSVWorld::RefIdTypeDelegateFactory::buildUidTypeList() const { UidTypeList list; std::vector<CSMWorld::UniversalId::Type> types = CSMWorld::UniversalId::listReferenceableTypes(); for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin()); iter!=types.end(); ++iter) { CSMWorld::UniversalId id (*iter, ""); list.push_back (std::make_pair (id.getType(), id.getIcon().c_str())); } return list; }
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) { std::ostringstream stream; CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); stream << id.toString() << "|"; if (type==ErrorMessage) stream << "error: "; else stream << "warning: "; stream << message; mMessages->push_back (stream.str()); }
void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>& messages) { const CSMWorld::Record<ESM::Faction>& record = mFactions.getRecord (stage); if (record.isDeleted()) return; const ESM::Faction& faction = record.get(); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Faction, faction.mId); // test for empty name if (faction.mName.empty()) messages.push_back (id.toString() + "|" + faction.mId + " has an empty name"); // test for invalid attributes if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) { std::ostringstream stream; stream << id.toString() << "|Faction lists same attribute twice"; messages.push_back (stream.str()); } // test for non-unique skill std::map<int, int> skills; // ID, number of occurrences for (int i=0; i<6; ++i) if (faction.mData.mSkills[i]!=-1) ++skills[faction.mData.mSkills[i]]; for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) if (iter->second>1) { std::ostringstream stream; stream << id.toString() << "|" << ESM::Skill::indexToId (iter->first) << " is listed more than once"; messages.push_back (stream.str()); } /// \todo check data members that can't be edited in the table view }
void CSMTools::RegionCheckStage::perform (int stage, std::vector<std::string>& messages) { const CSMWorld::Record<ESM::Region>& record = mRegions.getRecord (stage); if (record.isDeleted()) return; const ESM::Region& region = record.get(); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Region, region.mId); // test for empty name if (region.mName.empty()) messages.push_back (id.toString() + "|" + region.mId + " has an empty name"); /// \todo test that the ID in mSleeplist exists /// \todo check data members that can't be edited in the table view }
std::string CSMTools::MagicEffectCheckStage::checkReferenceable(const std::string &id, const CSMWorld::UniversalId &type, const std::string &column) const { std::string error; if (!id.empty()) { CSMWorld::RefIdData::LocalIndex index = mReferenceables.getDataSet().searchId(id); if (index.first == -1) { error = "No such " + column + " '" + id + "'"; } else if (index.second != type.getType()) { error = column + " is not of type " + type.getTypeName(); } } return error; }
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) { std::ostringstream stream; CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); stream << id.toString() << "|"; if (type==ErrorMessage) stream << "error "; else stream << "warning "; stream << "script " << mFile << ", line " << loc.mLine << ", column " << loc.mColumn << " (" << loc.mLiteral << "): " << message; mMessages->push_back (stream.str()); }
CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id) { QHBoxLayout *layout = new QHBoxLayout; layout->setContentsMargins (QMargins (0, 0, 0, 0)); if (document.getData().getReferenceables().searchId (id.getId())==-1) { std::string referenceableId = document.getData().getReferences().getRecord (id.getId()).get().mRefID; referenceableIdChanged (referenceableId); mScene = new CSVRender::PreviewWidget (document.getData(), referenceableId, id.getId(), this); } else mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), this); SceneToolbar *toolbar = new SceneToolbar (48+6, this); SceneToolMode *lightingTool = mScene->makeLightingSelector (toolbar); toolbar->addTool (lightingTool); layout->addWidget (toolbar, 0); layout->addWidget (mScene, 1); QWidget *widget = new QWidget; widget->setLayout (layout); setWidget (widget); connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest())); connect (mScene, SIGNAL (referenceableIdChanged (const std::string&)), this, SLOT (referenceableIdChanged (const std::string&))); }
CSVWorld::ReferenceableCreator::ReferenceableCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) : GenericCreator (data, undoStack, id) { QLabel *label = new QLabel ("Type", this); insertBeforeButtons (label, false); std::vector<CSMWorld::UniversalId::Type> types = CSMWorld::UniversalId::listReferenceableTypes(); mType = new QComboBox (this); for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin()); iter!=types.end(); ++iter) { CSMWorld::UniversalId id (*iter, ""); mType->addItem (QIcon (id.getIcon().c_str()), id.getTypeName().c_str(), static_cast<int> (id.getType())); } insertBeforeButtons (mType, false); }
CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mLayout(new QHBoxLayout), mDocument(document), mScene(NULL), mToolbar(NULL) { QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins (QMargins (0, 0, 0, 0)); layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id, this), 0); mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); CSVRender::WorldspaceWidget* wordspaceWidget = NULL; widgetType whatWidget; if (id.getId()=="sys::default") { whatWidget = widget_Paged; CSVRender::PagedWorldspaceWidget *newWidget = new CSVRender::PagedWorldspaceWidget (this, document); wordspaceWidget = newWidget; makeConnections(newWidget); } else { whatWidget = widget_Unpaged; CSVRender::UnpagedWorldspaceWidget *newWidget = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this); wordspaceWidget = newWidget; makeConnections(newWidget); } replaceToolbarAndWorldspace(wordspaceWidget, makeToolbar(wordspaceWidget, whatWidget)); layout->insertLayout (0, mLayout, 1); CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this); layout->insertWidget (0, filterBox); QWidget *widget = new QWidget; widget->setLayout (layout); setWidget (widget); }
void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& messages) { const ESM::Class& class_= mClasses.getRecord (stage).get(); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId); // test for empty name and description if (class_.mName.empty()) messages.push_back (id.toString() + "|" + class_.mId + " has an empty name"); if (class_.mDescription.empty()) messages.push_back (id.toString() + "|" + class_.mId + " has an empty description"); // test for invalid attributes for (int i=0; i<2; ++i) if (class_.mData.mAttribute[i]==-1) { std::ostringstream stream; stream << id.toString() << "|Attribute #" << i << " of " << class_.mId << " is not set"; messages.push_back (stream.str()); } if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) { std::ostringstream stream; stream << id.toString() << "|Class lists same attribute twice"; messages.push_back (stream.str()); } // test for non-unique skill std::map<int, int> skills; // ID, number of occurrences for (int i=0; i<5; ++i) for (int i2=0; i2<2; ++i2) ++skills[class_.mData.mSkills[i][i2]]; for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) if (iter->second>1) { std::ostringstream stream; stream << id.toString() << "|" << ESM::Skill::indexToId (iter->first) << " is listed more than once"; messages.push_back (stream.str()); } }
CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) : SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0) { setWidget (mEditor = new ScriptEdit (this, mDocument)); mEditor->setAcceptRichText (false); mEditor->setLineWrapMode (QTextEdit::NoWrap); mEditor->setTabStopWidth (4); mEditor->setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead mModel = &dynamic_cast<CSMWorld::IdTable&> ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); for (int i=0; i<mModel->columnCount(); ++i) if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== CSMWorld::ColumnBase::Display_Script) { mColumn = i; break; } if (mColumn==-1) throw std::logic_error ("Can't find script column"); mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); connect (&document.getData(), SIGNAL (idListChanged()), this, SLOT (idListChanged())); mHighlighter = new ScriptHighlighter (document.getData(), mEditor->document()); connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting())); mUpdateTimer.setSingleShot (true); }
void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::string>& messages) { const CSMWorld::Record<ESM::Race>& record = mRaces.getRecord (stage); if (record.isDeleted()) return; const ESM::Race& race = record.get(); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId); // test for empty name and description if (race.mName.empty()) messages.push_back (id.toString() + "|" + race.mId + " has an empty name"); if (race.mDescription.empty()) messages.push_back (id.toString() + "|" + race.mId + " has an empty description"); // test for positive height if (race.mData.mHeight.mMale<=0) messages.push_back (id.toString() + "|male " + race.mId + " has non-positive height"); if (race.mData.mHeight.mFemale<=0) messages.push_back (id.toString() + "|female " + race.mId + " has non-positive height"); // test for non-negative weight if (race.mData.mWeight.mMale<0) messages.push_back (id.toString() + "|male " + race.mId + " has negative weight"); if (race.mData.mWeight.mFemale<0) messages.push_back (id.toString() + "|female " + race.mId + " has negative weight"); // remember playable flag if (race.mData.mFlags & 0x1) mPlayable = true; /// \todo check data members that can't be edited in the table view }
void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { // configure dispatcher QModelIndexList selectedRows = selectionModel()->selectedRows(); std::vector<std::string> records; int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) { int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); records.push_back (mModel->data ( mModel->index (row, columnIndex)).toString().toUtf8().constData()); } mDispatcher->setSelection (records); std::vector<CSMWorld::UniversalId> extendedTypes = mDispatcher->getExtendedTypes(); mDispatcher->setExtendedTypes (extendedTypes); // create context menu QMenu menu (this); /// \todo add menu items for select all and clear selection { // Request UniversalId editing from table columns. int currRow = rowAt( event->y() ), currCol = columnAt( event->x() ); currRow = mProxyModel->mapToSource(mProxyModel->index( currRow, 0 )).row(); CSMWorld::ColumnBase::Display colDisplay = static_cast<CSMWorld::ColumnBase::Display>( mModel->headerData( currCol, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display ).toInt()); QString cellData = mModel->data(mModel->index( currRow, currCol )).toString(); CSMWorld::UniversalId::Type colType = CSMWorld::TableMimeData::convertEnums( colDisplay ); if ( !cellData.isEmpty() && colType != CSMWorld::UniversalId::Type_None ) { mEditCellAction->setText(tr("Edit '").append(cellData).append("'")); menu.addAction( mEditCellAction ); mEditCellId = CSMWorld::UniversalId( colType, cellData.toUtf8().constData() ); } } if (!mEditLock && !(mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) { if (selectedRows.size()==1) { menu.addAction (mEditAction); if (mCreateAction) menu.addAction(mCloneAction); } if (mCreateAction) menu.addAction (mCreateAction); if (mDispatcher->canRevert()) { menu.addAction (mRevertAction); if (!extendedTypes.empty()) menu.addAction (mExtendedRevertAction); } if (mDispatcher->canDelete()) { menu.addAction (mDeleteAction); if (!extendedTypes.empty()) menu.addAction (mExtendedDeleteAction); } if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_ReorderWithinTopic) { /// \todo allow reordering of multiple rows if (selectedRows.size()==1) { int column = mModel->searchColumnIndex (CSMWorld::Columns::ColumnId_Topic); if (column==-1) column = mModel->searchColumnIndex (CSMWorld::Columns::ColumnId_Journal); if (column!=-1) { int row = mProxyModel->mapToSource ( mProxyModel->index (selectedRows.begin()->row(), 0)).row(); QString curData = mModel->data(mModel->index(row, column)).toString(); if (row > 0) { QString prevData = mModel->data(mModel->index(row - 1, column)).toString(); if (Misc::StringUtils::ciEqual(curData.toStdString(), prevData.toStdString())) { menu.addAction(mMoveUpAction); } } if (row < mModel->rowCount() - 1) { QString nextData = mModel->data(mModel->index(row + 1, column)).toString(); if (Misc::StringUtils::ciEqual(curData.toStdString(), nextData.toStdString())) { menu.addAction(mMoveDownAction); } } } } } } if (selectedRows.size()==1) { int row = selectedRows.begin()->row(); row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row(); if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_View) { CSMWorld::UniversalId id = mModel->view (row).first; int index = mDocument.getData().getCells().searchId (id.getId()); // index==-1: the ID references a worldspace instead of a cell (ignore for now and go // ahead) if (index==-1 || !mDocument.getData().getCells().getRecord (index).isDeleted()) menu.addAction (mViewAction); } if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Preview) { QModelIndex index = mModel->index (row, mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification)); CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> ( mModel->data (index).toInt()); if (state!=CSMWorld::RecordBase::State_Deleted) menu.addAction (mPreviewAction); } } menu.exec (event->globalPos()); }
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool createAndDelete, bool sorting, CSMDoc::Document& document) : DragRecordTable(document), mCreateAction (0), mCloneAction(0),mRecordStatusDisplay (0) { CSMSettings::UserSettings &settings = CSMSettings::UserSettings::instance(); QString jumpSetting = settings.settingValue ("table-input/jump-to-added"); if (jumpSetting.isEmpty() || jumpSetting == "Jump and Select") // default { mJumpToAddedRecord = true; mUnselectAfterJump = false; } else if(jumpSetting == "Jump Only") { mJumpToAddedRecord = true; mUnselectAfterJump = true; } else { mJumpToAddedRecord = false; mUnselectAfterJump = false; } mModel = &dynamic_cast<CSMWorld::IdTableBase&> (*mDocument.getData().getTableModel (id)); bool isInfoTable = id.getType() == CSMWorld::UniversalId::Type_TopicInfos || id.getType() == CSMWorld::UniversalId::Type_JournalInfos; if (isInfoTable) { mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this); } else { mProxyModel = new CSMWorld::IdTableProxyModel (this); } mProxyModel->setSourceModel (mModel); mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); setModel (mProxyModel); #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive); #else horizontalHeader()->setResizeMode (QHeaderView::Interactive); #endif verticalHeader()->hide(); setSortingEnabled (sorting); setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); int columns = mModel->columnCount(); for (int i=0; i<columns; ++i) { int flags = mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); if (flags & CSMWorld::ColumnBase::Flag_Table) { CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display> ( mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display, mDispatcher, document, this); mDelegates.push_back (delegate); setItemDelegateForColumn (i, delegate); } else hideColumn (i); } mEditAction = new QAction (tr ("Edit Record"), this); connect (mEditAction, SIGNAL (triggered()), this, SLOT (editRecord())); addAction (mEditAction); if (createAndDelete) { mCreateAction = new QAction (tr ("Add Record"), this); connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest())); addAction (mCreateAction); mCloneAction = new QAction (tr ("Clone Record"), this); connect(mCloneAction, SIGNAL (triggered()), this, SLOT (cloneRecord())); addAction(mCloneAction); } mRevertAction = new QAction (tr ("Revert Record"), this); connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert())); addAction (mRevertAction); mDeleteAction = new QAction (tr ("Delete Record"), this); connect (mDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeDelete())); addAction (mDeleteAction); mMoveUpAction = new QAction (tr ("Move Up"), this); connect (mMoveUpAction, SIGNAL (triggered()), this, SLOT (moveUpRecord())); addAction (mMoveUpAction); mMoveDownAction = new QAction (tr ("Move Down"), this); connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord())); addAction (mMoveDownAction); mEditCellAction = new QAction( tr("Edit Cell"), this ); connect( mEditCellAction, SIGNAL(triggered()), this, SLOT(editCell()) ); addAction( mEditCellAction ); mViewAction = new QAction (tr ("View"), this); connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord())); addAction (mViewAction); mPreviewAction = new QAction (tr ("Preview"), this); connect (mPreviewAction, SIGNAL (triggered()), this, SLOT (previewRecord())); addAction (mPreviewAction); /// \todo add a user option, that redirects the extended action to an input panel (in /// the bottom bar) that lets the user select which record collections should be /// modified. mExtendedDeleteAction = new QAction (tr ("Extended Delete Record"), this); connect (mExtendedDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedDelete())); addAction (mExtendedDeleteAction); mExtendedRevertAction = new QAction (tr ("Extended Revert Record"), this); connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert())); addAction (mExtendedRevertAction); connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (tableSizeUpdate())); connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); /// \note This signal could instead be connected to a slot that filters out changes not affecting /// the records status column (for permanence reasons) connect (mProxyModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (tableSizeUpdate())); connect (selectionModel(), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT (selectionSizeUpdate ())); setAcceptDrops(true); mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_InPlaceEdit)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_EditRecord)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_View)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier | Qt::ControlModifier, Action_EditRecordAndClose)); }
void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { // configure dispatcher QModelIndexList selectedRows = selectionModel()->selectedRows(); std::vector<std::string> records; int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id); for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) { int row = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0)).row(); records.push_back (mModel->data ( mModel->index (row, columnIndex)).toString().toUtf8().constData()); } mDispatcher->setSelection (records); std::vector<CSMWorld::UniversalId> extendedTypes = mDispatcher->getExtendedTypes(); mDispatcher->setExtendedTypes (extendedTypes); // create context menu QMenu menu (this); /// \todo add menu items for select all and clear selection if (!mEditLock && !(mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) { if (selectedRows.size()==1) { menu.addAction (mEditAction); if (mCreateAction) menu.addAction(mCloneAction); } if (mCreateAction) menu.addAction (mCreateAction); if (mDispatcher->canRevert()) { menu.addAction (mRevertAction); if (!extendedTypes.empty()) menu.addAction (mExtendedRevertAction); } if (mDispatcher->canDelete()) { menu.addAction (mDeleteAction); if (!extendedTypes.empty()) menu.addAction (mExtendedDeleteAction); } if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_ReorderWithinTopic) { /// \todo allow reordering of multiple rows if (selectedRows.size()==1) { int column = mModel->searchColumnIndex (CSMWorld::Columns::ColumnId_Topic); if (column==-1) column = mModel->searchColumnIndex (CSMWorld::Columns::ColumnId_Journal); if (column!=-1) { int row = mProxyModel->mapToSource ( mProxyModel->index (selectedRows.begin()->row(), 0)).row(); if (row>0 && mModel->data (mModel->index (row, column))== mModel->data (mModel->index (row-1, column))) { menu.addAction (mMoveUpAction); } if (row<mModel->rowCount()-1 && mModel->data (mModel->index (row, column))== mModel->data (mModel->index (row+1, column))) { menu.addAction (mMoveDownAction); } } } } } if (selectedRows.size()==1) { int row = selectedRows.begin()->row(); row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row(); if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_View) { CSMWorld::UniversalId id = mModel->view (row).first; int index = mDocument.getData().getCells().searchId (id.getId()); // index==-1: the ID references a worldspace instead of a cell (ignore for now and go // ahead) if (index==-1 || !mDocument.getData().getCells().getRecord (index).isDeleted()) menu.addAction (mViewAction); } if (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Preview) { QModelIndex index = mModel->index (row, mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification)); CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> ( mModel->data (index).toInt()); if (state!=CSMWorld::RecordBase::State_Deleted) menu.addAction (mPreviewAction); } } menu.exec (event->globalPos()); }