Merge branch 'refs'

deque
Marc Zinnschlag 11 years ago
commit c23e9e03fd

@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc
opencs_units (model/world
idtable idtableproxymodel regionmap data
idtable idtableproxymodel regionmap data commanddispatcher
)

@ -0,0 +1,267 @@
#include "commanddispatcher.hpp"
#include <algorithm>
#include <components/misc/stringops.hpp>
#include "../doc/document.hpp"
#include "idtable.hpp"
#include "record.hpp"
#include "commands.hpp"
std::vector<std::string> CSMWorld::CommandDispatcher::getDeletableRecords() const
{
std::vector<std::string> result;
IdTable& model = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
int stateColumnIndex = model.findColumnIndex (Columns::ColumnId_Modification);
for (std::vector<std::string>::const_iterator iter (mSelection.begin());
iter!=mSelection.end(); ++iter)
{
int row = model.getModelIndex (*iter, 0).row();
// check record state
RecordBase::State state = static_cast<RecordBase::State> (
model.data (model.index (row, stateColumnIndex)).toInt());
if (state==RecordBase::State_Deleted)
continue;
// check other columns (only relevant for a subset of the tables)
int dialogueTypeIndex = model.searchColumnIndex (Columns::ColumnId_DialogueType);
if (dialogueTypeIndex!=-1)
{
int type = model.data (model.index (row, dialogueTypeIndex)).toInt();
if (type!=ESM::Dialogue::Topic && type!=ESM::Dialogue::Journal)
continue;
}
result.push_back (*iter);
}
return result;
}
std::vector<std::string> CSMWorld::CommandDispatcher::getRevertableRecords() const
{
std::vector<std::string> result;
IdTable& model = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
/// \todo Reverting temporarily disabled on tables that support reordering, because
/// revert logic currently can not handle reordering.
if (model.getFeatures() & IdTable::Feature_ReorderWithinTopic)
return result;
int stateColumnIndex = model.findColumnIndex (Columns::ColumnId_Modification);
for (std::vector<std::string>::const_iterator iter (mSelection.begin());
iter!=mSelection.end(); ++iter)
{
int row = model.getModelIndex (*iter, 0).row();
// check record state
RecordBase::State state = static_cast<RecordBase::State> (
model.data (model.index (row, stateColumnIndex)).toInt());
if (state==RecordBase::State_BaseOnly)
continue;
result.push_back (*iter);
}
return result;
}
CSMWorld::CommandDispatcher::CommandDispatcher (CSMDoc::Document& document,
const CSMWorld::UniversalId& id, QObject *parent)
: QObject (parent), mDocument (document), mId (id), mLocked (false)
{}
void CSMWorld::CommandDispatcher::setEditLock (bool locked)
{
mLocked = locked;
}
void CSMWorld::CommandDispatcher::setSelection (const std::vector<std::string>& selection)
{
mSelection = selection;
std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLower);
std::sort (mSelection.begin(), mSelection.end());
}
void CSMWorld::CommandDispatcher::setExtendedTypes (const std::vector<UniversalId>& types)
{
mExtendedTypes = types;
}
bool CSMWorld::CommandDispatcher::canDelete() const
{
if (mLocked)
return false;
return getDeletableRecords().size()!=0;
}
bool CSMWorld::CommandDispatcher::canRevert() const
{
if (mLocked)
return false;
return getRevertableRecords().size()!=0;
}
std::vector<CSMWorld::UniversalId> CSMWorld::CommandDispatcher::getExtendedTypes() const
{
std::vector<CSMWorld::UniversalId> tables;
if (mId==UniversalId::Type_Cells)
{
tables.push_back (mId);
tables.push_back (UniversalId::Type_References);
/// \todo add other cell-specific types
}
return tables;
}
void CSMWorld::CommandDispatcher::executeDelete()
{
if (mLocked)
return;
std::vector<std::string> rows = getDeletableRecords();
if (rows.empty())
return;
IdTable& model = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
int columnIndex = model.findColumnIndex (Columns::ColumnId_Id);
if (rows.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Delete multiple records"));
for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
{
std::string id = model.data (model.getModelIndex (*iter, columnIndex)).
toString().toUtf8().constData();
mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id));
}
if (rows.size()>1)
mDocument.getUndoStack().endMacro();
}
void CSMWorld::CommandDispatcher::executeRevert()
{
if (mLocked)
return;
std::vector<std::string> rows = getRevertableRecords();
if (rows.empty())
return;
IdTable& model = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
int columnIndex = model.findColumnIndex (Columns::ColumnId_Id);
if (rows.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Revert multiple records"));
for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
{
std::string id = model.data (model.getModelIndex (*iter, columnIndex)).
toString().toUtf8().constData();
mDocument.getUndoStack().push (new CSMWorld::RevertCommand (model, id));
}
if (rows.size()>1)
mDocument.getUndoStack().endMacro();
}
void CSMWorld::CommandDispatcher::executeExtendedDelete()
{
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Extended delete of multiple records"));
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
iter!=mExtendedTypes.end(); ++iter)
{
if (*iter==mId)
executeDelete();
else if (*iter==UniversalId::Type_References)
{
IdTable& model = dynamic_cast<IdTable&> (
*mDocument.getData().getTableModel (*iter));
const RefCollection& collection = mDocument.getData().getReferences();
int size = collection.getSize();
for (int i=size-1; i>=0; --i)
{
const Record<CellRef>& record = collection.getRecord (i);
if (record.mState==RecordBase::State_Deleted)
continue;
if (!std::binary_search (mSelection.begin(), mSelection.end(),
Misc::StringUtils::lowerCase (record.get().mCell)))
continue;
mDocument.getUndoStack().push (
new CSMWorld::DeleteCommand (model, record.get().mId));
}
}
}
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().endMacro();
}
void CSMWorld::CommandDispatcher::executeExtendedRevert()
{
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Extended revert of multiple records"));
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
iter!=mExtendedTypes.end(); ++iter)
{
if (*iter==mId)
executeRevert();
else if (*iter==UniversalId::Type_References)
{
IdTable& model = dynamic_cast<IdTable&> (
*mDocument.getData().getTableModel (*iter));
const RefCollection& collection = mDocument.getData().getReferences();
int size = collection.getSize();
for (int i=size-1; i>=0; --i)
{
const Record<CellRef>& record = collection.getRecord (i);
if (!std::binary_search (mSelection.begin(), mSelection.end(),
Misc::StringUtils::lowerCase (record.get().mCell)))
continue;
mDocument.getUndoStack().push (
new CSMWorld::RevertCommand (model, record.get().mId));
}
}
}
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().endMacro();
}

