diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 7723b15f5..37d13223a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -26,6 +26,7 @@ opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection + idcompletionmanager ) opencs_hdrs_noqt (model/world @@ -68,12 +69,12 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem + scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate ) opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton - scenetooltoggle2 + scenetooltoggle2 completerpopup ) opencs_units (view/render diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index a73201ec0..18a4f4878 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2257,7 +2257,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, mSavingOperation (*this, mProjectPath, encoding), mSaving (&mSavingOperation), mResDir(resDir), - mRunner (mProjectPath), mPhysics(boost::shared_ptr()) + mRunner (mProjectPath), mPhysics(boost::shared_ptr()), + mIdCompletionManager(mData) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2488,3 +2489,8 @@ boost::shared_ptr CSMDoc::Document::getPhysics () return mPhysics; } + +CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager() +{ + return mIdCompletionManager; +} diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 6b1a1fc1e..14daeeb75 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -13,6 +13,7 @@ #include #include "../world/data.hpp" +#include "../world/idcompletionmanager.hpp" #include "../tools/tools.hpp" @@ -66,6 +67,7 @@ namespace CSMDoc Blacklist mBlacklist; Runner mRunner; boost::shared_ptr mPhysics; + CSMWorld::IdCompletionManager mIdCompletionManager; // It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is // using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late. @@ -144,6 +146,8 @@ namespace CSMDoc boost::shared_ptr getPhysics(); + CSMWorld::IdCompletionManager &getIdCompletionManager(); + signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 3d13538c0..938503875 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -65,6 +65,8 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_BodyPart, + Display_Enchantment, Display_Script, Display_Mesh, diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index bf8378e37..789823d5c 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -74,6 +74,8 @@ namespace CSMWorld Display_JournalInfo, Display_Scene, Display_GlobalVariable, + Display_BodyPart, + Display_Enchantment, //CONCRETE TYPES ENDS HERE Display_Integer, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6b496e0ca..8758d924b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -709,7 +709,7 @@ namespace CSMWorld struct SleepListColumn : public Column { SleepListColumn() - : Column (Columns::ColumnId_SleepEncounter, ColumnBase::Display_String) + : Column (Columns::ColumnId_SleepEncounter, ColumnBase::Display_CreatureLevelledList) {} virtual QVariant get (const Record& record) const @@ -735,7 +735,7 @@ namespace CSMWorld template struct TextureColumn : public Column { - TextureColumn() : Column (Columns::ColumnId_Texture, ColumnBase::Display_String) {} + TextureColumn() : Column (Columns::ColumnId_Texture, ColumnBase::Display_Texture) {} virtual QVariant get (const Record& record) const { @@ -1269,7 +1269,7 @@ namespace CSMWorld template struct TrapColumn : public Column { - TrapColumn() : Column (Columns::ColumnId_Trap, ColumnBase::Display_String) {} + TrapColumn() : Column (Columns::ColumnId_Trap, ColumnBase::Display_Spell) {} virtual QVariant get (const Record& record) const { @@ -1294,7 +1294,7 @@ namespace CSMWorld template struct FilterColumn : public Column { - FilterColumn() : Column (Columns::ColumnId_Filter, ColumnBase::Display_String) {} + FilterColumn() : Column (Columns::ColumnId_Filter, ColumnBase::Display_Filter) {} virtual QVariant get (const Record& record) const { @@ -1497,7 +1497,10 @@ namespace CSMWorld template struct TopicColumn : public Column { - TopicColumn (bool journal) : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, ColumnBase::Display_String) {} + TopicColumn (bool journal) + : Column (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, + journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic) + {} virtual QVariant get (const Record& record) const { @@ -1527,7 +1530,7 @@ namespace CSMWorld template struct ActorColumn : public Column { - ActorColumn() : Column (Columns::ColumnId_Actor, ColumnBase::Display_String) {} + ActorColumn() : Column (Columns::ColumnId_Actor, ColumnBase::Display_Npc) {} virtual QVariant get (const Record& record) const { @@ -1830,7 +1833,7 @@ namespace CSMWorld template struct ModelColumn : public Column { - ModelColumn() : Column (Columns::ColumnId_Model, ColumnBase::Display_String) {} + ModelColumn() : Column (Columns::ColumnId_Model, ColumnBase::Display_Mesh) {} virtual QVariant get (const Record& record) const { @@ -2158,7 +2161,9 @@ namespace CSMWorld struct EffectTextureColumn : public Column { EffectTextureColumn (Columns::ColumnId columnId) - : Column (columnId, ColumnBase::Display_Texture) + : Column (columnId, + columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture + : ColumnBase::Display_Icon) { assert (this->mColumnId==Columns::ColumnId_Icon || this->mColumnId==Columns::ColumnId_Particle); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c27c068f1..529c8f88f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -115,7 +115,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mFactions.getColumns()-1; mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ())); mFactions.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction)); mFactions.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); @@ -135,7 +135,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRaces.getColumns()-1; mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); mRaces.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); // Race attributes mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes)); index = mRaces.getColumns()-1; @@ -180,7 +180,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc index = mRegions.getColumns()-1; mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ())); mRegions.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_Sound)); mRegions.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); @@ -196,7 +196,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index), new SpellListAdapter ())); mBirthsigns.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell)); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/idcompletionmanager.cpp b/apps/opencs/model/world/idcompletionmanager.cpp new file mode 100644 index 000000000..b59987cba --- /dev/null +++ b/apps/opencs/model/world/idcompletionmanager.cpp @@ -0,0 +1,110 @@ +#include "idcompletionmanager.hpp" + +#include + +#include + +#include "../../view/widget/completerpopup.hpp" + +#include "data.hpp" +#include "idtablebase.hpp" + +namespace +{ + std::map generateModelTypes() + { + std::map types; + + types[CSMWorld::ColumnBase::Display_BodyPart ] = CSMWorld::UniversalId::Type_BodyPart; + types[CSMWorld::ColumnBase::Display_Cell ] = CSMWorld::UniversalId::Type_Cell; + types[CSMWorld::ColumnBase::Display_Class ] = CSMWorld::UniversalId::Type_Class; + types[CSMWorld::ColumnBase::Display_CreatureLevelledList] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Creature ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Enchantment ] = CSMWorld::UniversalId::Type_Enchantment; + types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction; + types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global; + types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon; + types[CSMWorld::ColumnBase::Display_Mesh ] = CSMWorld::UniversalId::Type_Mesh; + types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Npc ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Race ] = CSMWorld::UniversalId::Type_Race; + types[CSMWorld::ColumnBase::Display_Region ] = CSMWorld::UniversalId::Type_Region; + types[CSMWorld::ColumnBase::Display_Referenceable ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Script ] = CSMWorld::UniversalId::Type_Script; + types[CSMWorld::ColumnBase::Display_Skill ] = CSMWorld::UniversalId::Type_Skill; + types[CSMWorld::ColumnBase::Display_Sound ] = CSMWorld::UniversalId::Type_Sound; + types[CSMWorld::ColumnBase::Display_SoundRes ] = CSMWorld::UniversalId::Type_SoundRes; + types[CSMWorld::ColumnBase::Display_Spell ] = CSMWorld::UniversalId::Type_Spell; + types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable; + types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture; + types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable; + + return types; + } + + typedef std::map::const_iterator ModelTypeConstIterator; +} + +const std::map + CSMWorld::IdCompletionManager::sCompleterModelTypes = generateModelTypes(); + +std::vector CSMWorld::IdCompletionManager::getDisplayTypes() +{ + std::vector types; + ModelTypeConstIterator current = sCompleterModelTypes.begin(); + ModelTypeConstIterator end = sCompleterModelTypes.end(); + for (; current != end; ++current) + { + types.push_back(current->first); + } + return types; +} + +CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data) +{ + generateCompleters(data); +} + +bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::ColumnBase::Display display) const +{ + return mCompleters.find(display) != mCompleters.end(); +} + +boost::shared_ptr CSMWorld::IdCompletionManager::getCompleter(CSMWorld::ColumnBase::Display display) +{ + if (!hasCompleterFor(display)) + { + throw std::logic_error("This column doesn't have an ID completer"); + } + return mCompleters[display]; +} + +void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data) +{ + ModelTypeConstIterator current = sCompleterModelTypes.begin(); + ModelTypeConstIterator end = sCompleterModelTypes.end(); + for (; current != end; ++current) + { + QAbstractItemModel *model = data.getTableModel(current->second); + CSMWorld::IdTableBase *table = dynamic_cast(model); + if (table != NULL) + { + int idColumn = table->searchColumnIndex(CSMWorld::Columns::ColumnId_Id); + if (idColumn != -1) + { + boost::shared_ptr completer = boost::make_shared(table); + completer->setCompletionColumn(idColumn); + // The completion role must be Qt::DisplayRole to get the ID values from the model + completer->setCompletionRole(Qt::DisplayRole); + completer->setCaseSensitivity(Qt::CaseInsensitive); + + QAbstractItemView *popup = new CSVWidget::CompleterPopup(); + completer->setPopup(popup); // The completer takes ownership of the popup + completer->setMaxVisibleItems(10); + + mCompleters[current->first] = completer; + } + } + } +} diff --git a/apps/opencs/model/world/idcompletionmanager.hpp b/apps/opencs/model/world/idcompletionmanager.hpp new file mode 100644 index 000000000..7944e6777 --- /dev/null +++ b/apps/opencs/model/world/idcompletionmanager.hpp @@ -0,0 +1,41 @@ +#ifndef CSM_WORLD_IDCOMPLETIONMANAGER_HPP +#define CSM_WORLD_IDCOMPLETIONMANAGER_HPP + +#include +#include + +#include + +#include "columnbase.hpp" +#include "universalid.hpp" + +class QCompleter; + +namespace CSMWorld +{ + class Data; + + /// \brief Creates and stores all ID completers + class IdCompletionManager + { + static const std::map sCompleterModelTypes; + + std::map > mCompleters; + + // Don't allow copying + IdCompletionManager(const IdCompletionManager &); + IdCompletionManager &operator = (const IdCompletionManager &); + + void generateCompleters(Data &data); + + public: + static std::vector getDisplayTypes(); + + IdCompletionManager(Data &data); + + bool hasCompleterFor(ColumnBase::Display display) const; + boost::shared_ptr getCompleter(ColumnBase::Display display); + }; +} + +#endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 04aa271cc..8ca19f7e9 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -33,6 +33,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (index.row() < 0 || index.column() < 0) return QVariant(); + if (role==ColumnBase::Role_Display) + return QVariant(mIdCollection->getColumn(index.column()).mDisplayType); + if (role==ColumnBase::Role_ColumnId) return QVariant (getColumnId (index.column())); @@ -84,6 +87,9 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const { + if (!index.isValid()) + return 0; + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; if (mIdCollection->getColumn (index.column()).isUserEditable()) diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 7351c03a7..1e81d6ac2 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -35,28 +35,29 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const if (!index.isValid()) return QVariant(); - if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0) - return QVariant(); - if (index.internalId() != 0) { std::pair parentAddress(unfoldIndexAddress(index.internalId())); + const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second); - if (role == Qt::EditRole && - !mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable()) - { + if (role == ColumnBase::Role_Display) + return parentColumn->nestedColumn(index.column()).mDisplayType; + + if (role == ColumnBase::Role_ColumnId) + return parentColumn->nestedColumn(index.column()).mColumnId; + + if (role == Qt::EditRole && !parentColumn->nestedColumn(index.column()).isEditable()) + return QVariant(); + + if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant(); - } return mNestedCollection->getNestedData(parentAddress.first, parentAddress.second, index.row(), index.column()); } else { - if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) - return QVariant(); - - return idCollection()->getData (index.row(), index.column()); + return IdTable::data(index, role); } } @@ -79,6 +80,9 @@ QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Ori if (role==ColumnBase::Role_Display) return parentColumn->nestedColumn(subSection).mDisplayType; + if (role==ColumnBase::Role_ColumnId) + return parentColumn->nestedColumn(subSection).mColumnId; + return QVariant(); } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index cda19c87b..5495926b4 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -99,7 +99,7 @@ CSMWorld::RefIdCollection::RefIdCollection() EnchantableColumns enchantableColumns (inventoryColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_Enchantment)); enchantableColumns.mEnchantment = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer)); enchantableColumns.mEnchantmentPoints = &mColumns.back(); @@ -135,7 +135,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedInventoryRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); @@ -150,7 +150,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedSpellRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell)); // Nested table mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, @@ -163,7 +163,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedTravelRefIdAdapter (UniversalId::Type_Creature))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); mColumns.back().addColumn( @@ -289,7 +289,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedInventoryRefIdAdapter (UniversalId::Type_Container))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); @@ -301,7 +301,7 @@ CSMWorld::RefIdCollection::RefIdCollection() creatureColumns.mSoul = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float)); creatureColumns.mScale = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_Creature)); creatureColumns.mOriginal = &mColumns.back(); mColumns.push_back ( RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer)); @@ -409,10 +409,10 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction)); npcColumns.mFaction = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_BodyPart)); npcColumns.mHair = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_String)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart)); npcColumns.mHead = &mColumns.back(); mColumns.push_back (RefIdColumn (Columns::ColumnId_Female, ColumnBase::Display_Boolean)); @@ -539,9 +539,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_BodyPart)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_BodyPart)); LevListColumns levListColumns (baseColumns); @@ -556,7 +556,7 @@ CSMWorld::RefIdCollection::RefIdCollection() new NestedLevListRefIdAdapter (UniversalId::Type_ItemLevelledList))); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_String)); + new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable)); mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 97b7aac19..b2f681df1 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -1,6 +1,7 @@ #include "viewmanager.hpp" +#include #include #include @@ -10,12 +11,14 @@ #include "../../model/doc/document.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/universalid.hpp" +#include "../../model/world/idcompletionmanager.hpp" #include "../world/util.hpp" #include "../world/enumdelegate.hpp" #include "../world/vartypedelegate.hpp" #include "../world/recordstatusdelegate.hpp" #include "../world/idtypedelegate.hpp" +#include "../world/idcompletiondelegate.hpp" #include "../../model/settings/usersettings.hpp" @@ -60,6 +63,14 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, new CSVWorld::IdTypeDelegateFactory()); + std::vector idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes(); + for (std::vector::const_iterator current = idCompletionColumns.begin(); + current != idCompletionColumns.end(); + ++current) + { + mDelegateFactories->add(*current, new CSVWorld::IdCompletionDelegateFactory()); + } + struct Mapping { CSMWorld::ColumnBase::Display mDisplay; diff --git a/apps/opencs/view/widget/completerpopup.cpp b/apps/opencs/view/widget/completerpopup.cpp new file mode 100644 index 000000000..5777325c8 --- /dev/null +++ b/apps/opencs/view/widget/completerpopup.cpp @@ -0,0 +1,28 @@ +#include "completerpopup.hpp" + +CSVWidget::CompleterPopup::CompleterPopup(QWidget *parent) + : QListView(parent) +{ + setEditTriggers(QAbstractItemView::NoEditTriggers); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::SingleSelection); +} + +int CSVWidget::CompleterPopup::sizeHintForRow(int row) const +{ + if (model() == NULL) + { + return -1; + } + if (row < 0 || row >= model()->rowCount()) + { + return -1; + } + + ensurePolished(); + QModelIndex index = model()->index(row, modelColumn()); + QStyleOptionViewItem option = viewOptions(); + QAbstractItemDelegate *delegate = itemDelegate(index); + return delegate->sizeHint(option, index).height(); +} diff --git a/apps/opencs/view/widget/completerpopup.hpp b/apps/opencs/view/widget/completerpopup.hpp new file mode 100644 index 000000000..6857064b8 --- /dev/null +++ b/apps/opencs/view/widget/completerpopup.hpp @@ -0,0 +1,17 @@ +#ifndef CSV_WIDGET_COMPLETERPOPUP_HPP +#define CSV_WIDGET_COMPLETERPOPUP_HPP + +#include + +namespace CSVWidget +{ + class CompleterPopup : public QListView + { + public: + CompleterPopup(QWidget *parent = 0); + + virtual int sizeHintForRow(int row) const; + }; +} + +#endif diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp new file mode 100644 index 000000000..056026471 --- /dev/null +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -0,0 +1,39 @@ +#include "idcompletiondelegate.hpp" + +#include "../../model/world/idcompletionmanager.hpp" + +CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) + : CommandDelegate(dispatcher, document, parent) +{} + +QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + return createEditor(parent, option, index, getDisplayTypeFromIndex(index)); +} + +QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index, + CSMWorld::ColumnBase::Display display) const +{ + if (!index.data(Qt::EditRole).isValid() && !index.data(Qt::DisplayRole).isValid()) + { + return NULL; + } + + CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager(); + DropLineEdit *editor = new DropLineEdit(parent); + editor->setCompleter(completionManager.getCompleter(display).get()); + return editor; +} + +CSVWorld::CommandDelegate *CSVWorld::IdCompletionDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) const +{ + return new IdCompletionDelegate(dispatcher, document, parent); +} diff --git a/apps/opencs/view/world/idcompletiondelegate.hpp b/apps/opencs/view/world/idcompletiondelegate.hpp new file mode 100644 index 000000000..d2ac6874f --- /dev/null +++ b/apps/opencs/view/world/idcompletiondelegate.hpp @@ -0,0 +1,36 @@ +#ifndef CSV_WORLD_IDCOMPLETIONDELEGATE_HPP +#define CSV_WORLD_IDCOMPLETIONDELEGATE_HPP + +#include "util.hpp" + +namespace CSVWorld +{ + /// \brief Enables the Id completion for a column + class IdCompletionDelegate : public CommandDelegate + { + public: + IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent); + + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index, + CSMWorld::ColumnBase::Display display) const; + }; + + class IdCompletionDelegateFactory : public CommandDelegateFactory + { + public: + virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher, + CSMDoc::Document& document, + QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + }; +} + +#endif diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 5452214ef..e1d165a24 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -111,6 +111,12 @@ CSMDoc::Document& CSVWorld::CommandDelegate::getDocument() const return mDocument; } +CSMWorld::ColumnBase::Display CSVWorld::CommandDelegate::getDisplayTypeFromIndex(const QModelIndex &index) const +{ + int rawDisplay = index.data(CSMWorld::ColumnBase::Role_Display).toInt(); + return static_cast(rawDisplay); +} + void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const { @@ -146,7 +152,17 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { - return createEditor (parent, option, index, CSMWorld::ColumnBase::Display_None); + CSMWorld::ColumnBase::Display display = getDisplayTypeFromIndex(index); + + // This createEditor() method is called implicitly from tables. + // For boolean values in tables use the default editor (combobox). + // Checkboxes is looking ugly in the table view. + // TODO: Find a better solution? + if (display == CSMWorld::ColumnBase::Display_Boolean) + { + return QStyledItemDelegate::createEditor(parent, option, index); + } + return createEditor (parent, option, index, display); } QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index a12e6ae36..8355e971c 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -124,6 +124,8 @@ namespace CSVWorld CSMDoc::Document& getDocument() const; + CSMWorld::ColumnBase::Display getDisplayTypeFromIndex(const QModelIndex &index) const; + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const;