Merge branch 'master' of https://github.com/OpenMW/openmw into osg

Conflicts:
	apps/opencs/CMakeLists.txt
c++11
scrawl 10 years ago
commit 1956e2c988

@ -26,7 +26,7 @@ opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
idcompletionmanager idcompletionmanager metadata
) )
opencs_hdrs_noqt (model/world opencs_hdrs_noqt (model/world
@ -64,18 +64,18 @@ opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview cellcreator referenceablecreator referencecreator scenesubview
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
dialoguespinbox dialoguespinbox recordbuttonbar
) )
opencs_units_noqt (view/world opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator idcompletiondelegate scripthighlighter idvalidator dialoguecreator idcompletiondelegate
colordelegate colordelegate dragdroputils
) )
opencs_units (view/widget opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2 completerpopup coloreditor colorpickerpopup scenetooltoggle2 completerpopup coloreditor colorpickerpopup droplineedit
) )
opencs_units (view/render opencs_units (view/render

@ -2280,9 +2280,6 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM
if (mNew) if (mNew)
{ {
mData.setDescription ("");
mData.setAuthor ("");
if (mContentFiles.size()==1) if (mContentFiles.size()==1)
createBase(); createBase();
} }
@ -2372,9 +2369,9 @@ void CSMDoc::Document::save()
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
CSMWorld::UniversalId CSMDoc::Document::verify() CSMWorld::UniversalId CSMDoc::Document::verify (const CSMWorld::UniversalId& reportId)
{ {
CSMWorld::UniversalId id = mTools.runVerifier(); CSMWorld::UniversalId id = mTools.runVerifier (reportId);
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
return id; return id;
} }

@ -124,7 +124,7 @@ namespace CSMDoc
void save(); void save();
CSMWorld::UniversalId verify(); CSMWorld::UniversalId verify (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
CSMWorld::UniversalId newSearch(); CSMWorld::UniversalId newSearch();

@ -53,18 +53,16 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages)
mState.getWriter().clearMaster(); mState.getWriter().clearMaster();
mState.getWriter().setFormat (0);
if (mSimple) if (mSimple)
{ {
mState.getWriter().setAuthor (""); mState.getWriter().setAuthor ("");
mState.getWriter().setDescription (""); mState.getWriter().setDescription ("");
mState.getWriter().setRecordCount (0); mState.getWriter().setRecordCount (0);
mState.getWriter().setFormat (ESM::Header::CurrentFormat);
} }
else else
{ {
mState.getWriter().setAuthor (mDocument.getData().getAuthor()); mDocument.getData().getMetaData().save (mState.getWriter());
mState.getWriter().setDescription (mDocument.getData().getDescription());
mState.getWriter().setRecordCount ( mState.getWriter().setRecordCount (
mDocument.getData().count (CSMWorld::RecordBase::State_Modified) + mDocument.getData().count (CSMWorld::RecordBase::State_Modified) +
mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) + mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) +

@ -339,6 +339,14 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip); formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip);
} }
declareSection ("general-input", "General Input");
{
Setting *cycle = createSetting (Type_CheckBox, "cycle", "Cyclic next/previous");
cycle->setDefaultValue ("false");
cycle->setToolTip ("When using next/previous functions at the last/first item of a "
"list go to the first/last item");
}
{ {
/****************************************************************** /******************************************************************
* There are three types of values: * There are three types of values:

@ -30,9 +30,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
// check the number of pathgrid points // check the number of pathgrid points
if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size())) if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
messages.push_back (std::make_pair (id, pathgrid.mId + " has less points than expected")); messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error);
else if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size())) else if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
messages.push_back (std::make_pair (id, pathgrid.mId + " has more points than expected")); messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error);
std::vector<CSMTools::Point> pointList(pathgrid.mPoints.size()); std::vector<CSMTools::Point> pointList(pathgrid.mPoints.size());
std::vector<int> duplList; std::vector<int> duplList;
@ -51,7 +51,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
std::ostringstream ss; std::ostringstream ss;
ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0 ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0
<< " and " << pathgrid.mEdges[i].mV1; << " and " << pathgrid.mEdges[i].mV1;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
break; break;
} }
} }
@ -64,7 +64,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0; ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
} }
@ -75,13 +75,13 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has has less edges than expected for point " << i; ss << " has has less edges than expected for point " << i;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum) else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum)
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has has more edges than expected for point " << i; ss << " has has more edges than expected for point " << i;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
// check that edges are bidirectional // check that edges are bidirectional
@ -101,7 +101,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j];
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
} }
@ -124,7 +124,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
<< ") x=" << pathgrid.mPoints[i].mX << ") x=" << pathgrid.mPoints[i].mX
<< ", y=" << pathgrid.mPoints[i].mY << ", y=" << pathgrid.mPoints[i].mY
<< ", z=" << pathgrid.mPoints[i].mZ; << ", z=" << pathgrid.mPoints[i].mZ;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning);
duplList.push_back(i); duplList.push_back(i);
break; break;
@ -143,7 +143,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
<< ") x=" << pathgrid.mPoints[i].mX << ") x=" << pathgrid.mPoints[i].mX
<< ", y=" << pathgrid.mPoints[i].mY << ", y=" << pathgrid.mPoints[i].mY
<< ", z=" << pathgrid.mPoints[i].mZ; << ", z=" << pathgrid.mPoints[i].mZ;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning);
} }
} }

@ -120,7 +120,7 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value) void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value)
{ {
if (name=="script-editor/warnings") if (name=="script-editor/warnings" && !value.isEmpty())
{ {
if (value.at (0)=="Ignore") if (value.at (0)=="Ignore")
mWarningMode = Mode_Ignore; mWarningMode = Mode_Ignore;

@ -146,14 +146,19 @@ CSMTools::Tools::~Tools()
delete iter->second; delete iter->second;
} }
CSMWorld::UniversalId CSMTools::Tools::runVerifier() CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& reportId)
{ {
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); int reportNumber = reportId.getType()==CSMWorld::UniversalId::Type_VerificationResults ?
mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1; reportId.getIndex() : mNextReportNumber++;
if (mReports.find (reportNumber)==mReports.end())
mReports.insert (std::make_pair (reportNumber, new ReportModel));
mActiveReports[CSMDoc::State_Verifying] = reportNumber;
getVerifier()->start(); getVerifier()->start();
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, reportNumber);
} }
CSMWorld::UniversalId CSMTools::Tools::newSearch() CSMWorld::UniversalId CSMTools::Tools::newSearch()

@ -57,8 +57,11 @@ namespace CSMTools
virtual ~Tools(); virtual ~Tools();
CSMWorld::UniversalId runVerifier(); /// \param reportId If a valid VerificationResults ID, run verifier for the
///< \return ID of the report for this verification run /// specified report instead of creating a new one.
///
/// \return ID of the report for this verification run
CSMWorld::UniversalId runVerifier (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
/// Return ID of the report for this search. /// Return ID of the report for this search.
CSMWorld::UniversalId newSearch(); CSMWorld::UniversalId newSearch();

@ -100,7 +100,8 @@ bool CSMWorld::ColumnBase::isId (Display display)
bool CSMWorld::ColumnBase::isText (Display display) bool CSMWorld::ColumnBase::isText (Display display)
{ {
return display==Display_String || display==Display_LongString; return display==Display_String || display==Display_LongString ||
display==Display_String32 || display==Display_LongString256;
} }
bool CSMWorld::ColumnBase::isScript (Display display) bool CSMWorld::ColumnBase::isScript (Display display)

@ -123,6 +123,8 @@ namespace CSMWorld
Display_InfoCondVar, Display_InfoCondVar,
Display_InfoCondComp, Display_InfoCondComp,
Display_RaceSkill, Display_RaceSkill,
Display_String32,
Display_LongString256,
//top level columns that nest other columns //top level columns that nest other columns
Display_NestedHeader Display_NestedHeader

@ -2308,6 +2308,78 @@ namespace CSMWorld
return true; return true;
} }
}; };
template<typename ESXRecordT>
struct FormatColumn : public Column<ESXRecordT>
{
FormatColumn()
: Column<ESXRecordT> (Columns::ColumnId_FileFormat, ColumnBase::Display_Integer)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mFormat;
}
virtual bool isEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct AuthorColumn : public Column<ESXRecordT>
{
AuthorColumn()
: Column<ESXRecordT> (Columns::ColumnId_Author, ColumnBase::Display_String32)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mAuthor.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mAuthor = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct FileDescriptionColumn : public Column<ESXRecordT>
{
FileDescriptionColumn()
: Column<ESXRecordT> (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString256)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mDescription.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mDescription = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
} }
#endif #endif

@ -311,6 +311,10 @@ namespace CSMWorld
{ ColumnId_WaterLevel, "Water Level" }, { ColumnId_WaterLevel, "Water Level" },
{ ColumnId_MapColor, "Map Color" }, { ColumnId_MapColor, "Map Color" },
{ ColumnId_FileFormat, "File Format" },
{ ColumnId_FileDescription, "File Description" },
{ ColumnId_Author, "Author" },
{ ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue1, "Use value 1" },
{ ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue2, "Use value 2" },
{ ColumnId_UseValue3, "Use value 3" }, { ColumnId_UseValue3, "Use value 3" },

@ -302,6 +302,10 @@ namespace CSMWorld
ColumnId_WaterLevel = 273, ColumnId_WaterLevel = 273,
ColumnId_MapColor = 274, ColumnId_MapColor = 274,
ColumnId_FileFormat = 275,
ColumnId_FileDescription = 276,
ColumnId_Author = 277,
// Allocated to a separate value range, so we don't get a collision should we ever need // Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values. // to extend the number of use values.
ColumnId_UseValue1 = 0x10000, ColumnId_UseValue1 = 0x10000,

@ -475,6 +475,14 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> ( mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
ScriptColumn<ESM::DebugProfile>::Type_Lines)); ScriptColumn<ESM::DebugProfile>::Type_Lines));
mMetaData.appendBlankRecord ("sys::meta");
mMetaData.addColumn (new StringIdColumn<MetaData> (true));
mMetaData.addColumn (new RecordStateColumn<MetaData>);
mMetaData.addColumn (new FormatColumn<MetaData>);
mMetaData.addColumn (new AuthorColumn<MetaData>);
mMetaData.addColumn (new FileDescriptionColumn<MetaData>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
@ -515,6 +523,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
UniversalId::Type_Texture); UniversalId::Type_Texture);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)), addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
UniversalId::Type_Video); UniversalId::Type_Video);
addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData);
mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files
} }
@ -813,6 +822,11 @@ const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id)
return mResourcesManager.get (id.getType()); return mResourcesManager.get (id.getType());
} }
const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const
{
return mMetaData.getRecord (0).get();
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
{ {
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType()); std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -857,9 +871,15 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
mBase = base; mBase = base;
mProject = project; mProject = project;
mAuthor = mReader->getAuthor(); if (!mProject && !mBase)
mDescription = mReader->getDesc(); {
MetaData metaData;
metaData.mId = "sys::meta";
metaData.load (*mReader);
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
}
return mReader->getRecordCount(); return mReader->getRecordCount();
} }
@ -1113,26 +1133,6 @@ int CSMWorld::Data::count (RecordBase::State state) const
count (state, mPathgrids); count (state, mPathgrids);
} }
void CSMWorld::Data::setDescription (const std::string& description)
{
mDescription = description;
}
std::string CSMWorld::Data::getDescription() const
{
return mDescription;
}
void CSMWorld::Data::setAuthor (const std::string& author)
{
mAuthor = author;
}
std::string CSMWorld::Data::getAuthor() const
{
return mAuthor;
}
std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const
{ {
std::vector<std::string> ids; std::vector<std::string> ids;

@ -46,6 +46,7 @@
#include "infocollection.hpp" #include "infocollection.hpp"
#include "nestedinfocollection.hpp" #include "nestedinfocollection.hpp"
#include "pathgrid.hpp" #include "pathgrid.hpp"
#include "metadata.hpp"
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include "subcellcollection.hpp" #include "subcellcollection.hpp"
#endif #endif
@ -101,11 +102,10 @@ namespace CSMWorld
RefIdCollection mReferenceables; RefIdCollection mReferenceables;
RefCollection mRefs; RefCollection mRefs;
IdCollection<ESM::Filter> mFilters; IdCollection<ESM::Filter> mFilters;
Collection<MetaData> mMetaData;
const ResourcesManager& mResourcesManager; const ResourcesManager& mResourcesManager;
std::vector<QAbstractItemModel *> mModels; std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex; std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
std::string mAuthor;
std::string mDescription;
ESM::ESMReader *mReader; ESM::ESMReader *mReader;
const ESM::Dialogue *mDialogue; // last loaded dialogue const ESM::Dialogue *mDialogue; // last loaded dialogue
bool mBase; bool mBase;
@ -253,6 +253,8 @@ namespace CSMWorld
/// Throws an exception, if \a id does not match a resources list. /// Throws an exception, if \a id does not match a resources list.
const Resources& getResources (const UniversalId& id) const; const Resources& getResources (const UniversalId& id) const;
const MetaData& getMetaData() const;
QAbstractItemModel *getTableModel (const UniversalId& id); QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown. ///< If no table model is available for \a id, an exception is thrown.
/// ///
@ -282,14 +284,6 @@ namespace CSMWorld
int count (RecordBase::State state) const; int count (RecordBase::State state) const;
///< Return number of top-level records with the given \a state. ///< Return number of top-level records with the given \a state.
void setDescription (const std::string& description);
std::string getDescription() const;
void setAuthor (const std::string& author);
std::string getAuthor() const;
signals: signals:
void idListChanged(); void idListChanged();

@ -97,7 +97,8 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int
return false; return false;
// Check that topics match // Check that topics match
if (getRecord (baseIndex).get().mTopicId!=getRecord (lastIndex).get().mTopicId) if (!Misc::StringUtils::ciEqual(getRecord(baseIndex).get().mTopicId,
getRecord(lastIndex).get().mTopicId))
return false; return false;
// reorder // reorder

@ -1,12 +1,24 @@
#include "infotableproxymodel.hpp" #include "infotableproxymodel.hpp"
#include <components/misc/stringops.hpp>
#include "idtablebase.hpp" #include "idtablebase.hpp"
#include "columns.hpp" #include "columns.hpp"
namespace
{
QString toLower(const QString &str)
{
return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str());
}
}
CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent)
: IdTableProxyModel(parent), : IdTableProxyModel(parent),
mType(type), mType(type),
mSourceModel(NULL) mSourceModel(NULL),
mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic :
Columns::ColumnId_Journal)
{ {
Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos);
} }
@ -15,44 +27,53 @@ void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceMod
{ {
IdTableProxyModel::setSourceModel(sourceModel); IdTableProxyModel::setSourceModel(sourceModel);
mSourceModel = dynamic_cast<IdTableBase *>(sourceModel); mSourceModel = dynamic_cast<IdTableBase *>(sourceModel);
connect(mSourceModel, if (mSourceModel != NULL)
SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), {
this, connect(mSourceModel,
SLOT(modelDataChanged(const QModelIndex &, const QModelIndex &))); SIGNAL(rowsInserted(const QModelIndex &, int, int)),
mFirstRowCache.clear(); this,
SLOT(modelRowsChanged(const QModelIndex &, int, int)));
connect(mSourceModel,
SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
this,
SLOT(modelRowsChanged(const QModelIndex &, int, int)));
mFirstRowCache.clear();
}
} }
bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{ {
QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column());
QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column());
// If both indexes are belonged to the same Topic/Journal, compare their original rows only
if (first.row() == second.row())
{
return sortOrder() == Qt::AscendingOrder ? left.row() < right.row() : right.row() < left.row();
}
return IdTableProxyModel::lessThan(first, second); return IdTableProxyModel::lessThan(first, second);
} }
int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const
{ {
Columns::ColumnId columnId = Columns::ColumnId_Topic; int row = currentRow;
if (mType == UniversalId::Type_JournalInfos) int column = mSourceModel->findColumnIndex(mInfoColumnId);
{ QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString());
columnId = Columns::ColumnId_Journal;
}
int column = mSourceModel->findColumnIndex(columnId);
QString info = mSourceModel->data(mSourceModel->index(currentRow, column)).toString();
if (mFirstRowCache.contains(info)) if (mFirstRowCache.contains(info))
{ {
return mFirstRowCache[info]; return mFirstRowCache[info];
} }
while (--currentRow >= 0 && while (--row >= 0 &&
mSourceModel->data(mSourceModel->index(currentRow, column)) == info); toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()) == info);
++row;
mFirstRowCache[info] = currentRow + 1; mFirstRowCache[info] = row;
return currentRow + 1; return row;
} }
void CSMWorld::InfoTableProxyModel::modelDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/)
{ {
mFirstRowCache.clear(); mFirstRowCache.clear();
} }

@ -4,6 +4,7 @@
#include <QHash> #include <QHash>
#include "idtableproxymodel.hpp" #include "idtableproxymodel.hpp"
#include "columns.hpp"
#include "universalid.hpp" #include "universalid.hpp"
namespace CSMWorld namespace CSMWorld
@ -16,6 +17,8 @@ namespace CSMWorld
UniversalId::Type mType; UniversalId::Type mType;
IdTableBase *mSourceModel; IdTableBase *mSourceModel;
Columns::ColumnId mInfoColumnId;
///< Contains ID for Topic or Journal ID
mutable QHash<QString, int> mFirstRowCache; mutable QHash<QString, int> mFirstRowCache;
@ -31,7 +34,7 @@ namespace CSMWorld
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
private slots: private slots:
void modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void modelRowsChanged(const QModelIndex &parent, int start, int end);
}; };
} }

@ -0,0 +1,27 @@
#include "metadata.hpp"
#include <components/esm/loadtes3.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
void CSMWorld::MetaData::blank()
{
mFormat = ESM::Header::CurrentFormat;
mAuthor.clear();
mDescription.clear();
}
void CSMWorld::MetaData::load (ESM::ESMReader& esm)
{
mFormat = esm.getHeader().mFormat;
mAuthor = esm.getHeader().mData.author.toString();
mDescription = esm.getHeader().mData.desc.toString();
}
void CSMWorld::MetaData::save (ESM::ESMWriter& esm) const
{
esm.setFormat (mFormat);
esm.setAuthor (mAuthor);
esm.setDescription (mDescription);
}

@ -0,0 +1,29 @@
#ifndef CSM_WOLRD_METADATA_H
#define CSM_WOLRD_METADATA_H
#include <string>
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace CSMWorld
{
struct MetaData
{
std::string mId;
int mFormat;
std::string mAuthor;
std::string mDescription;
void blank();
void load (ESM::ESMReader& esm);
void save (ESM::ESMWriter& esm) const;
};
}
#endif

@ -192,4 +192,8 @@ void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& top
emit dataChanged(index(0,0), emit dataChanged(index(0,0),
index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1)); index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1));
} }
else if (topLeft.parent() == parent && bottomRight.parent() == parent)
{
emit dataChanged(index(topLeft.row(), topLeft.column()), index(bottomRight.row(), bottomRight.column()));
}
} }

@ -264,6 +264,8 @@ namespace
{ CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture }, { CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture },
{ CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video }, { CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video },
{ CSMWorld::UniversalId::Type_Global, CSMWorld::ColumnBase::Display_GlobalVariable }, { CSMWorld::UniversalId::Type_Global, CSMWorld::ColumnBase::Display_GlobalVariable },
{ CSMWorld::UniversalId::Type_BodyPart, CSMWorld::ColumnBase::Display_BodyPart },
{ CSMWorld::UniversalId::Type_Enchantment, CSMWorld::ColumnBase::Display_Enchantment },
{ CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker { CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker
}; };

@ -56,6 +56,7 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };
@ -120,6 +121,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };

@ -131,6 +131,8 @@ namespace CSMWorld
Type_StartScripts, Type_StartScripts,
Type_StartScript, Type_StartScript,
Type_Search, Type_Search,
Type_MetaDatas,
Type_MetaData,
Type_RunLog Type_RunLog
}; };

@ -45,6 +45,7 @@ void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id)
{ {
mUniversalId = id; mUniversalId = id;
setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str())); setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str()));
emit universalIdChanged (mUniversalId);
} }
void CSVDoc::SubView::closeEvent (QCloseEvent *event) void CSVDoc::SubView::closeEvent (QCloseEvent *event)

@ -68,6 +68,8 @@ namespace CSVDoc
void updateSubViewIndicies (SubView *view = 0); void updateSubViewIndicies (SubView *view = 0);
void universalIdChanged (const CSMWorld::UniversalId& universalId);
protected slots: protected slots:
void closeRequest(); void closeRequest();

@ -70,6 +70,10 @@ void CSVDoc::View::setupFileMenu()
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
file->addAction (loadErrors); file->addAction (loadErrors);
QAction *meta = new QAction (tr ("Meta Data"), this);
connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView()));
file->addAction (meta);
QAction *close = new QAction (tr ("&Close"), this); QAction *close = new QAction (tr ("&Close"), this);
connect (close, SIGNAL (triggered()), this, SLOT (close())); connect (close, SIGNAL (triggered()), this, SLOT (close()));
file->addAction(close); file->addAction(close);
@ -813,6 +817,11 @@ void CSVDoc::View::addSearchSubView()
addSubView (mDocument->newSearch()); addSubView (mDocument->newSearch());
} }
void CSVDoc::View::addMetaDataSubView()
{
addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta"));
}
void CSVDoc::View::abortOperation (int type) void CSVDoc::View::abortOperation (int type)
{ {
mDocument->abortOperation (type); mDocument->abortOperation (type);

@ -224,6 +224,8 @@ namespace CSVDoc
void addSearchSubView(); void addSearchSubView();
void addMetaDataSubView();
void toggleShowStatusBar (bool show); void toggleShowStatusBar (bool show);
void loadErrorLog(); void loadErrorLog();

@ -4,12 +4,23 @@
#include "reporttable.hpp" #include "reporttable.hpp"
CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: CSVDoc::SubView (id) : CSVDoc::SubView (id), mDocument (document), mRefreshState (0)
{ {
setWidget (mTable = new ReportTable (document, id, false, this)); if (id.getType()==CSMWorld::UniversalId::Type_VerificationResults)
mRefreshState = CSMDoc::State_Verifying;
setWidget (mTable = new ReportTable (document, id, false, mRefreshState, this));
connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)),
SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)));
if (mRefreshState==CSMDoc::State_Verifying)
{
connect (mTable, SIGNAL (refreshRequest()), this, SLOT (refreshRequest()));
connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)),
mTable, SLOT (stateChanged (int, CSMDoc::Document *)));
}
} }
void CSVTools::ReportSubView::setEditLock (bool locked) void CSVTools::ReportSubView::setEditLock (bool locked)
@ -21,3 +32,15 @@ void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStr
{ {
mTable->updateUserSetting (name, list); mTable->updateUserSetting (name, list);
} }
void CSVTools::ReportSubView::refreshRequest()
{
if (!(mDocument.getState() & mRefreshState))
{
if (mRefreshState==CSMDoc::State_Verifying)
{
mTable->clear();
mDocument.verify (getUniversalId());
}
}
}

@ -20,6 +20,8 @@ namespace CSVTools
Q_OBJECT Q_OBJECT
ReportTable *mTable; ReportTable *mTable;
CSMDoc::Document& mDocument;
int mRefreshState;
public: public:
@ -28,6 +30,10 @@ namespace CSVTools
virtual void setEditLock (bool locked); virtual void setEditLock (bool locked);
virtual void updateUserSetting (const QString &, const QStringList &); virtual void updateUserSetting (const QString &, const QStringList &);
private slots:
void refreshRequest();
}; };
} }

@ -74,8 +74,10 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event)
if (found) if (found)
menu.addAction (mReplaceAction); menu.addAction (mReplaceAction);
} }
if (mRefreshAction)
menu.addAction (mRefreshAction);
menu.exec (event->globalPos()); menu.exec (event->globalPos());
} }
@ -134,8 +136,10 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)
} }
CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) const CSMWorld::UniversalId& id, bool richTextDescription, int refreshState,
: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) QWidget *parent)
: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)),
mRefreshAction (0), mRefreshState (refreshState)
{ {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive); horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive);
@ -171,6 +175,14 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest()));
addAction (mReplaceAction); addAction (mReplaceAction);
if (mRefreshState)
{
mRefreshAction = new QAction (tr ("Refresh"), this);
mRefreshAction->setEnabled (!(mDocument.getState() & mRefreshState));
connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest()));
addAction (mRefreshAction);
}
mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit));
mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove));
mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove));
@ -287,3 +299,9 @@ void CSVTools::ReportTable::clear()
{ {
mModel->clear(); mModel->clear();
} }
void CSVTools::ReportTable::stateChanged (int state, CSMDoc::Document *document)
{
if (mRefreshAction)
mRefreshAction->setEnabled (!(state & mRefreshState));
}

@ -36,7 +36,9 @@ namespace CSVTools
QAction *mShowAction; QAction *mShowAction;
QAction *mRemoveAction; QAction *mRemoveAction;
QAction *mReplaceAction; QAction *mReplaceAction;
QAction *mRefreshAction;
std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions; std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions;
int mRefreshState;
private: private:
@ -49,8 +51,11 @@ namespace CSVTools
public: public:
/// \param richTextDescription Use rich text in the description column. /// \param richTextDescription Use rich text in the description column.
/// \param refreshState Document state to check for refresh function. If value is
/// 0 no refresh function exists. If the document current has the specified state
/// the refresh function is disabled.
ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id,
bool richTextDescription, QWidget *parent = 0); bool richTextDescription, int refreshState = 0, QWidget *parent = 0);
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const; virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;
@ -71,11 +76,17 @@ namespace CSVTools
void removeSelection(); void removeSelection();
public slots:
void stateChanged (int state, CSMDoc::Document *document);
signals: signals:
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
void replaceRequest(); void replaceRequest();
void refreshRequest();
}; };
} }

@ -0,0 +1,41 @@
#include "droplineedit.hpp"
#include <QDropEvent>
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/universalid.hpp"
#include "../world/dragdroputils.hpp"
CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::ColumnBase::Display type, QWidget *parent)
: QLineEdit(parent),
mDropType(type)
{
setAcceptDrops(true);
}
void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event)
{
if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType))
{
event->acceptProposedAction();
}
}
void CSVWidget::DropLineEdit::dragMoveEvent(QDragMoveEvent *event)
{
if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType))
{
event->accept();
}
}
void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event)
{
if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType))
{
CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType);
setText(QString::fromUtf8(id.getId().c_str()));
emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr());
}
}

@ -0,0 +1,41 @@
#ifndef CSV_WIDGET_DROPLINEEDIT_HPP
#define CSV_WIDGET_DROPLINEEDIT_HPP
#include <QLineEdit>
#include "../../model/world/columnbase.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
class TableMimeData;
class UniversalId;
}
namespace CSVWidget
{
class DropLineEdit : public QLineEdit
{
Q_OBJECT
CSMWorld::ColumnBase::Display mDropType;
///< The accepted Display type for this LineEdit.
public:
DropLineEdit(CSMWorld::ColumnBase::Display type, QWidget *parent = 0);
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
signals:
void tableMimeDataDropped(const CSMWorld::UniversalId &id, const CSMDoc::Document *document);
};
}
#endif

@ -17,8 +17,6 @@
#include <QLineEdit> #include <QLineEdit>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QComboBox> #include <QComboBox>
#include <QPushButton>
#include <QToolButton>
#include <QHeaderView> #include <QHeaderView>
#include <QScrollBar> #include <QScrollBar>
@ -34,11 +32,13 @@
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../widget/coloreditor.hpp" #include "../widget/coloreditor.hpp"
#include "../widget/droplineedit.hpp"
#include "recordstatusdelegate.hpp" #include "recordstatusdelegate.hpp"
#include "util.hpp" #include "util.hpp"
#include "tablebottombox.hpp" #include "tablebottombox.hpp"
#include "nestedtable.hpp" #include "nestedtable.hpp"
#include "recordbuttonbar.hpp"
/* /*
==============================NotEditableSubDelegate========================================== ==============================NotEditableSubDelegate==========================================
*/ */
@ -63,16 +63,24 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo
} }
} }
CSMWorld::Columns::ColumnId columnId = static_cast<CSMWorld::Columns::ColumnId> (
mTable->getColumnId (index.column()));
if (QVariant::String == v.type()) if (QVariant::String == v.type())
{ {
label->setText(v.toString()); label->setText(v.toString());
} }
else //else we are facing enums else if (CSMWorld::Columns::hasEnums (columnId))
{ {
int data = v.toInt(); int data = v.toInt();
std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (static_cast<CSMWorld::Columns::ColumnId> (mTable->getColumnId (index.column())))); std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (columnId));
label->setText(QString::fromUtf8(enumNames.at(data).c_str())); label->setText(QString::fromUtf8(enumNames.at(data).c_str()));
} }
else
{
label->setText (v.toString());
}
} }
void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
@ -129,52 +137,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcherProxy::getEditor() const
return mEditor; return mEditor;
} }
void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data, const CSMDoc::Document* document)
{
QLineEdit* lineEdit = qobject_cast<QLineEdit*>(mEditor);
{
if (!lineEdit || !mIndexWrapper.get())
{
return;
}
}
for (unsigned i = 0; i < data.size(); ++i)
{
CSMWorld::UniversalId::Type type = data[i].getType();
if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable)
{
if (type == CSMWorld::UniversalId::Type_Activator
|| type == CSMWorld::UniversalId::Type_Potion
|| type == CSMWorld::UniversalId::Type_Apparatus
|| type == CSMWorld::UniversalId::Type_Armor
|| type == CSMWorld::UniversalId::Type_Book
|| type == CSMWorld::UniversalId::Type_Clothing
|| type == CSMWorld::UniversalId::Type_Container
|| type == CSMWorld::UniversalId::Type_Creature
|| type == CSMWorld::UniversalId::Type_Door
|| type == CSMWorld::UniversalId::Type_Ingredient
|| type == CSMWorld::UniversalId::Type_CreatureLevelledList
|| type == CSMWorld::UniversalId::Type_ItemLevelledList
|| type == CSMWorld::UniversalId::Type_Light
|| type == CSMWorld::UniversalId::Type_Lockpick
|| type == CSMWorld::UniversalId::Type_Miscellaneous
|| type == CSMWorld::UniversalId::Type_Npc
|| type == CSMWorld::UniversalId::Type_Probe
|| type == CSMWorld::UniversalId::Type_Repair
|| type == CSMWorld::UniversalId::Type_Static
|| type == CSMWorld::UniversalId::Type_Weapon)
{
type = CSMWorld::UniversalId::Type_Referenceable;
}
}
if (mDisplay == CSMWorld::TableMimeData::convertEnums(type))
{
emit tableMimeDataDropped(mEditor, mIndexWrapper->mIndex, data[i], document);
emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay);
break;
}
}
}
/* /*
==============================DialogueDelegateDispatcher========================================== ==============================DialogueDelegateDispatcher==========================================
*/ */
@ -306,16 +268,12 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
// NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry // NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry
// is required here // is required here
if (qobject_cast<DropLineEdit*>(editor)) if (qobject_cast<CSVWidget::DropLineEdit*>(editor))
{ {
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
connect(editor, SIGNAL(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*)), connect(editor, SIGNAL(tableMimeDataDropped(const CSMWorld::UniversalId&, const CSMDoc::Document*)),
proxy, SLOT(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*))); proxy, SLOT(editorDataCommited()));
connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
} }
else if (qobject_cast<QCheckBox*>(editor)) else if (qobject_cast<QCheckBox*>(editor))
{ {
@ -386,9 +344,6 @@ mCommandDispatcher (commandDispatcher),
mDocument (document) mDocument (document)
{ {
remake (row); remake (row);
connect(mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
} }
void CSVWorld::EditWidget::remake(int row) void CSVWorld::EditWidget::remake(int row)
@ -600,17 +555,37 @@ void CSVWorld::EditWidget::remake(int row)
this->setWidgetResizable(true); this->setWidgetResizable(true);
} }
/*
==============================DialogueSubView==========================================
*/
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, QVBoxLayout& CSVWorld::SimpleDialogueSubView::getMainLayout()
const CreatorFactoryBase& creatorFactory, bool sorting) : {
return *mMainLayout;
}
CSMWorld::IdTable& CSVWorld::SimpleDialogueSubView::getTable()
{
return *mTable;
}
CSMWorld::CommandDispatcher& CSVWorld::SimpleDialogueSubView::getCommandDispatcher()
{
return mCommandDispatcher;
}
CSVWorld::EditWidget& CSVWorld::SimpleDialogueSubView::getEditWidget()
{
return *mEditWidget;
}
bool CSVWorld::SimpleDialogueSubView::isLocked() const
{
return mLocked;
}
CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) :
SubView (id), SubView (id),
mEditWidget(0), mEditWidget(0),
mMainLayout(NULL), mMainLayout(NULL),
mTable(dynamic_cast<CSMWorld::IdTable*>(document.getData().getTableModel(id))), mTable(dynamic_cast<CSMWorld::IdTable*>(document.getData().getTableModel(id))),
mUndoStack(document.getUndoStack()),
mLocked(false), mLocked(false),
mDocument(document), mDocument(document),
mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType())) mCommandDispatcher (document, CSMWorld::UniversalId::getParentType (id.getType()))
@ -618,171 +593,29 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&))); connect(mTable, SIGNAL(dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT(dataChanged(const QModelIndex&)));
connect(mTable, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), this, SLOT(rowsAboutToBeRemoved(const QModelIndex&, int, int))); connect(mTable, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)), this, SLOT(rowsAboutToBeRemoved(const QModelIndex&, int, int)));
changeCurrentId(id.getId()); updateCurrentId();
QWidget *mainWidget = new QWidget(this); QWidget *mainWidget = new QWidget(this);
QHBoxLayout *buttonsLayout = new QHBoxLayout;
QToolButton* prevButton = new QToolButton(mainWidget);
prevButton->setIcon(QIcon(":/go-previous.png"));
prevButton->setToolTip ("Switch to previous record");
QToolButton* nextButton = new QToolButton(mainWidget);
nextButton->setIcon(QIcon(":/go-next.png"));
nextButton->setToolTip ("Switch to next record");
buttonsLayout->addWidget(prevButton, 0);
buttonsLayout->addWidget(nextButton, 1);
buttonsLayout->addStretch(2);
QToolButton* cloneButton = new QToolButton(mainWidget);
cloneButton->setIcon(QIcon(":/edit-clone.png"));
cloneButton->setToolTip ("Clone record");
QToolButton* addButton = new QToolButton(mainWidget);
addButton->setIcon(QIcon(":/add.png"));
addButton->setToolTip ("Add new record");
QToolButton* deleteButton = new QToolButton(mainWidget);
deleteButton->setIcon(QIcon(":/edit-delete.png"));
deleteButton->setToolTip ("Delete record");
QToolButton* revertButton = new QToolButton(mainWidget);
revertButton->setIcon(QIcon(":/edit-undo.png"));
revertButton->setToolTip ("Revert record");
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview)
{
QToolButton* previewButton = new QToolButton(mainWidget);
previewButton->setIcon(QIcon(":/edit-preview.png"));
previewButton->setToolTip ("Open a preview of this record");
buttonsLayout->addWidget(previewButton);
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
}
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_View)
{
QToolButton* viewButton = new QToolButton(mainWidget);
viewButton->setIcon(QIcon(":/cell.png"));
viewButton->setToolTip ("Open a scene view of the cell this record is located in");
buttonsLayout->addWidget(viewButton);
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord()));
}
buttonsLayout->addWidget(cloneButton);
buttonsLayout->addWidget(addButton);
buttonsLayout->addWidget(deleteButton);
buttonsLayout->addWidget(revertButton);
connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId()));
connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId()));
connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest()));
connect(revertButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeRevert()));
connect(deleteButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeDelete()));
mMainLayout = new QVBoxLayout(mainWidget); mMainLayout = new QVBoxLayout(mainWidget);
setWidget (mainWidget);
mEditWidget = new EditWidget(mainWidget, mEditWidget = new EditWidget(mainWidget,
mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); mTable->getModelIndex(getUniversalId().getId(), 0).row(), mTable, mCommandDispatcher, document, false);
connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
mMainLayout->addWidget(mEditWidget); mMainLayout->addWidget(mEditWidget);
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
mMainLayout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this)); dataChanged(mTable->getModelIndex (getUniversalId().getId(), 0));
mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&)));
connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest()));
if(!mBottom->canCreateAndDelete())
{
cloneButton->setDisabled (true);
addButton->setDisabled (true);
deleteButton->setDisabled (true);
}
dataChanged(mTable->getModelIndex (mCurrentId, 0));
mMainLayout->addLayout (buttonsLayout);
setWidget (mainWidget);
} }
void CSVWorld::DialogueSubView::prevId () void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked)
{ {
int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1; if (!mEditWidget) // hack to indicate that getUniversalId().getId() is no longer valid
if (newRow < 0)
{
return;
}
while (newRow >= 0)
{
QModelIndex newIndex(mTable->index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased))
{
mEditWidget->remake(newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (newRow, 2)).toInt()),
mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
mEditWidget->setDisabled(mLocked);
return;
}
--newRow;
}
}
void CSVWorld::DialogueSubView::nextId ()
{
int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1;
if (newRow >= mTable->rowCount())
{
return;
}
while (newRow < mTable->rowCount())
{
QModelIndex newIndex(mTable->index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted))
{
mEditWidget->remake(newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (newRow, 2)).toInt()),
mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
mEditWidget->setDisabled(mLocked);
return;
}
++newRow;
}
}
void CSVWorld::DialogueSubView::setEditLock (bool locked)
{
if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid
return; return;
mLocked = locked; mLocked = locked;
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0));
if (currentIndex.isValid()) if (currentIndex.isValid())
{ {
@ -795,9 +628,9 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked)
} }
void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index)
{ {
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0));
if (currentIndex.isValid() && if (currentIndex.isValid() &&
(index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row()) (index.parent().isValid() ? index.parent().row() : index.row()) == currentIndex.row())
@ -828,9 +661,9 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index)
} }
} }
void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{ {
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); QModelIndex currentIndex(mTable->getModelIndex(getUniversalId().getId(), 0));
if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end) if (currentIndex.isValid() && currentIndex.row() >= start && currentIndex.row() <= end)
{ {
@ -843,60 +676,106 @@ void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent,
} }
} }
void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, void CSVWorld::SimpleDialogueSubView::updateCurrentId()
const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document)
{ {
if (document == &mDocument) std::vector<std::string> selection;
{ selection.push_back (getUniversalId().getId());
qobject_cast<DropLineEdit*>(editor)->setText(id.getId().c_str()); mCommandDispatcher.setSelection(selection);
}
} }
void CSVWorld::DialogueSubView::requestFocus (const std::string& id)
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting)
: SimpleDialogueSubView (id, document)
{ {
changeCurrentId(id); // bottom box
mBottom = new TableBottomBox (creatorFactory, document, id, this);
mBottom->setSizePolicy (QSizePolicy::Ignored, QSizePolicy::Fixed);
connect (mBottom, SIGNAL (requestFocus (const std::string&)),
this, SLOT (requestFocus (const std::string&)));
// button bar
mButtons = new RecordButtonBar (id, getTable(), mBottom,
&getCommandDispatcher(), this);
mEditWidget->remake(mTable->getModelIndex (id, 0).row()); // layout
getMainLayout().addWidget (mButtons);
getMainLayout().addWidget (mBottom);
// connections
connect (mButtons, SIGNAL (showPreview()), this, SLOT (showPreview()));
connect (mButtons, SIGNAL (viewRecord()), this, SLOT (viewRecord()));
connect (mButtons, SIGNAL (switchToRow (int)), this, SLOT (switchToRow (int)));
connect (this, SIGNAL (universalIdChanged (const CSMWorld::UniversalId&)),
mButtons, SLOT (universalIdChanged (const CSMWorld::UniversalId&)));
}
void CSVWorld::DialogueSubView::setEditLock (bool locked)
{
SimpleDialogueSubView::setEditLock (locked);
mButtons->setEditLock (locked);
} }
void CSVWorld::DialogueSubView::cloneRequest () void CSVWorld::DialogueSubView::updateUserSetting (const QString& name, const QStringList& value)
{ {
mBottom->cloneRequest(mCurrentId, static_cast<CSMWorld::UniversalId::Type>(mTable->data(mTable->getModelIndex(mCurrentId, 2)).toInt())); SimpleDialogueSubView::updateUserSetting (name, value);
mButtons->updateUserSetting (name, value);
} }
void CSVWorld::DialogueSubView::showPreview () void CSVWorld::DialogueSubView::showPreview ()
{ {
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0));
if (currentIndex.isValid() && if (currentIndex.isValid() &&
mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview && getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview &&
currentIndex.row() < mTable->rowCount()) currentIndex.row() < getTable().rowCount())
{ {
emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), ""); emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getUniversalId().getId()), "");
} }
} }
void CSVWorld::DialogueSubView::viewRecord () void CSVWorld::DialogueSubView::viewRecord ()
{ {
QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0)); QModelIndex currentIndex (getTable().getModelIndex (getUniversalId().getId(), 0));
if (currentIndex.isValid() && if (currentIndex.isValid() &&
currentIndex.row() < mTable->rowCount()) currentIndex.row() < getTable().rowCount())
{ {
std::pair<CSMWorld::UniversalId, std::string> params = mTable->view (currentIndex.row()); std::pair<CSMWorld::UniversalId, std::string> params = getTable().view (currentIndex.row());
if (params.first.getType()!=CSMWorld::UniversalId::Type_None) if (params.first.getType()!=CSMWorld::UniversalId::Type_None)
emit focusId (params.first, params.second); emit focusId (params.first, params.second);
} }
} }
void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId) void CSVWorld::DialogueSubView::switchToRow (int row)
{ {
std::vector<std::string> selection; int idColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Id);
mCurrentId = std::string(newId); std::string id = getTable().data (getTable().index (row, idColumn)).toString().toUtf8().constData();
selection.push_back(mCurrentId); int typeColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_RecordType);
mCommandDispatcher.setSelection(selection); CSMWorld::UniversalId::Type type = static_cast<CSMWorld::UniversalId::Type> (
getTable().data (getTable().index (row, typeColumn)).toInt());
setUniversalId (CSMWorld::UniversalId (type, id));
updateCurrentId();
getEditWidget().remake (row);
int stateColumn = getTable().findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> (
getTable().data (getTable().index (row, stateColumn)).toInt());
getEditWidget().setDisabled (isLocked() || state==CSMWorld::RecordBase::State_Deleted);
}
void CSVWorld::DialogueSubView::requestFocus (const std::string& id)
{
QModelIndex index = getTable().getModelIndex (id, 0);
if (index.isValid())
switchToRow (index.row());
} }