@ -0,0 +1,69 @@
#ifndef CSM_WOLRD_COMMANDDISPATCHER_H
#define CSM_WOLRD_COMMANDDISPATCHER_H
#include <vector>
#include <QObject>
#include "universalid.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
class CommandDispatcher : public QObject
{
Q_OBJECT
bool mLocked;
CSMDoc::Document& mDocument;
UniversalId mId;
std::vector<std::string> mSelection;
std::vector<UniversalId> mExtendedTypes;
std::vector<std::string> getDeletableRecords() const;
std::vector<std::string> getRevertableRecords() const;
public:
CommandDispatcher (CSMDoc::Document& document, const CSMWorld::UniversalId& id,
QObject *parent = 0);
///< \param id ID of the table the commands should operate on primarily.
void setEditLock (bool locked);
void setSelection (const std::vector<std::string>& selection);
void setExtendedTypes (const std::vector<UniversalId>& types);
///< Set record lists selected by the user for extended operations.
bool canDelete() const;
bool canRevert() const;
/// Return IDs of the record collection that can also be affected when
/// operating on the record collection this dispatcher is used for.
///
/// \note The returned collection contains the ID of the record collection this
/// dispatcher is used for. However if that record collection does not support
/// the extended mode, the returned vector will be empty instead.
std::vector<UniversalId> getExtendedTypes() const;
public slots:
void executeDelete();
void executeRevert();
void executeExtendedDelete();
void executeExtendedRevert();
};
}
#endif

