1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-12 04:14:05 +00:00

added support for record reordering to model (only implemented in info collection)

This commit is contained in:
Marc Zinnschlag 2013-11-14 11:39:14 +01:00
parent 2fff7fc843
commit 780ea3a41f
12 changed files with 267 additions and 8 deletions

View File

@ -57,6 +57,12 @@ namespace CSMWorld
const std::vector<Record<ESXRecordT> >& getRecords() const;
bool reorderRowsImp (int baseIndex, const std::vector<int>& newOrder);
///< 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).
///
/// \return Success?
public:
Collection();
@ -128,6 +134,12 @@ namespace CSMWorld
/// If the index is invalid either generally (by being out of range) or for the particular
/// record, an exception is thrown.
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
///< 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).
///
/// \return Success?
void addColumn (Column<ESXRecordT> *column);
void setRecord (int index, const Record<ESXRecordT>& record);
@ -146,6 +158,38 @@ namespace CSMWorld
return mRecords;
}
template<typename ESXRecordT, typename IdAccessorT>
bool Collection<ESXRecordT, IdAccessorT>::reorderRowsImp (int baseIndex,
const std::vector<int>& newOrder)
{
if (!newOrder.empty())
{
int size = static_cast<int> (newOrder.size());
// check that all indices are present
std::vector<int> test (newOrder);
std::sort (test.begin(), test.end());
if (*test.begin()!=0 || *--test.end()!=size-1)
return false;
// reorder records
std::vector<Record<ESXRecordT> > buffer (size);
for (int i=0; i<size; ++i)
buffer[newOrder[i]] = mRecords [baseIndex+i];
std::copy (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
// adjust index
for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
++iter)
if (iter->second>=baseIndex && iter->second<baseIndex+size)
iter->second = newOrder.at (iter->second-baseIndex)+baseIndex;
}
return true;
}
template<typename ESXRecordT, typename IdAccessorT>
Collection<ESXRecordT, IdAccessorT>::Collection()
{}
@ -389,6 +433,12 @@ namespace CSMWorld
mRecords.at (index) = record;
}
template<typename ESXRecordT, typename IdAccessorT>
bool Collection<ESXRecordT, IdAccessorT>::reorderRows (int baseIndex, const std::vector<int>& newOrder)
{
return false;
}
}
#endif

View File

@ -2,6 +2,7 @@
#define CSM_WOLRD_COLLECTIONBASE_H
#include <string>
#include <vector>
#include "universalid.hpp"
#include "columns.hpp"
@ -86,6 +87,12 @@ namespace CSMWorld
///
/// \param listDeleted include deleted record in the list
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder) = 0;
///< 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).
///
/// \return Success?
int searchColumnIndex (Columns::ColumnId id) const;
///< Return index of column with the given \a id. If no such column exists, -1 is returned.

View File

@ -122,4 +122,26 @@ void CSMWorld::DeleteCommand::redo()
void CSMWorld::DeleteCommand::undo()
{
mModel.setRecord (mId, *mOld);
}
CSMWorld::ReorderRowsCommand::ReorderRowsCommand (IdTable& model, int baseIndex,
const std::vector<int>& newOrder)
: mModel (model), mBaseIndex (baseIndex), mNewOrder (newOrder)
{}
void CSMWorld::ReorderRowsCommand::redo()
{
mModel.reorderRows (mBaseIndex, mNewOrder);
}
void CSMWorld::ReorderRowsCommand::undo()
{
int size = static_cast<int> (mNewOrder.size());
std::vector<int> reverse (size);
for (int i=0; i<size; ++i)
reverse.at (mNewOrder[i]) = i;
mModel.reorderRows (mBaseIndex, reverse);
}

View File

@ -5,6 +5,7 @@
#include <string>
#include <map>
#include <vector>
#include <QVariant>
#include <QUndoCommand>
@ -99,6 +100,21 @@ namespace CSMWorld
virtual void undo();
};
class ReorderRowsCommand : public QUndoCommand
{
IdTable& mModel;
int mBaseIndex;
std::vector<int> mNewOrder;
public:
ReorderRowsCommand (IdTable& model, int baseIndex, const std::vector<int>& newOrder);
virtual void redo();
virtual void undo();
};
}
#endif

View File

@ -4,15 +4,12 @@
#include "collectionbase.hpp"
#include "columnbase.hpp"
CSMWorld::IdTable::IdTable (CollectionBase *idCollection) : mIdCollection (idCollection)
{
}
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering)
: mIdCollection (idCollection), mReordering (reordering)
{}
CSMWorld::IdTable::~IdTable()
{
}
{}
int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const
{
@ -167,4 +164,17 @@ int CSMWorld::IdTable::searchColumnIndex (Columns::ColumnId id) const
int CSMWorld::IdTable::findColumnIndex (Columns::ColumnId id) const
{
return mIdCollection->findColumnIndex (id);
}
void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newOrder)
{
if (!newOrder.empty())
if (mIdCollection->reorderRows (baseIndex, newOrder))
emit dataChanged (index (baseIndex, 0),
index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1));
}
CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const
{
return mReordering;
}

View File