@ -86,18 +86,12 @@ namespace CSVWorld
public slots: public slots:
void editorDataCommited(); void editorDataCommited();
void setIndex(const QModelIndex& index); void setIndex(const QModelIndex& index);
void tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data,
const CSMDoc::Document* document);
signals: signals:
void editorDataCommited(QWidget* editor, void editorDataCommited(QWidget* editor,
const QModelIndex& index, const QModelIndex& index,
CSMWorld::ColumnBase::Display display); CSMWorld::ColumnBase::Display display);
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document);
}; };
class DialogueDelegateDispatcher : public QAbstractItemDelegate class DialogueDelegateDispatcher : public QAbstractItemDelegate
@ -153,11 +147,6 @@ namespace CSVWorld
private slots: private slots:
void editorDataCommited(QWidget* editor, const QModelIndex& index, void editorDataCommited(QWidget* editor, const QModelIndex& index,
CSMWorld::ColumnBase::Display display); CSMWorld::ColumnBase::Display display);
signals:
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document);
}; };
class EditWidget : public QScrollArea class EditWidget : public QScrollArea
@ -182,61 +171,74 @@ namespace CSVWorld
virtual ~EditWidget(); virtual ~EditWidget();
void remake(int row); void remake(int row);
signals:
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document);
}; };
class DialogueSubView : public CSVDoc::SubView class SimpleDialogueSubView : public CSVDoc::SubView
{ {
Q_OBJECT Q_OBJECT
EditWidget* mEditWidget; EditWidget* mEditWidget;
QVBoxLayout* mMainLayout; QVBoxLayout* mMainLayout;
CSMWorld::IdTable* mTable; CSMWorld::IdTable* mTable;
QUndoStack& mUndoStack; bool mLocked;
std::string mCurrentId; const CSMDoc::Document& mDocument;
bool mLocked; CSMWorld::CommandDispatcher mCommandDispatcher;
const CSMDoc::Document& mDocument;
TableBottomBox* mBottom;
CSMWorld::CommandDispatcher mCommandDispatcher;
public: protected:
DialogueSubView (const CSMWorld::UniversalId& id, QVBoxLayout& getMainLayout();
CSMDoc::Document& document,
const CreatorFactoryBase& creatorFactory,
bool sorting = false);
virtual void setEditLock (bool locked); CSMWorld::IdTable& getTable();
private: CSMWorld::CommandDispatcher& getCommandDispatcher();
void changeCurrentId(const std::string& newCurrent);
private slots: EditWidget& getEditWidget();
void nextId(); void updateCurrentId();
void prevId(); bool isLocked() const;
public:
void showPreview(); SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
void viewRecord(); virtual void setEditLock (bool locked);
void cloneRequest(); private slots:
void dataChanged(const QModelIndex & index); void dataChanged(const QModelIndex & index);
///\brief we need to care for deleting currently edited record ///\brief we need to care for deleting currently edited record
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index, void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
const CSMWorld::UniversalId& id, };
const CSMDoc::Document* document);
void requestFocus (const std::string& id); class RecordButtonBar;
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); class DialogueSubView : public SimpleDialogueSubView
{
Q_OBJECT
TableBottomBox* mBottom;
RecordButtonBar *mButtons;
public:
DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
const CreatorFactoryBase& creatorFactory, bool sorting = false);
virtual void setEditLock (bool locked);
virtual void updateUserSetting (const QString& name, const QStringList& value);
private slots:
void showPreview();
void viewRecord();
void switchToRow (int row);
void requestFocus (const std::string& id);
}; };
} }