@ -16,11 +16,12 @@
#include "regionmap.hpp"
#include "columns.hpp"
void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1,
UniversalId::Type type2, bool update)
void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update)
{
mModels.push_back (model);
mModelIndex.insert (std::make_pair (type1, model));
mModelIndex.insert (std::make_pair (type, model));
UniversalId::Type type2 = UniversalId::getParentType (type);
if (type2!=UniversalId::Type_None)
mModelIndex.insert (std::make_pair (type2, model));
@ -235,26 +236,26 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding)
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill, false);
addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class);
addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction);
addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race);
addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound);
addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script);
addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region);
addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign);
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic);
addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal);
addModel (new IdTable (&mTopicInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo);
addModel (new IdTable (&mJournalInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo);
addModel (new IdTable (&mCells, IdTable::Reordering_None, IdTable::Viewing_Id), UniversalId::Type_Cells, UniversalId::Type_Cell);
addModel (new IdTable (&mReferenceables, IdTable::Reordering_None, IdTable::Viewing_None, true),
UniversalId::Type_Referenceables, UniversalId::Type_Referenceable);
addModel (new IdTable (&mRefs, IdTable::Reordering_None, IdTable::Viewing_Cell, true), UniversalId::Type_References, UniversalId::Type_Reference, false);
addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false);
addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
addModel (new IdTable (&mClasses), UniversalId::Type_Class);
addModel (new IdTable (&mFactions), UniversalId::Type_Faction);
addModel (new IdTable (&mRaces), UniversalId::Type_Race);
addModel (new IdTable (&mSounds), UniversalId::Type_Sound);
addModel (new IdTable (&mScripts), UniversalId::Type_Script);
addModel (new IdTable (&mRegions), UniversalId::Type_Region);
addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsign);
addModel (new IdTable (&mSpells), UniversalId::Type_Spell);
addModel (new IdTable (&mTopics), UniversalId::Type_Topic);
addModel (new IdTable (&mJournals), UniversalId::Type_Journal);
addModel (new IdTable (&mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo);
addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo);
addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell);
addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview),
UniversalId::Type_Referenceable);
addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference);
addModel (new IdTable (&mFilters), UniversalId::Type_Filter);
}
CSMWorld::Data::~Data()
@ -469,8 +470,7 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId&
if (id.getType()==UniversalId::Type_RegionMap)
{
RegionMap *table = 0;
addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap,
UniversalId::Type_None, false);
addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, false);
return table;
}
throw std::logic_error ("No table model available for " + id.toString());

@ -83,8 +83,8 @@ namespace CSMWorld
Data (const Data&);
Data& operator= (const Data&);
void addModel (QAbstractItemModel *model, UniversalId::Type type1,
UniversalId::Type type2 = UniversalId::Type_None, bool update = true);
void addModel (QAbstractItemModel *model, UniversalId::Type type,
bool update = true);
static void appendIds (std::vector<std::string>& ids, const CollectionBase& collection,
bool listDeleted);

@ -4,9 +4,8 @@
#include "collectionbase.hpp"
#include "columnbase.hpp"
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering,
Viewing viewing, bool preview)
: mIdCollection (idCollection), mReordering (reordering), mViewing (viewing), mPreview (preview)
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features)
: mIdCollection (idCollection), mFeatures (features)
{}
CSMWorld::IdTable::~IdTable()
@ -186,19 +185,9 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newO
index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1));
}
CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const
unsigned int CSMWorld::IdTable::getFeatures() const
{
return mReordering;
}
CSMWorld::IdTable::Viewing CSMWorld::IdTable::getViewing() const
{
return mViewing;
}
bool CSMWorld::IdTable::hasPreview() const
{
return mPreview;
return mFeatures;
}
std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row) const
@ -206,7 +195,7 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
std::string id;
std::string hint;
if (mViewing==Viewing_Cell)
if (mFeatures & Feature_ViewCell)
{
int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell);
int idColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
@ -217,7 +206,7 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
hint = "r:" + std::string (mIdCollection->getData (row, idColumn).toString().toUtf8().constData());
}
}
else if (mViewing==Viewing_Id)
else if (mFeatures & Feature_ViewId)
{
int column = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);