@ -1,6 +1,8 @@
#ifndef CSM_WOLRD_IDTABLE_H
#define CSM_WOLRD_IDTABLE_H
#include <vector>
#include <QAbstractItemModel>
#include "universalid.hpp"
@ -15,7 +17,18 @@ namespace CSMWorld
{
Q_OBJECT
public:
enum Reordering
{
Reordering_None,
Reordering_WithinTopic
};
private:
CollectionBase *mIdCollection;
Reordering mReordering;
// not implemented
IdTable (const IdTable&);
@ -23,7 +36,7 @@ namespace CSMWorld
public:
IdTable (CollectionBase *idCollection);
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_WithinTopic);
///< The ownership of \a idCollection is not transferred.
virtual ~IdTable();
@ -63,6 +76,12 @@ namespace CSMWorld
int findColumnIndex (Columns::ColumnId id) const;
///< Return index of column with the given \a id. If no such column exists, an exception is
/// thrown.
void reorderRows (int baseIndex, const std::vector<int>& newOrder);
///< 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;
};
}

View File

@ -88,6 +88,22 @@ int CSMWorld::InfoCollection::getAppendIndex (const std::string& id, UniversalId
return std::distance (getRecords().begin(), range.second);
}
bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int>& newOrder)
{
// check if the range is valid
int lastIndex = baseIndex + newOrder.size() -1;
if (lastIndex>=getSize())
return false;
// Check that topics match
if (getRecord (baseIndex).get().mTopicId!=getRecord (lastIndex).get().mTopicId)
return false;
// reorder
return reorderRowsImp (baseIndex, newOrder);
}
void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue)
{
std::string id = Misc::StringUtils::lowerCase (dialogue.mId) + "#" +

View File

@ -33,6 +33,12 @@ namespace CSMWorld
UniversalId::Type type = UniversalId::Type_None) const;
///< \param type Will be ignored, unless the collection supports multiple record types
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
///< 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).
///
/// \return Success?
void load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue);
Range getTopicRange (const std::string& topic) const;

View File

@ -540,6 +540,11 @@ std::vector<std::string> CSMWorld::RefIdCollection::getIds (bool listDeleted) co
return mData.getIds (listDeleted);
}
bool CSMWorld::RefIdCollection::reorderRows (int baseIndex, const std::vector<int>& newOrder)
{
return false;
}
void CSMWorld::RefIdCollection::save (int index, ESM::ESMWriter& writer) const
{
mData.save (index, writer);

View File

@ -100,6 +100,12 @@ namespace CSMWorld
///
/// \param listDeleted include deleted record in the list
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
///< 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).
///
/// \return Success?
void save (int index, ESM::ESMWriter& writer) const;
};
}

View File

@ -12,6 +12,7 @@
#include "../../model/world/idtableproxymodel.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp"
#include "../../model/world/columns.hpp"
#include "recordstatusdelegate.hpp"
#include "util.hpp"
@ -37,6 +38,35 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
if (listDeletableSelectedIds().size()>0)
menu.addAction (mDeleteAction);
if (mModel->getReordering()==CSMWorld::IdTable::Reordering_WithinTopic)
{
/// \todo allow reordering of multiple rows
if (selectedRows.size()==1)
{
int row =selectedRows.begin()->row();
int column = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Topic);
if (column==-1)
column = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Journal);
if (column!=-1)
{
if (row>0 && mProxyModel->data (mProxyModel->index (row, column))==
mProxyModel->data (mProxyModel->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)))
{
menu.addAction (mMoveDownAction);
}
}
}
}
}
menu.exec (event->globalPos());
@ -176,6 +206,14 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
connect (mDeleteAction, SIGNAL (triggered()), this, SLOT (deleteRecord()));
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);
connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (tableSizeUpdate()));
@ -254,6 +292,64 @@ void CSVWorld::Table::editRecord()
}
}
void CSVWorld::Table::moveUpRecord()
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
if (selectedRows.size()==1)
{
int row2 =selectedRows.begin()->row();
if (row2>0)
{
int row = row2-1;
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
row2 = mProxyModel->mapToSource (mProxyModel->index (row2, 0)).row();
if (row2<=row)
throw std::runtime_error ("Inconsistent row order");
std::vector<int> newOrder (row2-row+1);
newOrder[0] = row2-row;
newOrder[row2-row] = 0;
for (int i=1; i<row2-row; ++i)
newOrder[i] = i;
mUndoStack.push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
}
}
}
void CSVWorld::Table::moveDownRecord()
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
if (selectedRows.size()==1)
{
int row =selectedRows.begin()->row();
if (row<mProxyModel->rowCount()-1)
{
int row2 = row+1;
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
row2 = mProxyModel->mapToSource (mProxyModel->index (row2, 0)).row();
if (row2<=row)
throw std::runtime_error ("Inconsistent row order");
std::vector<int> newOrder (row2-row+1);
newOrder[0] = row2-row;
newOrder[row2-row] = 0;
for (int i=1; i<row2-row; ++i)
newOrder[i] = i;
mUndoStack.push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
}
}
}
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
int columns = mModel->columnCount();

View File

@ -34,6 +34,8 @@ namespace CSVWorld
QAction *mCreateAction;
QAction *mRevertAction;
QAction *mDeleteAction;
QAction *mMoveUpAction;
QAction *mMoveDownAction;
CSMWorld::IdTableProxyModel *mProxyModel;
CSMWorld::IdTable *mModel;
bool mEditLock;
@ -80,6 +82,10 @@ namespace CSVWorld
void editRecord();
void moveUpRecord();
void moveDownRecord();
public slots:
void tableSizeUpdate();