@ -0,0 +1,26 @@
#include "dragdroputils.hpp"
#include <QDropEvent>
#include "../../model/world/tablemimedata.hpp"
const CSMWorld::TableMimeData *CSVWorld::DragDropUtils::getTableMimeData(const QDropEvent &event)
{
return dynamic_cast<const CSMWorld::TableMimeData *>(event.mimeData());
}
bool CSVWorld::DragDropUtils::canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type)
{
const CSMWorld::TableMimeData *data = getTableMimeData(event);
return data != NULL && data->holdsType(type);
}
CSMWorld::UniversalId CSVWorld::DragDropUtils::getAcceptedData(const QDropEvent &event,
CSMWorld::ColumnBase::Display type)
{
if (canAcceptData(event, type))
{
return getTableMimeData(event)->returnMatching(type);
}
return CSMWorld::UniversalId::Type_None;
}

@ -0,0 +1,29 @@
#ifndef CSV_WORLD_DRAGDROPUTILS_HPP
#define CSV_WORLD_DRAGDROPUTILS_HPP
#include "../../model/world/columnbase.hpp"
class QDropEvent;
namespace CSMWorld
{
class TableMimeData;
class UniversalId;
}
namespace CSVWorld
{
namespace DragDropUtils
{
const CSMWorld::TableMimeData *getTableMimeData(const QDropEvent &event);
bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type);
///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type
CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type);
///< Gets the accepted data from the \a event using the \a type
///< \return Type_None if the \a event data doesn't holds the \a type
}
}
#endif