@ -19,26 +19,27 @@ namespace CSMWorld
public:
enum Reordering
enum Features
{
Reordering_None,
Reordering_WithinTopic
};
Feature_ReorderWithinTopic = 1,
enum Viewing
{
Viewing_None,
Viewing_Id, // use ID column to generate view request (ID is transformed into
// worldspace and original ID is passed as hint with c: prefix)
Viewing_Cell // use cell column to generate view request (cell ID is transformed
// into worldspace and record ID is passed as hint with r: prefix)
/// Use ID column to generate view request (ID is transformed into
/// worldspace and original ID is passed as hint with c: prefix).
Feature_ViewId = 2,
/// Use cell column to generate view request (cell ID is transformed
/// into worldspace and record ID is passed as hint with r: prefix).
Feature_ViewCell = 4,
Feature_View = Feature_ViewId | Feature_ViewCell,
Feature_Preview = 8
};
private:
CollectionBase *mIdCollection;
Reordering mReordering;
Viewing mViewing;
unsigned int mFeatures;
bool mPreview;
// not implemented
@ -47,8 +48,7 @@ namespace CSMWorld
public:
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_None,
Viewing viewing = Viewing_None, bool preview = false);
IdTable (CollectionBase *idCollection, unsigned int features = 0);
///< The ownership of \a idCollection is not transferred.
virtual ~IdTable();
@ -97,11 +97,7 @@ namespace CSMWorld
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
Reordering getReordering() const;
Viewing getViewing() const;
bool hasPreview() const;
unsigned int getFeatures() const;
std::pair<UniversalId, std::string> view (int row) const;
///< Return the UniversalId and the hint for viewing \a row. If viewing is not

@ -61,8 +61,8 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables", 0 },
@ -90,7 +90,7 @@ namespace
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" },
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 },
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 0 },
@ -320,6 +320,28 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listReferenceabl
return list;
}
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type)
{
for (int i=0; sIdArg[i].mType; ++i)
if (type==sIdArg[i].mType)
{
if (sIdArg[i].mClass==Class_RefRecord)
return Type_Referenceables;
if (sIdArg[i].mClass==Class_SubRecord || sIdArg[i].mClass==Class_Record)
{
if (type==Type_Cell_Missing)
return Type_Cells;
return static_cast<Type> (type-1);
}
break;
}
return Type_None;
}
bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
{
return left.isEqual (right);

@ -32,6 +32,8 @@ namespace CSMWorld
ArgumentType_Index
};
/// \note A record list type must always be immediately followed by the matching
/// record type, if this type is of class SubRecord or Record.
enum Type
{
Type_None = 0,
@ -86,8 +88,8 @@ namespace CSMWorld
Type_References,
Type_Reference,
Type_RegionMap,
Type_Filter,
Type_Filters,
Type_Filter,
Type_Topics,
Type_Topic,
Type_Journals,
@ -147,6 +149,11 @@ namespace CSMWorld
///< Will return an empty string, if no icon is available.
static std::vector<Type> listReferenceableTypes();
/// If \a type is a SubRecord, RefRecord or Record type return the type of the table
/// that contains records of type \a type.
/// Otherwise return Type_None.
static Type getParentType (Type type);
};
bool operator== (const UniversalId& left, const UniversalId& right);

