Merge branch 'bottombar'

actorid
Marc Zinnschlag 12 years ago
commit 2e667f1d94

@ -57,13 +57,14 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator
)
opencs_units_noqt (view/world
dialoguesubview subviews
enumdelegate vartypedelegate recordstatusdelegate refidtypedelegate datadisplaydelegate
scripthighlighter
scripthighlighter idvalidator
)

@ -3,7 +3,7 @@
#include <QAbstractItemModel>
#include "idtableproxymodel.hpp"
#include "idtable.hpp"
#include "idtable.hpp"
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
@ -25,15 +25,28 @@ void CSMWorld::ModifyCommand::undo()
mModel.setData (mIndex, mOld);
}
CSMWorld::CreateCommand::CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent)
: QUndoCommand (parent), mModel (model), mId (id)
CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand *parent)
: QUndoCommand (parent), mModel (model), mId (id), mType (UniversalId::Type_None)
{
setText (("Create record " + id).c_str());
}
void CSMWorld::CreateCommand::addValue (int column, const QVariant& value)
{
mValues[column] = value;
}
void CSMWorld::CreateCommand::setType (UniversalId::Type type)
{
mType = type;
}
void CSMWorld::CreateCommand::redo()
{
mModel.addRecord (mId);
mModel.addRecord (mId, mType);
for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter)
mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second);
}
void CSMWorld::CreateCommand::undo()

@ -4,17 +4,20 @@
#include "record.hpp"
#include <string>
#include <map>
#include <QVariant>
#include <QUndoCommand>
#include <QModelIndex>
#include "universalid.hpp"
class QModelIndex;
class QAbstractItemModel;
namespace CSMWorld
{
class IdTableProxyModel;
class IdTable;
class IdTable;
class RecordBase;
@ -37,12 +40,18 @@ namespace CSMWorld
class CreateCommand : public QUndoCommand
{
IdTableProxyModel& mModel;
IdTable& mModel;
std::string mId;
UniversalId::Type mType;
std::map<int, QVariant> mValues;
public:
CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent = 0);
CreateCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0);
void setType (UniversalId::Type type);
void addValue (int column, const QVariant& value);
virtual void redo();

@ -300,6 +300,16 @@ CSMWorld::RefIdCollection& CSMWorld::Data::getReferenceables()
return mReferenceables;
}
const CSMWorld::RefCollection& CSMWorld::Data::getReferences() const
{
return mRefs;
}
CSMWorld::RefCollection& CSMWorld::Data::getReferences()
{
return mRefs;
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
{
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -394,4 +404,22 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
reader.skipRecord();
}
}
}
}
bool CSMWorld::Data::hasId (const std::string& id) const
{
return
getGlobals().searchId (id)!=-1 ||
getGmsts().searchId (id)!=-1 ||
getSkills().searchId (id)!=-1 ||
getClasses().searchId (id)!=-1 ||
getFactions().searchId (id)!=-1 ||
getRaces().searchId (id)!=-1 ||
getSounds().searchId (id)!=-1 ||
getScripts().searchId (id)!=-1 ||
getRegions().searchId (id)!=-1 ||
getBirthsigns().searchId (id)!=-1 ||
getSpells().searchId (id)!=-1 ||
getCells().searchId (id)!=-1 ||
getReferenceables().searchId (id)!=-1;
}

@ -112,6 +112,10 @@ namespace CSMWorld
RefIdCollection& getReferenceables();
const RefCollection& getReferences() const;
RefCollection& getReferences();
QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown.
///
@ -123,6 +127,8 @@ namespace CSMWorld
void loadFile (const boost::filesystem::path& path, bool base);
///< Merging content of a file into base or modified.
bool hasId (const std::string& id) const;
};
}

@ -116,13 +116,13 @@ QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const
return QModelIndex();
}
void CSMWorld::IdTable::addRecord (const std::string& id)
void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type)
{
int index = mIdCollection->getAppendIndex();
beginInsertRows (QModelIndex(), index, index);
mIdCollection->appendBlankRecord (id);
mIdCollection->appendBlankRecord (id, type);
endInsertRows();
}

@ -3,6 +3,8 @@
#include <QAbstractItemModel>
#include "universalid.hpp"
namespace CSMWorld
{
class CollectionBase;
@ -44,7 +46,8 @@ namespace CSMWorld
virtual QModelIndex parent (const QModelIndex& index) const;
void addRecord (const std::string& id);
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types
QModelIndex getModelIndex (const std::string& id, int column) const;

@ -7,11 +7,6 @@ CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
: QSortFilterProxyModel (parent)
{}
void CSMWorld::IdTableProxyModel::addRecord (const std::string& id)
{
dynamic_cast<IdTable&> (*sourceModel()).addRecord (id);
}
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const
{
return mapFromSource (dynamic_cast<IdTable&> (*sourceModel()).getModelIndex (id, column));

@ -15,8 +15,6 @@ namespace CSMWorld
IdTableProxyModel (QObject *parent = 0);
virtual void addRecord (const std::string& id);
virtual QModelIndex getModelIndex (const std::string& id, int column) const;
};
}