@ -1,12 +1,24 @@
#include "dragrecordtable.hpp"
#include <QDrag> #include <QDrag>
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include "../../model/doc/document.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "dragrecordtable.hpp" #include "../../model/world/commands.hpp"
#include "dragdroputils.hpp"
void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table) void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table)
{ {
CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument); std::vector<CSMWorld::UniversalId> records = table.getDraggedRecords();
if (records.empty())
{
return;
}
CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (records, mDocument);
if (mime) if (mime)
{ {
@ -21,7 +33,9 @@ CSVWorld::DragRecordTable::DragRecordTable (CSMDoc::Document& document, QWidget*
QTableView(parent), QTableView(parent),
mDocument(document), mDocument(document),
mEditLock(false) mEditLock(false)
{} {
setAcceptDrops(true);
}
void CSVWorld::DragRecordTable::setEditLock (bool locked) void CSVWorld::DragRecordTable::setEditLock (bool locked)
{ {
@ -35,5 +49,51 @@ void CSVWorld::DragRecordTable::dragEnterEvent(QDragEnterEvent *event)
void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event)
{ {
event->accept(); QModelIndex index = indexAt(event->pos());
if (CSVWorld::DragDropUtils::canAcceptData(*event, getIndexDisplayType(index)))
{
if (index.flags() & Qt::ItemIsEditable)
{
event->accept();
}
}
else
{
event->ignore();
}
}
void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event)
{
QModelIndex index = indexAt(event->pos());
CSMWorld::ColumnBase::Display display = getIndexDisplayType(index);
if (CSVWorld::DragDropUtils::canAcceptData(*event, display))
{
const CSMWorld::TableMimeData *data = CSVWorld::DragDropUtils::getTableMimeData(*event);
if (data->fromDocument(mDocument))
{
CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, display);
QVariant newIndexData = QString::fromUtf8(id.getId().c_str());
QVariant oldIndexData = index.data(Qt::EditRole);
if (newIndexData != oldIndexData)
{
mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model(), index, newIndexData));
}
}
}
}
CSMWorld::ColumnBase::Display CSVWorld::DragRecordTable::getIndexDisplayType(const QModelIndex &index) const
{
Q_ASSERT(model() != NULL);
if (index.isValid())
{
QVariant display = model()->headerData(index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display);
if (display.isValid())
{
return static_cast<CSMWorld::ColumnBase::Display>(display.toInt());
}
}
return CSMWorld::ColumnBase::Display_None;
} }

@ -4,6 +4,8 @@
#include <QTableView> #include <QTableView>
#include <QEvent> #include <QEvent>
#include "../../model/world/columnbase.hpp"
class QWidget; class QWidget;
class QAction; class QAction;
@ -38,6 +40,11 @@ namespace CSVWorld
void dragEnterEvent(QDragEnterEvent *event); void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event); void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
private:
CSMWorld::ColumnBase::Display getIndexDisplayType(const QModelIndex &index) const;
}; };
} }

