mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-12 13:13:27 +00:00
added support for record reordering to model (only implemented in info collection)
This commit is contained in:
parent
2fff7fc843
commit
780ea3a41f
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -123,3 +123,25 @@ 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);
|
||||
}
|
@ -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
|
@ -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
|
||||
{
|
||||
@ -168,3 +165,16 @@ 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;
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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) + "#" +
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user