@ -21,10 +21,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
while (cell2.getNextRef (reader, ref))
{
/// \todo handle deleted and moved references
std::ostringstream stream;
stream << "ref#" << mNextId++;
ref.load (reader, cell2, stream.str());
ref.load (reader, cell2, getNewId());
Record<CellRef> record2;
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
@ -34,4 +31,11 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
}
mCells.setRecord (cellIndex, cell);
}
std::string CSMWorld::RefCollection::getNewId()
{
std::ostringstream stream;
stream << "ref#" << mNextId++;
return stream.str();
}

@ -21,6 +21,8 @@ namespace CSMWorld
void load (ESM::ESMReader& reader, int cellIndex, bool base);
///< Load a sequence of references.
std::string getNewId();
};
}

@ -12,81 +12,82 @@ namespace
CSMWorld::UniversalId::Class mClass;
CSMWorld::UniversalId::Type mType;
const char *mName;
const char *mIcon;
};
static const TypeData sNoArg[] =
{
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables,
"Referenceables" },
"Referenceables", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References,
"References" },
"References", 0 },
{ CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap,
"Region Map" },
"Region Map", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};
static const TypeData sIdArg[] =
{
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Activator, "Activator" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Potion, "Potion" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Apparatus, "Apparatus" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Armor, "Armor" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Book, "Book" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Clothing, "Clothing" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Container, "Container" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Creature, "Creature" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Door, "Door" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Ingredient, "Ingredient" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_CreatureLevelledList,
"Creature Levelled List" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_ItemLevelledList,
"Item Levelled List" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Light, "Light" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Lockpick, "Lockpick" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Miscellaneous,
"Miscellaneous" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Npc, "NPC" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Probe, "Probe" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Repair, "Repair" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Static, "Static" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Weapon, "Weapon" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Reference, "Reference" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables", 0 },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":./activator.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Apparatus, "Apparatus", ":./apparatus.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Armor, "Armor", ":./armor.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Book, "Book", ":./book.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Clothing, "Clothing", ":./clothing.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Container, "Container", ":./container.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Creature, "Creature", ":./creature.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Door, "Door", ":./door.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient", ":./ingredient.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_CreatureLevelledList,
"Creature Levelled List", ":./creature.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_ItemLevelledList,
"Item Levelled List", ":./leveled-item.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Light, "Light", ":./light.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Lockpick, "Lockpick", ":./lockpick.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Miscellaneous,
"Miscellaneous", ":./miscellaneous.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Npc, "NPC", ":./npc.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Probe, "Probe", ":./probe.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Repair, "Repair", ":./repair.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};
static const TypeData sIndexArg[] =
{
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results" },
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};
static const unsigned int IDARG_SIZE = sizeof (sIdArg) / sizeof (TypeData);
@ -268,6 +269,28 @@ std::string CSMWorld::UniversalId::toString() const
return stream.str();
}
std::string CSMWorld::UniversalId::getIcon() const
{
const TypeData *typeData = mArgumentType==ArgumentType_None ? sNoArg :
(mArgumentType==ArgumentType_Id ? sIdArg : sIndexArg);
for (int i=0; typeData[i].mName; ++i)
if (typeData[i].mType==mType)
return typeData[i].mIcon ? typeData[i].mIcon : "";
throw std::logic_error ("failed to retrieve UniversalId type icon");
}
std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listReferenceableTypes()
{
std::vector<CSMWorld::UniversalId::Type> list;
for (int i=0; sIdArg[i].mName; ++i)
if (sIdArg[i].mClass==Class_RefRecord)
list.push_back (sIdArg[i].mType);
return list;
}
std::pair<int, const char *> CSMWorld::UniversalId::getIdArgPair (unsigned int index)
{

@ -3,6 +3,7 @@
#include <string>
#include <iosfwd>
#include <vector>
#include <QMetaType>
@ -14,13 +15,14 @@ namespace CSMWorld
enum Class
{
Class_None = 0,
Class_Record,
Class_SubRecord,
Class_RecordList,
Class_Collection, // multiple types of records combined
Class_Transient, // not part of the world data or the project data
Class_NonRecord // record like data that is not part of the world
Class_None = 0,
Class_Record,
Class_RefRecord, // referenceable record
Class_SubRecord,
Class_RecordList,
Class_Collection, // multiple types of records combined
Class_Transient, // not part of the world data or the project data
Class_NonRecord // record like data that is not part of the world
};
enum ArgumentType
@ -126,6 +128,11 @@ namespace CSMWorld
std::string toString() const;
std::string getIcon() const;
///< Will return an empty string, if no icon is available.
static std::vector<Type> listReferenceableTypes();
static std::pair<int, const char *> getIdArgPair (unsigned int index);
static unsigned int getIdArgSize ();
};

@ -1,15 +1,10 @@
#include "subview.hpp"
CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id)
{
/// \todo add a button to the title bar that clones this sub view
setWindowTitle (mUniversalId.toString().c_str());
/// \todo remove (for testing only)
setMinimumWidth (100);
setMinimumHeight (60);
}
CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const
@ -20,3 +15,5 @@ CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const
void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
}
void CSVDoc::SubView::setStatusBar (bool show) {}

@ -37,6 +37,9 @@ namespace CSVDoc
virtual void setEditLock (bool locked) = 0;
virtual void updateEditorSetting (const QString &, const QString &);
virtual void setStatusBar (bool show);
///< Default implementation: ignored
signals:
void focusId (const CSMWorld::UniversalId& universalId);