@ -2,6 +2,8 @@
#include "../../model/world/idcompletionmanager.hpp" #include "../../model/world/idcompletionmanager.hpp"
#include "../widget/droplineedit.hpp"
CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document, CSMDoc::Document& document,
QObject *parent) QObject *parent)
@ -26,7 +28,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent,
} }
CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager();
DropLineEdit *editor = new DropLineEdit(parent); CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(display, parent);
editor->setCompleter(completionManager.getCompleter(display).get()); editor->setCompleter(completionManager.getCompleter(display).get());
return editor; return editor;
} }

@ -4,7 +4,6 @@
#include <algorithm> #include <algorithm>
#include <QLabel> #include <QLabel>
#include <QLineEdit>
#include <QUuid> #include <QUuid>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
@ -17,6 +16,8 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp" #include "../../model/world/idcompletionmanager.hpp"
#include "../widget/droplineedit.hpp"
std::string CSVWorld::InfoCreator::getId() const std::string CSVWorld::InfoCreator::getId() const
{ {
std::string id = Misc::StringUtils::lowerCase (mTopic->text().toUtf8().constData()); std::string id = Misc::StringUtils::lowerCase (mTopic->text().toUtf8().constData());
@ -48,12 +49,12 @@ CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
QLabel *label = new QLabel ("Topic", this); QLabel *label = new QLabel ("Topic", this);
insertBeforeButtons (label, false); insertBeforeButtons (label, false);
mTopic = new QLineEdit (this);
CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic; CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic;
if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos) if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos)
{ {
displayType = CSMWorld::ColumnBase::Display_Journal; displayType = CSMWorld::ColumnBase::Display_Journal;
} }
mTopic = new CSVWidget::DropLineEdit(displayType, this);
mTopic->setCompleter(completionManager.getCompleter(displayType).get()); mTopic->setCompleter(completionManager.getCompleter(displayType).get());
insertBeforeButtons (mTopic, true); insertBeforeButtons (mTopic, true);