@ -332,6 +332,7 @@ void CSVWorld::EditWidget::remake(int row)
if (mMainWidget)
{
delete mMainWidget;
mMainWidget = 0;
}
mMainWidget = new QWidget (this);
@ -339,6 +340,7 @@ void CSVWorld::EditWidget::remake(int row)
if (mWidgetMapper)
{
delete mWidgetMapper;
mWidgetMapper = 0;
}
mWidgetMapper = new QDataWidgetMapper (this);
mWidgetMapper->setModel(mTable);
@ -396,7 +398,7 @@ void CSVWorld::EditWidget::remake(int row)
mWidgetMapper->setCurrentModelIndex(mTable->index(row, 0));
this->setMinimumWidth(325); //TODO find better way to set the width or make it customizable
this->setMinimumWidth(325); /// \todo replace hardcoded value with a user setting
this->setWidget(mMainWidget);
this->setWidgetResizable(true);
}
@ -407,7 +409,6 @@ void CSVWorld::EditWidget::remake(int row)
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
const CreatorFactoryBase& creatorFactory, bool sorting) :
SubView (id),
mEditWidget(0),
mMainLayout(NULL),
@ -415,8 +416,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
mTable(dynamic_cast<CSMWorld::IdTable*>(document.getData().getTableModel(id))),
mRow (-1),
mLocked(false),
mDocument(document)
mDocument(document),
mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType()))
{
connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&)));
mRow = mTable->getModelIndex (id.getId(), 0).row();
@ -440,7 +441,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
QToolButton* revertButton = new QToolButton(mainWidget);
revertButton->setIcon(QIcon(":/edit-undo.png"));
if (mTable->hasPreview())
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview)
{
QToolButton* previewButton = new QToolButton(mainWidget);
previewButton->setIcon(QIcon(":/edit-preview.png"));
@ -448,7 +449,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
}
if (mTable->getViewing()!=CSMWorld::IdTable::Viewing_None)
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_View)
{
QToolButton* viewButton = new QToolButton(mainWidget);
viewButton->setIcon(QIcon(":/cell.png"));
@ -560,14 +561,12 @@ void CSVWorld::DialogueSubView::nextId()
void CSVWorld::DialogueSubView::setEditLock (bool locked)
{
mLocked = locked;
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (mRow, 1)).toInt());
if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)
{
mEditWidget->setDisabled(true);
} else
{
mEditWidget->setDisabled(mLocked);
}
mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || locked);
mCommandDispatcher.setEditLock (locked);
}
void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index)
@ -575,13 +574,8 @@ void CSVWorld::DialogueSubView::dataChanged(const QModelIndex & index)
if (index.row() == mRow)
{
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (mRow, 1)).toInt());
if (state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased)
{
mEditWidget->setDisabled(true);
} else
{
mEditWidget->setDisabled(mLocked);
}
mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked);
}
}
@ -671,7 +665,8 @@ void CSVWorld::DialogueSubView::cloneRequest ()
void CSVWorld::DialogueSubView::showPreview ()
{
if (mTable->hasPreview() && mRow < mTable->rowCount())
if ((mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview) &&
mRow < mTable->rowCount())
{
emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mTable->data(mTable->index (mRow, 0)).toString().toUtf8().constData()), "");
}

@ -8,7 +8,9 @@
#include <QScrollArea>
#include "../doc/subview.hpp"
#include "../../model/world/columnbase.hpp"
#include "../../model/world/commanddispatcher.hpp"
class QDataWidgetMapper;
class QSize;
@ -169,6 +171,7 @@ namespace CSVWorld
bool mLocked;
const CSMDoc::Document& mDocument;
TableBottomBox* mBottom;
CSMWorld::CommandDispatcher mCommandDispatcher;
public:

@ -80,30 +80,35 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory<SceneSubView>);
//edit subviews
manager.add (CSMWorld::UniversalId::Type_Region,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Spell,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
// Dialogue subviews
static const CSMWorld::UniversalId::Type sTableTypes2[] =
{
CSMWorld::UniversalId::Type_Region,
CSMWorld::UniversalId::Type_Spell,
CSMWorld::UniversalId::Type_Birthsign,
CSMWorld::UniversalId::Type_Global,
CSMWorld::UniversalId::Type_Race,
CSMWorld::UniversalId::Type_Class,
CSMWorld::UniversalId::Type_Filter,
CSMWorld::UniversalId::Type_Sound,
CSMWorld::UniversalId::Type_Faction,
manager.add (CSMWorld::UniversalId::Type_Referenceable,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceableCreator> > (false));
CSMWorld::UniversalId::Type_None // end marker
};
manager.add (CSMWorld::UniversalId::Type_Birthsign,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
for (int i=0; sTableTypes2[i]!=CSMWorld::UniversalId::Type_None; ++i)
manager.add (sTableTypes2[i],
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView,
CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Global,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Skill,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, NullCreatorFactory > (false));
manager.add (CSMWorld::UniversalId::Type_Gmst,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Race,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, NullCreatorFactory > (false));
manager.add (CSMWorld::UniversalId::Type_Class,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Referenceable,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceableCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Reference,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceCreator> > (false));
@ -111,18 +116,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Cell,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<CellCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Filter,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Sound,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Faction,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Skill,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_JournalInfo,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<InfoCreator> > (false));

@ -19,14 +19,36 @@
#include "../../model/world/columns.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/commanddispatcher.hpp"
#include "recordstatusdelegate.hpp"
#include "util.hpp"
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
@ -44,22 +66,27 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
if (mCreateAction)
menu.addAction (mCreateAction);
/// \todo Reverting temporarily disabled on tables that support reordering, because
/// revert logic currently can not handle reordering.
if (mModel->getReordering()==CSMWorld::IdTable::Reordering_None)
if (listRevertableSelectedIds().size()>0)
if (mDispatcher->canRevert())
{
menu.addAction (mRevertAction);
if (listDeletableSelectedIds().size()>0)
if (!extendedTypes.empty())
menu.addAction (mExtendedRevertAction);
}
if (mDispatcher->canDelete())
{
menu.addAction (mDeleteAction);
if (mModel->getReordering()==CSMWorld::IdTable::Reordering_WithinTopic)
if (!extendedTypes.empty())
menu.addAction (mExtendedDeleteAction);
}
if (mModel->getFeatures() & CSMWorld::IdTable::Feature_ReorderWithinTopic)
{
/// \todo allow reordering of multiple rows
if (selectedRows.size()==1)
{
int row =selectedRows.begin()->row();
int column = mModel->searchColumnIndex (CSMWorld::Columns::ColumnId_Topic);
if (column==-1)
@ -67,14 +94,17 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
if (column!=-1)
{
if (row>0 && mProxyModel->data (mProxyModel->index (row, column))==
mProxyModel->data (mProxyModel->index (row-1, column)))
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<mProxyModel->rowCount()-1 && mProxyModel->data (mProxyModel->index (row, column))==
mProxyModel->data (mProxyModel->index (row+1, column)))
if (row<mModel->rowCount()-1 && mModel->data (mModel->index (row, column))==
mModel->data (mModel->index (row+1, column)))
{
menu.addAction (mMoveDownAction);
}
@ -85,7 +115,7 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
if (selectedRows.size()==1)
{
if (mModel->getViewing()!=CSMWorld::IdTable::Viewing_None)
if (mModel->getFeatures() & CSMWorld::IdTable::Feature_View)
{
int row = selectedRows.begin()->row();
@ -101,91 +131,13 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
menu.addAction (mViewAction);
}
if (mModel->hasPreview())
if (mModel->getFeatures() & CSMWorld::IdTable::Feature_Preview)
menu.addAction (mPreviewAction);
}
menu.exec (event->globalPos());
}
std::vector<std::string> CSVWorld::Table::listRevertableSelectedIds() const
{
std::vector<std::string> revertableIds;
if (mProxyModel->columnCount()>0)
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter)
{
QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0));
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (
mModel->data (mModel->index (index.row(), 1)).toInt());
if (state!=CSMWorld::RecordBase::State_BaseOnly)
{
int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
std::string id = mModel->data (mModel->index (index.row(), columnIndex)).
toString().toUtf8().constData();
revertableIds.push_back (id);
}
}
}
return revertableIds;
}
std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
{
std::vector<std::string> deletableIds;
if (mProxyModel->columnCount()>0)
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter)
{
QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0));
// check record state
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (
mModel->data (mModel->index (index.row(), 1)).toInt());
if (state==CSMWorld::RecordBase::State_Deleted)
continue;
// check other columns (only relevant for a subset of the tables)
int dialogueTypeIndex =
mModel->searchColumnIndex (CSMWorld::Columns::ColumnId_DialogueType);
if (dialogueTypeIndex!=-1)
{
int type = mModel->data (mModel->index (index.row(), dialogueTypeIndex)).toInt();
if (type!=ESM::Dialogue::Topic && type!=ESM::Dialogue::Journal)
continue;
}
// add the id to the collection
int columnIndex = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
std::string id = mModel->data (mModel->index (index.row(), columnIndex)).
toString().toUtf8().constData();
deletableIds.push_back (id);
}
}
return deletableIds;
}
CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
bool createAndDelete, bool sorting, CSMDoc::Document& document)
: mCreateAction (0), mCloneAction(0), mRecordStatusDisplay (0),
@ -196,6 +148,8 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
mProxyModel = new CSMWorld::IdTableProxyModel (this);
mProxyModel->setSourceModel (mModel);
mDispatcher = new CSMWorld::CommandDispatcher (document, id, this);
setModel (mProxyModel);
horizontalHeader()->setResizeMode (QHeaderView::Interactive);
verticalHeader()->hide();
@ -240,11 +194,11 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
}
mRevertAction = new QAction (tr ("Revert Record"), this);
connect (mRevertAction, SIGNAL (triggered()), this, SLOT (revertRecord()));
connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert()));
addAction (mRevertAction);
mDeleteAction = new QAction (tr ("Delete Record"), this);
connect (mDeleteAction, SIGNAL (triggered()), this, SLOT (deleteRecord()));
connect (mDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeDelete()));
addAction (mDeleteAction);
mMoveUpAction = new QAction (tr ("Move Up"), this);
@ -263,6 +217,18 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
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 (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (tableSizeUpdate()));
@ -283,53 +249,19 @@ void CSVWorld::Table::setEditLock (bool locked)
(*iter)->setEditLock (locked);
DragRecordTable::setEditLock(locked);
mDispatcher->setEditLock (locked);
}
CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const
{
return CSMWorld::UniversalId (
static_cast<CSMWorld::UniversalId::Type> (mProxyModel->data (mProxyModel->index (row, 2)).toInt()),
mProxyModel->data (mProxyModel->index (row, 0)).toString().toUtf8().constData());
}
void CSVWorld::Table::revertRecord()
{
if (!mEditLock)
{
std::vector<std::string> revertableIds = listRevertableSelectedIds();
if (!revertableIds.empty())
{
if (revertableIds.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Revert multiple records"));
for (std::vector<std::string>::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter)
mDocument.getUndoStack().push (new CSMWorld::RevertCommand (*mModel, *iter));
if (revertableIds.size()>1)
mDocument.getUndoStack().endMacro();
}
}
}
void CSVWorld::Table::deleteRecord()
{
if (!mEditLock)
{
std::vector<std::string> deletableIds = listDeletableSelectedIds();
if (!deletableIds.empty())
{
if (deletableIds.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Delete multiple records"));
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
for (std::vector<std::string>::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter)
mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (*mModel, *iter));
int idColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int typeColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_RecordType);
if (deletableIds.size()>1)
mDocument.getUndoStack().endMacro();
}
}
return CSMWorld::UniversalId (
static_cast<CSMWorld::UniversalId::Type> (mModel->data (mModel->index (row, typeColumn)).toInt()),
mModel->data (mModel->index (row, idColumn)).toString().toUtf8().constData());
}
void CSVWorld::Table::editRecord()

@ -24,6 +24,7 @@ namespace CSMWorld
class UniversalId;
class IdTableProxyModel;
class IdTable;
class CommandDispatcher;
}
namespace CSVWorld
@ -45,18 +46,17 @@ namespace CSVWorld
QAction *mMoveDownAction;
QAction *mViewAction;
QAction *mPreviewAction;
QAction *mExtendedDeleteAction;
QAction *mExtendedRevertAction;
CSMWorld::IdTableProxyModel *mProxyModel;
CSMWorld::IdTable *mModel;
int mRecordStatusDisplay;
CSMWorld::CommandDispatcher *mDispatcher;
private:
void contextMenuEvent (QContextMenuEvent *event);
std::vector<std::string> listRevertableSelectedIds() const;
std::vector<std::string> listDeletableSelectedIds() const;
void mouseMoveEvent(QMouseEvent *event);
void dropEvent(QDropEvent *event);
@ -93,10 +93,6 @@ namespace CSVWorld
private slots:
void revertRecord();
void deleteRecord();
void editRecord();
void cloneRecord();

Loading…
Cancel
Save