@ -22,28 +22,20 @@ namespace CSVDoc
return new SubViewT (id, document);
}
template<class SubViewT>
class SubViewFactoryWithCreateFlag : public SubViewFactoryBase
{
bool mCreateAndDelete;
template<class SubViewT, class CreatorFactoryT>
class SubViewFactoryWithCreator : public SubViewFactoryBase
{
public:
SubViewFactoryWithCreateFlag (bool createAndDelete);
virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
};
template<class SubViewT>
SubViewFactoryWithCreateFlag<SubViewT>::SubViewFactoryWithCreateFlag (bool createAndDelete)
: mCreateAndDelete (createAndDelete)
{}
template<class SubViewT>
CSVDoc::SubView *SubViewFactoryWithCreateFlag<SubViewT>::makeSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document)
template<class SubViewT, class CreatorFactoryT>
CSVDoc::SubView *SubViewFactoryWithCreator<SubViewT, CreatorFactoryT>::makeSubView (
const CSMWorld::UniversalId& id, CSMDoc::Document& document)
{
return new SubViewT (id, document, mCreateAndDelete);
return new SubViewT (id, document, CreatorFactoryT());
}
}

@ -78,6 +78,11 @@ void CSVDoc::View::setupViewMenu()
QAction *newWindow = new QAction (tr ("&New View"), this);
connect (newWindow, SIGNAL (triggered()), this, SLOT (newView()));
view->addAction (newWindow);
mShowStatusBar = new QAction (tr ("Show Status Bar"), this);
mShowStatusBar->setCheckable (true);
connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool)));
view->addAction (mShowStatusBar);
}
void CSVDoc::View::setupWorldMenu()
@ -282,6 +287,9 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
/// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis)
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
view->setStatusBar (mShowStatusBar->isChecked());
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
@ -436,3 +444,12 @@ void CSVDoc::View::updateEditorSetting (const QString &settingName, const QStrin
else if (settingName == "Height")
resizeViewHeight (settingValue.toInt());
}
void CSVDoc::View::toggleShowStatusBar (bool show)
{
foreach (QObject *view, mSubViewWindow.children())
{
if (CSVDoc::SubView *subView = dynamic_cast<CSVDoc::SubView *> (view))
subView->setStatusBar (show);
}
}

@ -38,6 +38,7 @@ namespace CSVDoc
QAction *mRedo;
QAction *mSave;
QAction *mVerify;
QAction *mShowStatusBar;
std::vector<QAction *> mEditingActions;
Operations *mOperations;
SubViewFactoryManager mSubViewFactory;
@ -158,6 +159,8 @@ namespace CSVDoc
void addRegionMapSubView();
void showUserSettings();
void toggleShowStatusBar (bool show);
};
}

@ -0,0 +1,81 @@
#include "cellcreator.hpp"
#include <limits>
#include <sstream>
#include <QComboBox>
#include <QSpinBox>
#include <QLabel>
std::string CSVWorld::CellCreator::getId() const
{
if (mType->currentIndex()==0)
return GenericCreator::getId();
std::ostringstream stream;
stream << "#" << mX->value() << " " << mY->value();
return stream.str();
}
CSVWorld::CellCreator::CellCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
: GenericCreator (data, undoStack, id)
{
mY = new QSpinBox (this);
mY->setVisible (false);
mY->setMinimum (std::numeric_limits<int>::min());
mY->setMaximum (std::numeric_limits<int>::max());
connect (mY, SIGNAL (valueChanged (int)), this, SLOT (valueChanged (int)));
insertAtBeginning (mY, true);
mYLabel = new QLabel ("Y", this);
mYLabel->setVisible (false);
insertAtBeginning (mYLabel, false);
mX = new QSpinBox (this);
mX->setVisible (false);
mX->setMinimum (std::numeric_limits<int>::min());
mX->setMaximum (std::numeric_limits<int>::max());
connect (mX, SIGNAL (valueChanged (int)), this, SLOT (valueChanged (int)));
insertAtBeginning (mX, true);
mXLabel = new QLabel ("X", this);
mXLabel->setVisible (false);
insertAtBeginning (mXLabel, false);
mType = new QComboBox (this);
mType->addItem ("Interior Cell");
mType->addItem ("Exterior Cell");
connect (mType, SIGNAL (currentIndexChanged (int)), this, SLOT (setType (int)));
insertAtBeginning (mType, false);
}
void CSVWorld::CellCreator::reset()
{
mX->setValue (0);
mY->setValue (0);
mType->setCurrentIndex (0);
GenericCreator::reset();
}
void CSVWorld::CellCreator::setType (int index)
{
setManualEditing (index==0);
mXLabel->setVisible (index==1);
mX->setVisible (index==1);
mYLabel->setVisible (index==1);
mY->setVisible (index==1);
update();
}
void CSVWorld::CellCreator::valueChanged (int index)
{
update();
}

@ -0,0 +1,40 @@
#ifndef CSV_WORLD_CELLCREATOR_H
#define CSV_WORLD_CELLCREATOR_H
class QLabel;
class QSpinBox;
class QComboBox;
#include "genericcreator.hpp"
namespace CSVWorld
{
class CellCreator : public GenericCreator
{
Q_OBJECT
QComboBox *mType;
QLabel *mXLabel;
QSpinBox *mX;
QLabel *mYLabel;
QSpinBox *mY;
protected:
virtual std::string getId() const;
public:
CellCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id);
virtual void reset();
private slots:
void setType (int index);
void valueChanged (int index);
};
}
#endif