@ -3,21 +3,24 @@
#include "genericcreator.hpp" #include "genericcreator.hpp"
class QLineEdit;
namespace CSMWorld namespace CSMWorld
{ {
class InfoCollection; class InfoCollection;
class IdCompletionManager; class IdCompletionManager;
} }
namespace CSVWidget
{
class DropLineEdit;
}
namespace CSVWorld namespace CSVWorld
{ {
class InfoCreator : public GenericCreator class InfoCreator : public GenericCreator
{ {
Q_OBJECT Q_OBJECT
QLineEdit *mTopic; CSVWidget::DropLineEdit *mTopic;
virtual std::string getId() const; virtual std::string getId() const;

@ -14,8 +14,7 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
CSMWorld::UniversalId id, CSMWorld::UniversalId id,
CSMWorld::NestedTableProxyModel* model, CSMWorld::NestedTableProxyModel* model,
QWidget* parent) QWidget* parent)
: QTableView(parent), : DragRecordTable(document, parent),
mUndoStack(document.getUndoStack()),
mModel(model) mModel(model)
{ {
mDispatcher = new CSMWorld::CommandDispatcher (document, id, this); mDispatcher = new CSMWorld::CommandDispatcher (document, id, this);
@ -47,8 +46,6 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
setModel(model); setModel(model);
setAcceptDrops(true);
mAddNewRowAction = new QAction (tr ("Add new row"), this); mAddNewRowAction = new QAction (tr ("Add new row"), this);
connect(mAddNewRowAction, SIGNAL(triggered()), connect(mAddNewRowAction, SIGNAL(triggered()),
@ -60,12 +57,10 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
this, SLOT(removeRowActionTriggered())); this, SLOT(removeRowActionTriggered()));
} }
void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event) std::vector<CSMWorld::UniversalId> CSVWorld::NestedTable::getDraggedRecords() const
{
}
void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event)
{ {
// No drag support for nested tables
return std::vector<CSMWorld::UniversalId>();
} }
void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event) void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event)
@ -84,16 +79,16 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event)
void CSVWorld::NestedTable::removeRowActionTriggered() void CSVWorld::NestedTable::removeRowActionTriggered()
{ {
mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()), mDocument.getUndoStack().push(new CSMWorld::DeleteNestedCommand(*(mModel->model()),
mModel->getParentId(), mModel->getParentId(),
selectionModel()->selectedRows().begin()->row(), selectionModel()->selectedRows().begin()->row(),
mModel->getParentColumn())); mModel->getParentColumn()));
} }
void CSVWorld::NestedTable::addNewRowActionTriggered() void CSVWorld::NestedTable::addNewRowActionTriggered()
{ {
mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()), mDocument.getUndoStack().push(new CSMWorld::AddNestedCommand(*(mModel->model()),
mModel->getParentId(), mModel->getParentId(),
selectionModel()->selectedRows().size(), selectionModel()->selectedRows().size(),
mModel->getParentColumn())); mModel->getParentColumn()));
} }