@ -0,0 +1,13 @@
#include "creator.hpp"
CSVWorld::Creator:: ~Creator() {}
CSVWorld::CreatorFactoryBase::~CreatorFactoryBase() {}
CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
{
return 0;
}

@ -0,0 +1,86 @@
#ifndef CSV_WORLD_CREATOR_H
#define CSV_WORLD_CREATOR_H
#include <QWidget>
class QUndoStack;
namespace CSMWorld
{
class Data;
class UniversalId;
}
namespace CSVWorld
{
/// \brief Record creator UI base class
class Creator : public QWidget
{
Q_OBJECT
public:
virtual ~Creator();
virtual void reset() = 0;
virtual void setEditLock (bool locked) = 0;
signals:
void done();
void requestFocus (const std::string& id);
///< Request owner of this creator to focus the just created \a id. The owner may
/// ignore this request.
};
/// \brief Base class for Creator factory
class CreatorFactoryBase
{
public:
virtual ~CreatorFactoryBase();
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const = 0;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function can return a 0-pointer, which means no UI for creating/deleting
/// records should be provided.
};
/// \brief Creator factory that does not produces any creator
class NullCreatorFactory : public CreatorFactoryBase
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function always returns 0.
};
template<class CreatorT>
class CreatorFactory : public CreatorFactoryBase
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function can return a 0-pointer, which means no UI for creating/deleting
/// records should be provided.
};
template<class CreatorT>
Creator *CreatorFactory<CreatorT>::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const
{
return new CreatorT (data, undoStack, id);
}
}
#endif

@ -0,0 +1,135 @@
#include "genericcreator.hpp"
#include <memory>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QUndoStack>
#include "../../model/world/commands.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp"
#include "idvalidator.hpp"
void CSVWorld::GenericCreator::update()
{
mErrors = getErrors();
mCreate->setToolTip (QString::fromUtf8 (mErrors.c_str()));
mId->setToolTip (QString::fromUtf8 (mErrors.c_str()));
mCreate->setEnabled (mErrors.empty() && !mLocked);
}
void CSVWorld::GenericCreator::setManualEditing (bool enabled)
{
mId->setVisible (enabled);
}
void CSVWorld::GenericCreator::insertAtBeginning (QWidget *widget, bool stretched)
{
mLayout->insertWidget (0, widget, stretched ? 1 : 0);
}
void CSVWorld::GenericCreator::insertBeforeButtons (QWidget *widget, bool stretched)
{
mLayout->insertWidget (mLayout->count()-2, widget, stretched ? 1 : 0);
}
std::string CSVWorld::GenericCreator::getId() const
{
return mId->text().toUtf8().constData();
}
void CSVWorld::GenericCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const {}
const CSMWorld::Data& CSVWorld::GenericCreator::getData() const
{
return mData;
}
CSMWorld::Data& CSVWorld::GenericCreator::getData()
{
return mData;
}
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false)
{
mLayout = new QHBoxLayout;
mLayout->setContentsMargins (0, 0, 0, 0);
mId = new QLineEdit;
mId->setValidator (new IdValidator (this));
mLayout->addWidget (mId, 1);
mCreate = new QPushButton ("Create");
mLayout->addWidget (mCreate);
QPushButton *cancelButton = new QPushButton ("Cancel");
mLayout->addWidget (cancelButton);
setLayout (mLayout);
connect (cancelButton, SIGNAL (clicked (bool)), this, SIGNAL (done()));
connect (mCreate, SIGNAL (clicked (bool)), this, SLOT (create()));
connect (mId, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&)));
}
void CSVWorld::GenericCreator::setEditLock (bool locked)
{
mLocked = locked;
update();
}
void CSVWorld::GenericCreator::reset()
{
mId->setText ("");
update();
}
std::string CSVWorld::GenericCreator::getErrors() const
{
std::string errors;
std::string id = getId();
if (id.empty())
{
errors = "Missing ID";
}
else if (mData.hasId (id))
{
errors = "ID is already in use";
}
return errors;
}
void CSVWorld::GenericCreator::textChanged (const QString& text)
{
update();
}
void CSVWorld::GenericCreator::create()
{
if (!mLocked)
{
std::string id = getId();
std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand (
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id));
configureCreateCommand (*command);
mUndoStack.push (command.release());
emit done();
emit requestFocus (id);
}
}

@ -0,0 +1,73 @@
#ifndef CSV_WORLD_GENERICCREATOR_H
#define CSV_WORLD_GENERICCREATOR_H
class QPushButton;
class QLineEdit;
class QHBoxLayout;
#include "creator.hpp"
#include "../../model/world/universalid.hpp"
namespace CSMWorld
{
class CreateCommand;
}
namespace CSVWorld
{
class GenericCreator : public Creator
{
Q_OBJECT
CSMWorld::Data& mData;
QUndoStack& mUndoStack;
CSMWorld::UniversalId mListId;
QPushButton *mCreate;
QLineEdit *mId;
std::string mErrors;
QHBoxLayout *mLayout;
bool mLocked;
protected:
void update();
virtual void setManualEditing (bool enabled);
///< Enable/disable manual ID editing (enabled by default).
void insertAtBeginning (QWidget *widget, bool stretched);
void insertBeforeButtons (QWidget *widget, bool stretched);
virtual std::string getId() const;
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
const CSMWorld::Data& getData() const;
CSMWorld::Data& getData();
public:
GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
virtual void setEditLock (bool locked);
virtual void reset();
virtual std::string getErrors() const;
///< Return formatted error descriptions for the current state of the creator. if an empty
/// string is returned, there is no error.
private slots:
void textChanged (const QString& text);
void create();
};
}
#endif

@ -0,0 +1,26 @@
#include "idvalidator.hpp"
bool CSVWorld::IdValidator::isValid (const QChar& c, bool first) const
{
if (c.isLetter() || c=='_')
return true;
if (!first && (c.isDigit() || c.isSpace()))
return true;
return false;
}
CSVWorld::IdValidator::IdValidator (QObject *parent) : QValidator (parent) {}
QValidator::State CSVWorld::IdValidator::validate (QString& input, int& pos) const
{
bool first = true;
for (QString::const_iterator iter (input.begin()); iter!=input.end(); ++iter, first = false)
if (!isValid (*iter, first))
return QValidator::Invalid;
return QValidator::Acceptable;
}

@ -0,0 +1,23 @@
#ifndef CSV_WORLD_IDVALIDATOR_H
#define CSV_WORLD_IDVALIDATOR_H
#include <QValidator>
namespace CSVWorld
{
class IdValidator : public QValidator
{
private:
bool isValid (const QChar& c, bool first) const;
public:
IdValidator (QObject *parent = 0);
virtual State validate (QString& input, int& pos) const;
};
}
#endif

@ -0,0 +1,43 @@
#include "referenceablecreator.hpp"
#include <QComboBox>
#include <QLabel>
#include "../../model/world/universalid.hpp"
#include "../../model/world/commands.hpp"
void CSVWorld::ReferenceableCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
{
command.setType (
static_cast<CSMWorld::UniversalId::Type> (mType->itemData (mType->currentIndex()).toInt()));
}
CSVWorld::ReferenceableCreator::ReferenceableCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
: GenericCreator (data, undoStack, id)
{
QLabel *label = new QLabel ("Type", this);
insertBeforeButtons (label, false);
std::vector<CSMWorld::UniversalId::Type> types = CSMWorld::UniversalId::listReferenceableTypes();
mType = new QComboBox (this);
for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin());
iter!=types.end(); ++iter)
{
CSMWorld::UniversalId id (*iter, "");
mType->addItem (QIcon (id.getIcon().c_str()), id.getTypeName().c_str(),
static_cast<int> (id.getType()));
}
insertBeforeButtons (mType, false);
}
void CSVWorld::ReferenceableCreator::reset()
{
mType->setCurrentIndex (0);
GenericCreator::reset();
}

@ -0,0 +1,30 @@
#ifndef CSV_WORLD_REFERENCEABLECREATOR_H
#define CSV_WORLD_REFERENCEABLECREATOR_H
class QComboBox;
#include "genericcreator.hpp"
namespace CSVWorld
{
class ReferenceableCreator : public GenericCreator
{
Q_OBJECT
QComboBox *mType;
private:
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
public:
ReferenceableCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
virtual void reset();
};
}
#endif

@ -0,0 +1,70 @@
#include "referencecreator.hpp"
#include <QLabel>
#include <QLineEdit>
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
std::string CSVWorld::ReferenceCreator::getId() const
{
return mId;
}
void CSVWorld::ReferenceCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
{
/// \todo avoid using hard-coded column numbers
command.addValue (2, mCell->text());
}
CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
: GenericCreator (data, undoStack, id)
{
QLabel *label = new QLabel ("Cell", this);
insertBeforeButtons (label, false);
mCell = new QLineEdit (this);
insertBeforeButtons (mCell, true);
setManualEditing (false);
connect (mCell, SIGNAL (textChanged (const QString&)), this, SLOT (cellChanged()));
}
void CSVWorld::ReferenceCreator::reset()
{
mCell->setText ("");
mId = getData().getReferences().getNewId();
GenericCreator::reset();
}
std::string CSVWorld::ReferenceCreator::getErrors() const
{
std::string errors = GenericCreator::getErrors();
std::string cell = mCell->text().toUtf8().constData();
if (cell.empty())
{
if (!errors.empty())
errors += "<br>";
errors += "Missing Cell ID";
}
else if (getData().getCells().searchId (cell)==-1)
{
if (!errors.empty())
errors += "<br>";
errors += "Invalid Cell ID";
}
return errors;
}
void CSVWorld::ReferenceCreator::cellChanged()
{
update();
}

@ -0,0 +1,40 @@
#ifndef CSV_WORLD_REFERENCECREATOR_H
#define CSV_WORLD_REFERENCECREATOR_H
#include "genericcreator.hpp"
class QLineEdit;
namespace CSVWorld
{
class ReferenceCreator : public GenericCreator
{
Q_OBJECT
QLineEdit *mCell;
std::string mId;
private:
virtual std::string getId() const;
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
public:
ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
virtual void reset();
virtual std::string getErrors() const;
///< Return formatted error descriptions for the current state of the creator. if an empty
/// string is returned, there is no error.
private slots:
void cellChanged();
};
}
#endif