@ -1,10 +1,10 @@
#ifndef CSV_WORLD_NESTEDTABLE_H #ifndef CSV_WORLD_NESTEDTABLE_H
#define CSV_WORLD_NESTEDTABLE_H #define CSV_WORLD_NESTEDTABLE_H
#include <QTableView>
#include <QEvent> #include <QEvent>
class QUndoStack; #include "dragrecordtable.hpp"
class QAction; class QAction;
class QContextMenuEvent; class QContextMenuEvent;
@ -22,13 +22,12 @@ namespace CSMDoc
namespace CSVWorld namespace CSVWorld
{ {
class NestedTable : public QTableView class NestedTable : public DragRecordTable
{ {
Q_OBJECT Q_OBJECT
QAction *mAddNewRowAction; QAction *mAddNewRowAction;
QAction *mRemoveRowAction; QAction *mRemoveRowAction;
QUndoStack& mUndoStack;
CSMWorld::NestedTableProxyModel* mModel; CSMWorld::NestedTableProxyModel* mModel;
CSMWorld::CommandDispatcher *mDispatcher; CSMWorld::CommandDispatcher *mDispatcher;
@ -38,10 +37,7 @@ namespace CSVWorld
CSMWorld::NestedTableProxyModel* model, CSMWorld::NestedTableProxyModel* model,
QWidget* parent = NULL); QWidget* parent = NULL);
protected: virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
private: private:
void contextMenuEvent (QContextMenuEvent *event); void contextMenuEvent (QContextMenuEvent *event);

@ -0,0 +1,207 @@
#include "recordbuttonbar.hpp"
#include <QHBoxLayout>
#include <QToolButton>
#include "../../model/world/idtable.hpp"
#include "../../model/world/commanddispatcher.hpp"
#include "../../model/settings/usersettings.hpp"
#include "../world/tablebottombox.hpp"
void CSVWorld::RecordButtonBar::updateModificationButtons()
{
bool createAndDeleteDisabled = !mBottom || !mBottom->canCreateAndDelete() || mLocked;
mCloneButton->setDisabled (createAndDeleteDisabled);
mAddButton->setDisabled (createAndDeleteDisabled);
mDeleteButton->setDisabled (createAndDeleteDisabled);
bool commandDisabled = !mCommandDispatcher || mLocked;
mRevertButton->setDisabled (commandDisabled);
mDeleteButton->setDisabled (commandDisabled);
}
void CSVWorld::RecordButtonBar::updatePrevNextButtons()
{
int rows = mTable.rowCount();
if (rows<=1)
{
mPrevButton->setDisabled (true);
mNextButton->setDisabled (true);
}
else if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle")=="true")
{
mPrevButton->setDisabled (false);
mNextButton->setDisabled (false);
}
else
{
int row = mTable.getModelIndex (mId.getId(), 0).row();
mPrevButton->setDisabled (row<=0);
mNextButton->setDisabled (row>=rows-1);
}
}
CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id,
CSMWorld::IdTable& table, TableBottomBox *bottomBox,
CSMWorld::CommandDispatcher *commandDispatcher, QWidget *parent)
: QWidget (parent), mId (id), mTable (table), mBottom (bottomBox),
mCommandDispatcher (commandDispatcher), mLocked (false)
{
QHBoxLayout *buttonsLayout = new QHBoxLayout;
buttonsLayout->setContentsMargins (0, 0, 0, 0);
// left section
mPrevButton = new QToolButton (this);
mPrevButton->setIcon(QIcon(":/go-previous.png"));
mPrevButton->setToolTip ("Switch to previous record");
buttonsLayout->addWidget (mPrevButton, 0);
mNextButton = new QToolButton (this);
mNextButton->setIcon(QIcon(":/go-next.png"));
mNextButton->setToolTip ("Switch to next record");
buttonsLayout->addWidget (mNextButton, 1);
buttonsLayout->addStretch(2);
// optional buttons of the right section
if (mTable.getFeatures() & CSMWorld::IdTable::Feature_Preview)
{
QToolButton* previewButton = new QToolButton (this);
previewButton->setIcon(QIcon(":/edit-preview.png"));
previewButton->setToolTip ("Open a preview of this record");
buttonsLayout->addWidget(previewButton);
connect (previewButton, SIGNAL(clicked()), this, SIGNAL (showPreview()));
}
if (mTable.getFeatures() & CSMWorld::IdTable::Feature_View)
{
QToolButton* viewButton = new QToolButton (this);
viewButton->setIcon(QIcon(":/cell.png"));
viewButton->setToolTip ("Open a scene view of the cell this record is located in");
buttonsLayout->addWidget(viewButton);
connect (viewButton, SIGNAL(clicked()), this, SIGNAL (viewRecord()));
}
// right section
mCloneButton = new QToolButton (this);
mCloneButton->setIcon(QIcon(":/edit-clone.png"));
mCloneButton->setToolTip ("Clone record");
buttonsLayout->addWidget(mCloneButton);
mAddButton = new QToolButton (this);
mAddButton->setIcon(QIcon(":/add.png"));
mAddButton->setToolTip ("Add new record");
buttonsLayout->addWidget(mAddButton);
mDeleteButton = new QToolButton (this);
mDeleteButton->setIcon(QIcon(":/edit-delete.png"));
mDeleteButton->setToolTip ("Delete record");
buttonsLayout->addWidget(mDeleteButton);
mRevertButton = new QToolButton (this);
mRevertButton->setIcon(QIcon(":/edit-undo.png"));
mRevertButton->setToolTip ("Revert record");
buttonsLayout->addWidget(mRevertButton);
setLayout (buttonsLayout);
// connections
if(mBottom && mBottom->canCreateAndDelete())
{
connect (mAddButton, SIGNAL (clicked()), mBottom, SLOT (createRequest()));
connect (mCloneButton, SIGNAL (clicked()), this, SLOT (cloneRequest()));
}
connect (mNextButton, SIGNAL (clicked()), this, SLOT (nextId()));
connect (mPrevButton, SIGNAL (clicked()), this, SLOT (prevId()));
if (mCommandDispatcher)
{
connect (mRevertButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeRevert()));
connect (mDeleteButton, SIGNAL (clicked()), mCommandDispatcher, SLOT (executeDelete()));
}
connect (&mTable, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (rowNumberChanged (const QModelIndex&, int, int)));
connect (&mTable, SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
this, SLOT (rowNumberChanged (const QModelIndex&, int, int)));
updateModificationButtons();
updatePrevNextButtons();
}
void CSVWorld::RecordButtonBar::setEditLock (bool locked)
{
mLocked = locked;
updateModificationButtons();
}
void CSVWorld::RecordButtonBar::updateUserSetting (const QString& name, const QStringList& value)
{
if (name=="general-input/cycle")
updatePrevNextButtons();
}
void CSVWorld::RecordButtonBar::universalIdChanged (const CSMWorld::UniversalId& id)
{
mId = id;
updatePrevNextButtons();
}
void CSVWorld::RecordButtonBar::cloneRequest()
{
if (mBottom)
{
int typeColumn = mTable.findColumnIndex (CSMWorld::Columns::ColumnId_RecordType);
QModelIndex typeIndex = mTable.getModelIndex (mId.getId(), typeColumn);
CSMWorld::UniversalId::Type type = static_cast<CSMWorld::UniversalId::Type> (
mTable.data (typeIndex).toInt());
mBottom->cloneRequest (mId.getId(), type);
}
}
void CSVWorld::RecordButtonBar::nextId()
{
int newRow = mTable.getModelIndex (mId.getId(), 0).row() + 1;
if (newRow >= mTable.rowCount())
{
if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle")
=="true")
newRow = 0;
else
return;
}
emit switchToRow (newRow);
}
void CSVWorld::RecordButtonBar::prevId()
{
int newRow = mTable.getModelIndex (mId.getId(), 0).row() - 1;
if (newRow < 0)
{
if (CSMSettings::UserSettings::instance().settingValue ("general-input/cycle")
=="true")
newRow = mTable.rowCount()-1;
else
return;
}
emit switchToRow (newRow);
}
void CSVWorld::RecordButtonBar::rowNumberChanged (const QModelIndex& parent, int start, int end)
{
updatePrevNextButtons();
}

@ -0,0 +1,87 @@
#ifndef CSV_WORLD_RECORDBUTTONBAR_H
#define CSV_WORLD_RECORDBUTTONBAR_H
#include <QWidget>
#include "../../model/world/universalid.hpp"
class QToolButton;
class QModelIndex;
namespace CSMWorld
{
class IdTable;
class CommandDispatcher;
}
namespace CSVWorld
{
class TableBottomBox;
/// \brief Button bar for use in dialogue-type subviews
///
/// Contains the following buttons:
/// - next/prev
/// - clone
/// - add
/// - delete
/// - revert
/// - preview (optional)
/// - view (optional)
class RecordButtonBar : public QWidget
{
Q_OBJECT
CSMWorld::UniversalId mId;
CSMWorld::IdTable& mTable;
TableBottomBox *mBottom;
CSMWorld::CommandDispatcher *mCommandDispatcher;
QToolButton *mPrevButton;
QToolButton *mNextButton;
QToolButton *mCloneButton;
QToolButton *mAddButton;
QToolButton *mDeleteButton;
QToolButton *mRevertButton;
bool mLocked;
private:
void updateModificationButtons();
void updatePrevNextButtons();
public:
RecordButtonBar (const CSMWorld::UniversalId& id,
CSMWorld::IdTable& table, TableBottomBox *bottomBox = 0,
CSMWorld::CommandDispatcher *commandDispatcher = 0, QWidget *parent = 0);
void setEditLock (bool locked);
void updateUserSetting (const QString& name, const QStringList& value);
public slots:
void universalIdChanged (const CSMWorld::UniversalId& id);
private slots:
void cloneRequest();
void nextId();
void prevId();
void rowNumberChanged (const QModelIndex& parent, int start, int end);
signals:
void showPreview();
void viewRecord();
void switchToRow (int row);
};
}
#endif

@ -2,7 +2,6 @@
#include "referencecreator.hpp" #include "referencecreator.hpp"
#include <QLabel> #include <QLabel>
#include <QLineEdit>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
@ -12,6 +11,8 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp" #include "../../model/world/idcompletionmanager.hpp"
#include "../widget/droplineedit.hpp"
std::string CSVWorld::ReferenceCreator::getId() const std::string CSVWorld::ReferenceCreator::getId() const
{ {
return mId; return mId;
@ -80,7 +81,7 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack&
QLabel *label = new QLabel ("Cell", this); QLabel *label = new QLabel ("Cell", this);
insertBeforeButtons (label, false); insertBeforeButtons (label, false);
mCell = new QLineEdit (this); mCell = new CSVWidget::DropLineEdit(CSMWorld::ColumnBase::Display_Cell, this);
mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get()); mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get());
insertBeforeButtons (mCell, true); insertBeforeButtons (mCell, true);