@ -27,26 +27,15 @@ CSVWorld::RefIdTypeDelegateFactory::UidTypeList CSVWorld::RefIdTypeDelegateFacto
{
UidTypeList list;
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Activator, ":./activator.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Potion, ":./potion.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Apparatus, ":./apparatus.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Armor, ":./armor.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Book, ":./book.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Clothing, ":./clothing.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Container, ":./container.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Creature, ":./creature.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Door, ":./door.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Ingredient, ":./ingredient.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_CreatureLevelledList, ":./creature.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_ItemLevelledList, ":./item.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Light, ":./light.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Lockpick, ":./lockpick.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Miscellaneous, ":./misc.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Npc, ":./npc.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Probe, ":./probe.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Repair, ":./repair.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Static, ":./static.png"));
list.push_back (std::make_pair (CSMWorld::UniversalId::Type_Weapon, ":./weapon.png"));
std::vector<CSMWorld::UniversalId::Type> types = CSMWorld::UniversalId::listReferenceableTypes();
for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin());
iter!=types.end(); ++iter)
{
CSMWorld::UniversalId id (*iter, "");
list.push_back (std::make_pair (id.getType(), id.getIcon().c_str()));
}
return list;
}

@ -7,14 +7,20 @@
#include "dialoguesubview.hpp"
#include "scriptsubview.hpp"
#include "regionmapsubview.hpp"
#include "genericcreator.hpp"
#include "cellcreator.hpp"
#include "referenceablecreator.hpp"
#include "referencecreator.hpp"
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
{
// Regular record tables (including references which are actually sub-records, but are promoted
// to top-level records within the editor)
manager.add (CSMWorld::UniversalId::Type_Gmsts,
new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (false));
new CSVDoc::SubViewFactoryWithCreator<TableSubView, NullCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_Skills,
new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (false));
new CSVDoc::SubViewFactoryWithCreator<TableSubView, NullCreatorFactory>);
static const CSMWorld::UniversalId::Type sTableTypes[] =
{
@ -27,20 +33,26 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_Regions,
CSMWorld::UniversalId::Type_Birthsigns,
CSMWorld::UniversalId::Type_Spells,
CSMWorld::UniversalId::Type_Cells,
CSMWorld::UniversalId::Type_Referenceables,
CSMWorld::UniversalId::Type_References,
CSMWorld::UniversalId::Type_None // end marker
};
for (int i=0; sTableTypes[i]!=CSMWorld::UniversalId::Type_None; ++i)
manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreateFlag<TableSubView> (true));
manager.add (sTableTypes[i],
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator> >);
manager.add (CSMWorld::UniversalId::Type_Cells,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<CellCreator> >);
manager.add (CSMWorld::UniversalId::Type_Referenceables,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceableCreator> >);
manager.add (CSMWorld::UniversalId::Type_References,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceCreator> >);
// Subviews for editing/viewing individual records
manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory<ScriptSubView>);
// Other stuff (combined record tables)
manager.add (CSMWorld::UniversalId::Type_RegionMap, new CSVDoc::SubViewFactory<RegionMapSubView>);
// manager.add (CSMWorld::UniversalId::Type_Global,
// new CSVDoc::SubViewFactoryWithCreateFlag<DialogueSubView> (true));
}

@ -44,19 +44,30 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
std::vector<std::string> CSVWorld::Table::listRevertableSelectedIds() const
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
/// \todo Do not use hardcoded column numbers
std::vector<std::string> revertableIds;
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter)
if (mProxyModel->columnCount()>0)
{
std::string id = mProxyModel->data (*iter).toString().toStdString();
QModelIndexList selectedRows = selectionModel()->selectedRows();
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter)
{
QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0));
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (
mModel->data (mModel->index (index.row(), 1)).toInt());
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (mModel->data (mModel->getModelIndex (id, 1)).toInt());
if (state!=CSMWorld::RecordBase::State_BaseOnly)
{
std::string id = mModel->data (mModel->index (index.row(), 0)).
toString().toUtf8().constData();
if (state!=CSMWorld::RecordBase::State_BaseOnly)
revertableIds.push_back (id);
revertableIds.push_back (id);
}
}
}
return revertableIds;
@ -64,19 +75,30 @@ std::vector<std::string> CSVWorld::Table::listRevertableSelectedIds() const
std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
{
QModelIndexList selectedRows = selectionModel()->selectedRows();
/// \todo Do not use hardcoded column numbers
std::vector<std::string> deletableIds;
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter)
if (mProxyModel->columnCount()>0)
{
std::string id = mProxyModel->data (*iter).toString().toStdString();
QModelIndexList selectedRows = selectionModel()->selectedRows();
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (mModel->data (mModel->getModelIndex (id, 1)).toInt());
for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end();
++iter)
{
QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (iter->row(), 0));
if (state!=CSMWorld::RecordBase::State_Deleted)
deletableIds.push_back (id);
CSMWorld::RecordBase::State state =
static_cast<CSMWorld::RecordBase::State> (
mModel->data (mModel->index (index.row(), 1)).toInt());
if (state!=CSMWorld::RecordBase::State_Deleted)
{
std::string id = mModel->data (mModel->index (index.row(), 0)).
toString().toUtf8().constData();
deletableIds.push_back (id);
}
}
}
return deletableIds;
@ -126,7 +148,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
if (createAndDelete)
{
mCreateAction = new QAction (tr ("Add Record"), this);
connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord()));
connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest()));
addAction (mCreateAction);
}
@ -137,6 +159,17 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
mDeleteAction = new QAction (tr ("Delete Record"), this);
connect (mDeleteAction, SIGNAL (triggered()), this, SLOT (deleteRecord()));
addAction (mDeleteAction);
connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (tableSizeUpdate()));
/// \note This signal could instead be connected to a slot that filters out changes not affecting
/// the records status column (for permanence reasons)
connect (mProxyModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (tableSizeUpdate()));
connect (selectionModel(), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)),
this, SLOT (selectionSizeUpdate ()));
}
void CSVWorld::Table::setEditLock (bool locked)
@ -154,22 +187,6 @@ CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const
mProxyModel->data (mProxyModel->index (row, 0)).toString().toStdString());
}
#include <sstream> /// \todo remove
void CSVWorld::Table::createRecord()
{
if (!mEditLock)
{
/// \todo ask the user for an ID instead.
static int index = 0;
std::ostringstream stream;
stream << "id" << index++;
mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str()));
}
}
void CSVWorld::Table::revertRecord()
{
if (!mEditLock)
@ -231,3 +248,46 @@ void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QSt
updateEditorSetting (settingName, settingValue))
emit dataChanged (mModel->index (0, i), mModel->index (mModel->rowCount()-1, i));
}
void CSVWorld::Table::tableSizeUpdate()
{
int size = 0;
int deleted = 0;
int modified = 0;
if (mModel->columnCount()>0)
{
int rows = mModel->rowCount();
for (int i=0; i<rows; ++i)
{
QModelIndex index = mProxyModel->mapToSource (mProxyModel->index (i, 0));
/// \todo Do not use hardcoded column numbers
int state = mModel->data (mModel->index (index.row(), 1)).toInt();
switch (state)
{
case CSMWorld::RecordBase::State_BaseOnly: ++size; break;
case CSMWorld::RecordBase::State_Modified: ++size; ++modified; break;
case CSMWorld::RecordBase::State_ModifiedOnly: ++size; ++modified; break;
case CSMWorld::RecordBase:: State_Deleted: ++deleted; ++modified; break;
}
}
}
tableSizeChanged (size, deleted, modified);
}
void CSVWorld::Table::selectionSizeUpdate()
{
selectionSizeChanged (selectionModel()->selectedRows().size());
}
void CSVWorld::Table::requestFocus (const std::string& id)
{
QModelIndex index = mProxyModel->getModelIndex (id, 0);
if (index.isValid())
scrollTo (index, QAbstractItemView::PositionAtTop);
}

@ -60,15 +60,31 @@ namespace CSVWorld
void editRequest (int row);
private slots:
void selectionSizeChanged (int size);
void tableSizeChanged (int size, int deleted, int modified);
///< \param size Number of not deleted records
/// \param deleted Number of deleted records
/// \param modified Number of added and modified records
void createRecord();
void createRequest();
private slots:
void revertRecord();
void deleteRecord();
void editRecord();
public slots:
void tableSizeUpdate();
void selectionSizeUpdate();
void requestFocus (const std::string& id);
};
}

@ -0,0 +1,156 @@
#include "tablebottombox.hpp"
#include <sstream>
#include <QStatusBar>
#include <QStackedLayout>
#include <QLabel>
#include "creator.hpp"
void CSVWorld::TableBottomBox::updateStatus()
{
if (mShowStatusBar)
{
static const char *sLabels[4] = { "record", "deleted", "touched", "selected" };
static const char *sLabelsPlural[4] = { "records", "deleted", "touched", "selected" };
std::ostringstream stream;
bool first = true;
for (int i=0; i<4; ++i)
{
if (mStatusCount[i]>0)
{
if (first)
first = false;
else
stream << ", ";
stream
<< mStatusCount[i] << ' '
<< (mStatusCount[i]==1 ? sLabels[i] : sLabelsPlural[i]);
}
}
mStatus->setText (QString::fromUtf8 (stream.str().c_str()));
}
}
CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory,
CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, QWidget *parent)
: QWidget (parent), mShowStatusBar (false), mCreating (false)
{
for (int i=0; i<4; ++i)
mStatusCount[i] = 0;
setVisible (false);
mLayout = new QStackedLayout;
mLayout->setContentsMargins (0, 0, 0, 0);
mStatus = new QLabel;
mStatusBar = new QStatusBar;
mStatusBar->addWidget (mStatus);
mLayout->addWidget (mStatusBar);
setLayout (mLayout);
mCreator = creatorFactory.makeCreator (data, undoStack, id);
mLayout->addWidget (mCreator);
connect (mCreator, SIGNAL (done()), this, SLOT (createRequestDone()));
connect (mCreator, SIGNAL (requestFocus (const std::string&)),
this, SIGNAL (requestFocus (const std::string&)));
}
void CSVWorld::TableBottomBox::setEditLock (bool locked)
{
if (mCreator)
mCreator->setEditLock (locked);
}
CSVWorld::TableBottomBox::~TableBottomBox()
{
delete mCreator;
}
void CSVWorld::TableBottomBox::setStatusBar (bool show)
{
if (show!=mShowStatusBar)
{
setVisible (show || mCreating);
mShowStatusBar = show;
if (show)
updateStatus();
}
}
bool CSVWorld::TableBottomBox::canCreateAndDelete() const
{
return mCreator;
}
void CSVWorld::TableBottomBox::createRequestDone()
{
if (!mShowStatusBar)
setVisible (false);
else
updateStatus();
mLayout->setCurrentWidget (mStatusBar);
mCreating = false;
}
void CSVWorld::TableBottomBox::selectionSizeChanged (int size)
{
if (mStatusCount[3]!=size)
{
mStatusCount[3] = size;
updateStatus();
}
}
void CSVWorld::TableBottomBox::tableSizeChanged (int size, int deleted, int modified)
{
bool changed = false;
if (mStatusCount[0]!=size)
{
mStatusCount[0] = size;
changed = true;
}
if (mStatusCount[1]!=deleted)
{
mStatusCount[1] = deleted;
changed = true;
}
if (mStatusCount[2]!=modified)
{
mStatusCount[2] = modified;
changed = true;
}
if (changed)
updateStatus();
}
void CSVWorld::TableBottomBox::createRequest()
{
mCreator->reset();
mLayout->setCurrentWidget (mCreator);
setVisible (true);
mCreating = true;
}