@ -3,13 +3,16 @@
#include "genericcreator.hpp" #include "genericcreator.hpp"
class QLineEdit;
namespace CSMWorld namespace CSMWorld
{ {
class IdCompletionManager; class IdCompletionManager;
} }
namespace CSVWidget
{
class DropLineEdit;
}
namespace CSVWorld namespace CSVWorld
{ {
@ -17,7 +20,7 @@ namespace CSVWorld
{ {
Q_OBJECT Q_OBJECT
QLineEdit *mCell; CSVWidget::DropLineEdit *mCell;
std::string mId; std::string mId;
private: private:

@ -170,6 +170,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Filter, manager.add (CSMWorld::UniversalId::Type_Filter,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
manager.add (CSMWorld::UniversalId::Type_MetaData,
new CSVDoc::SubViewFactory<SimpleDialogueSubView >);
//preview //preview
manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>); manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>);
} }

@ -9,6 +9,8 @@
#include <QString> #include <QString>
#include <QtCore/qnamespace.h> #include <QtCore/qnamespace.h>
#include <components/misc/stringops.hpp>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
@ -128,17 +130,24 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
{ {
int row = mProxyModel->mapToSource ( int row = mProxyModel->mapToSource (
mProxyModel->index (selectedRows.begin()->row(), 0)).row(); mProxyModel->index (selectedRows.begin()->row(), 0)).row();
QString curData = mModel->data(mModel->index(row, column)).toString();
if (row>0 && mModel->data (mModel->index (row, column))== if (row > 0)
mModel->data (mModel->index (row-1, column)))
{ {
menu.addAction (mMoveUpAction); 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 && mModel->data (mModel->index (row, column))== if (row < mModel->rowCount() - 1)
mModel->data (mModel->index (row+1, column)))
{ {
menu.addAction (mMoveDownAction); QString nextData = mModel->data(mModel->index(row + 1, column)).toString();
if (Misc::StringUtils::ciEqual(curData.toStdString(), nextData.toStdString()))
{
menu.addAction(mMoveDownAction);
}
} }
} }
} }
@ -697,36 +706,6 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)
} }
} }
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
}
std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const
{ {
const int count = mModel->columnCount(); const int count = mModel->columnCount();

@ -76,8 +76,6 @@ namespace CSVWorld
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event);
void dropEvent(QDropEvent *event);
protected: protected:
virtual void mouseDoubleClickEvent (QMouseEvent *event); virtual void mouseDoubleClickEvent (QMouseEvent *event);

@ -17,7 +17,10 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "../../model/world/commanddispatcher.hpp" #include "../../model/world/commanddispatcher.hpp"
#include "../widget/coloreditor.hpp" #include "../widget/coloreditor.hpp"
#include "../widget/droplineedit.hpp"
#include "dialoguespinbox.hpp" #include "dialoguespinbox.hpp"
#include "scriptedit.hpp" #include "scriptedit.hpp"
@ -229,33 +232,35 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
return edit; return edit;
} }
case CSMWorld::ColumnBase::Display_LongString256:
{
/// \todo implement size limit. QPlainTextEdit does not support a size limit.
QPlainTextEdit *edit = new QPlainTextEdit(parent);
edit->setUndoRedoEnabled (false);
return edit;
}
case CSMWorld::ColumnBase::Display_Boolean: case CSMWorld::ColumnBase::Display_Boolean:
return new QCheckBox(parent); return new QCheckBox(parent);
case CSMWorld::ColumnBase::Display_String:
case CSMWorld::ColumnBase::Display_Skill:
case CSMWorld::ColumnBase::Display_Script:
case CSMWorld::ColumnBase::Display_Race:
case CSMWorld::ColumnBase::Display_Region:
case CSMWorld::ColumnBase::Display_Class:
case CSMWorld::ColumnBase::Display_Faction:
case CSMWorld::ColumnBase::Display_Miscellaneous:
case CSMWorld::ColumnBase::Display_Sound:
case CSMWorld::ColumnBase::Display_Mesh:
case CSMWorld::ColumnBase::Display_Icon:
case CSMWorld::ColumnBase::Display_Music:
case CSMWorld::ColumnBase::Display_SoundRes:
case CSMWorld::ColumnBase::Display_Texture:
case CSMWorld::ColumnBase::Display_Video:
case CSMWorld::ColumnBase::Display_GlobalVariable:
return new DropLineEdit(parent);
case CSMWorld::ColumnBase::Display_ScriptLines: case CSMWorld::ColumnBase::Display_ScriptLines:
return new ScriptEdit (mDocument, ScriptHighlighter::Mode_Console, parent); return new ScriptEdit (mDocument, ScriptHighlighter::Mode_Console, parent);
case CSMWorld::ColumnBase::Display_String:
// For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used
return new CSVWidget::DropLineEdit(display, parent);
case CSMWorld::ColumnBase::Display_String32:
{
// For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used
CSVWidget::DropLineEdit *widget = new CSVWidget::DropLineEdit(display, parent);
widget->setMaxLength (32);
return widget;
}
default: default:
return QStyledItemDelegate::createEditor (parent, option, index); return QStyledItemDelegate::createEditor (parent, option, index);
@ -324,29 +329,3 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde
} }
} }
CSVWorld::DropLineEdit::DropLineEdit(QWidget* parent) :
QLineEdit(parent)
{
setAcceptDrops(true);
}
void CSVWorld::DropLineEdit::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void CSVWorld::DropLineEdit::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}
void CSVWorld::DropLineEdit::dropEvent(QDropEvent *event)
{
const CSMWorld::TableMimeData* data(dynamic_cast<const CSMWorld::TableMimeData*>(event->mimeData()));
if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped
return;
emit tableMimeDataDropped(data->getData(), data->getDocumentPtr());
//WIP
}

@ -5,7 +5,6 @@
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QLineEdit>
#include "../../model/world/columnbase.hpp" #include "../../model/world/columnbase.hpp"
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
@ -91,24 +90,6 @@ namespace CSVWorld
}; };
class DropLineEdit : public QLineEdit
{
Q_OBJECT
public:
DropLineEdit(QWidget *parent);
private:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
signals:
void tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data, const CSMDoc::Document* document);
};
///< \brief Use commands instead of manipulating the model directly ///< \brief Use commands instead of manipulating the model directly
class CommandDelegate : public QStyledItemDelegate class CommandDelegate : public QStyledItemDelegate
{ {

@ -45,6 +45,8 @@ std::set<MWMechanics::EffectKey> MWMechanics::Alchemy::listEffects() const
{ {
const MWWorld::LiveCellRef<ESM::Ingredient> *ingredient = iter->get<ESM::Ingredient>(); const MWWorld::LiveCellRef<ESM::Ingredient> *ingredient = iter->get<ESM::Ingredient>();
std::set<EffectKey> seenEffects;
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
if (ingredient->mBase->mData.mEffectID[i]!=-1) if (ingredient->mBase->mData.mEffectID[i]!=-1)
{ {
@ -52,7 +54,8 @@ std::set<MWMechanics::EffectKey> MWMechanics::Alchemy::listEffects() const
ingredient->mBase->mData.mEffectID[i], ingredient->mBase->mData.mSkills[i]!=-1 ? ingredient->mBase->mData.mEffectID[i], ingredient->mBase->mData.mSkills[i]!=-1 ?
ingredient->mBase->mData.mSkills[i] : ingredient->mBase->mData.mAttributes[i]); ingredient->mBase->mData.mSkills[i] : ingredient->mBase->mData.mAttributes[i]);
++effects[key]; if (seenEffects.insert(key).second)
++effects[key];
} }
} }
} }
@ -461,7 +464,10 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na
return Result_NoName; return Result_NoName;
if (listEffects().empty()) if (listEffects().empty())
{
removeIngredients();
return Result_NoEffects; return Result_NoEffects;
}
if (beginEffects() == endEffects()) if (beginEffects() == endEffects())
{ {

@ -174,6 +174,15 @@ namespace ESM
endRecord(name); endRecord(name);
} }
void ESMWriter::writeFixedSizeString(const std::string &data, int size)
{
std::string string;
if (!data.empty())
string = mEncoder ? mEncoder->getLegacyEnc(data) : data;
string.resize(size);
write(string.c_str(), string.size());
}
void ESMWriter::writeHString(const std::string& data) void ESMWriter::writeHString(const std::string& data)
{ {
if (data.size() == 0) if (data.size() == 0)

@ -120,6 +120,7 @@ public:
void startSubRecord(const std::string& name); void startSubRecord(const std::string& name);
void endRecord(const std::string& name); void endRecord(const std::string& name);
void endRecord(uint32_t name); void endRecord(uint32_t name);
void writeFixedSizeString(const std::string& data, int size);
void writeHString(const std::string& data); void writeHString(const std::string& data);
void writeHCString(const std::string& data); void writeHCString(const std::string& data);
void writeName(const std::string& data); void writeName(const std::string& data);

@ -71,7 +71,13 @@ void ESM::Header::save (ESMWriter &esm)
if (mFormat>0) if (mFormat>0)
esm.writeHNT ("FORM", mFormat); esm.writeHNT ("FORM", mFormat);
esm.writeHNT ("HEDR", mData, 300); esm.startSubRecord("HEDR");
esm.writeT(mData.version);
esm.writeT(mData.type);
esm.writeFixedSizeString(mData.author.toString(), 32);
esm.writeFixedSizeString(mData.desc.toString(), 256);
esm.writeT(mData.records);
esm.endRecord("HEDR");
for (std::vector<Header::MasterData>::iterator iter = mMaster.begin(); for (std::vector<Header::MasterData>::iterator iter = mMaster.begin();
iter != mMaster.end(); ++iter) iter != mMaster.end(); ++iter)

Loading…
Cancel
Save