@ -0,0 +1,82 @@
#ifndef CSV_WORLD_BOTTOMBOX_H
#define CSV_WORLD_BOTTOMBOX_H
#include <QWidget>
class QLabel;
class QStackedLayout;
class QStatusBar;
class QUndoStack;
namespace CSMWorld
{
class Data;
class UniversalId;
}
namespace CSVWorld
{
class CreatorFactoryBase;
class Creator;
class TableBottomBox : public QWidget
{
Q_OBJECT
bool mShowStatusBar;
QLabel *mStatus;
QStatusBar *mStatusBar;
int mStatusCount[4];
Creator *mCreator;
bool mCreating;
QStackedLayout *mLayout;
private:
// not implemented
TableBottomBox (const TableBottomBox&);
TableBottomBox& operator= (const TableBottomBox&);
void updateStatus();
public:
TableBottomBox (const CreatorFactoryBase& creatorFactory, CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id, QWidget *parent = 0);
virtual ~TableBottomBox();
void setEditLock (bool locked);
void setStatusBar (bool show);
bool canCreateAndDelete() const;
///< Is record creation and deletion supported?
///
/// \note The BotomBox does not partake in the deletion of records.
signals:
void requestFocus (const std::string& id);
///< Request owner of this box to focus the just created \a id. The owner may
/// ignore this request.
private slots:
void createRequestDone();
///< \note This slot being called does not imply success.
public slots:
void selectionSizeChanged (int size);
void tableSizeChanged (int size, int deleted, int modified);
///< \param size Number of not deleted records
/// \param deleted Number of deleted records
/// \param modified Number of added and modified records
void createRequest();
};
}
#endif

@ -1,22 +1,55 @@
#include "tablesubview.hpp"
#include <QVBoxLayout>
#include "../../model/doc/document.hpp"
#include "table.hpp"
#include "tablebottombox.hpp"
#include "creator.hpp"
CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
bool createAndDelete)
const CreatorFactoryBase& creatorFactory)
: SubView (id)
{
setWidget (mTable = new Table (id, document.getData(), document.getUndoStack(), createAndDelete));
QVBoxLayout *layout = new QVBoxLayout;
layout->setContentsMargins (QMargins (0, 0, 0, 0));
layout->addWidget (mBottom =
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
layout->insertWidget (0, mTable =
new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete()), 2);
QWidget *widget = new QWidget;
widget->setLayout (layout);
setWidget (widget);
connect (mTable, SIGNAL (editRequest (int)), this, SLOT (editRequest (int)));
connect (mTable, SIGNAL (selectionSizeChanged (int)),
mBottom, SLOT (selectionSizeChanged (int)));
connect (mTable, SIGNAL (tableSizeChanged (int, int, int)),
mBottom, SLOT (tableSizeChanged (int, int, int)));
mTable->tableSizeUpdate();
mTable->selectionSizeUpdate();
if (mBottom->canCreateAndDelete())
connect (mTable, SIGNAL (createRequest()), mBottom, SLOT (createRequest()));
connect (mBottom, SIGNAL (requestFocus (const std::string&)),
mTable, SLOT (requestFocus (const std::string&)));
}
void CSVWorld::TableSubView::setEditLock (bool locked)
{
mTable->setEditLock (locked);
mBottom->setEditLock (locked);
}
void CSVWorld::TableSubView::editRequest (int row)
@ -28,3 +61,8 @@ void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, con
{
mTable->updateEditorSetting(settingName, settingValue);
}
void CSVWorld::TableSubView::setStatusBar (bool show)
{
mBottom->setStatusBar (show);
}

@ -13,18 +13,26 @@ namespace CSMDoc
namespace CSVWorld
{
class Table;
class TableBottomBox;
class CreatorFactoryBase;
class TableSubView : public CSVDoc::SubView
{
Q_OBJECT
Table *mTable;
TableBottomBox *mBottom;
public:
TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete);
TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
const CreatorFactoryBase& creatorFactory);
virtual void setEditLock (bool locked);
void updateEditorSetting (const QString &, const QString &);
virtual void updateEditorSetting (const QString& key, const QString& value);
virtual void setStatusBar (bool show);
private slots:

Loading…
Cancel
Save