Commit 27ba3923 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Extended LuaTableTreeModel to support different model styles.

The FULL_MODEL represents the entire data tree as it exists in the Lua VM. The COMPLETER_MODEL collapses the tables to a representation only containing tables and their corresponding SWIG instance methods. This allows the CompletingLuaLineEdit also to show inherited methods.

refs #643
parent 9b59c3eb
......@@ -38,7 +38,7 @@ namespace campvis {
, _luaVmState(luaVmState)
{
auto luaTreeModel = new LuaTableTreeModel(this);
luaTreeModel->setData(_luaVmState);
luaTreeModel->setData(_luaVmState, LuaTreeItem::COMPLETER_MODEL);
setModel(luaTreeModel);
}
......@@ -59,9 +59,7 @@ namespace campvis {
}
if (path[end] == ':') {
toReturn.push_back(path.mid(start, end-start));
toReturn.push_back("[Metatable]");
//toReturn.push_back(".instance");
toReturn.push_back(".fn");
toReturn.push_back("[Methods]");
start = end+1;
}
}
......
......@@ -69,9 +69,10 @@ namespace campvis {
// = TreeModel items ==============================================================================
LuaTreeItem::LuaTreeItem(const std::string& name, int type, TreeItem* parent /*= nullptr*/) : TreeItem(parent)
LuaTreeItem::LuaTreeItem(ModelStyle modelStyle, const std::string& name, int type, TreeItem* parent /*= nullptr*/) : TreeItem(parent)
, _name(name)
, _type(type)
, _modelStyle(modelStyle)
{
}
......@@ -120,12 +121,12 @@ namespace campvis {
// ================================================================================================
LuaTreeItemLeaf::LuaTreeItemLeaf(std::shared_ptr<LuaTable> parentTable, const std::string& name, int type, TreeItem* parent)
: LuaTreeItem(name, type, parent)
LuaTreeItemLeaf::LuaTreeItemLeaf(ModelStyle modelStyle, std::shared_ptr<LuaTable> parentTable, const std::string& name, int type, TreeItem* parent)
: LuaTreeItem(modelStyle, name, type, parent)
, _parentTable(parentTable)
{
if (parentTable->hasMetatable(_name)) {
new LuaTreeItemTable(true, parentTable->getMetatable(name), name, LUA_TTABLE, this);
new LuaTreeItemTable(_modelStyle, true, parentTable->getMetatable(name), name, LUA_TTABLE, this);
}
}
......@@ -147,8 +148,8 @@ namespace campvis {
// ================================================================================================
LuaTreeItemTable::LuaTreeItemTable(bool isMetatable, std::shared_ptr<LuaTable> thisTable, const std::string& name, int type, TreeItem* parent)
: LuaTreeItem(name, type, parent)
LuaTreeItemTable::LuaTreeItemTable(ModelStyle modelStyle, bool isMetatable, std::shared_ptr<LuaTable> thisTable, const std::string& name, int type, TreeItem* parent)
: LuaTreeItem(modelStyle, name, type, parent)
, _thisTable(thisTable)
, _isMetatable(isMetatable)
{
......@@ -156,22 +157,56 @@ namespace campvis {
// somehow, we need to get the parent table to check for the metatable.
auto ltit = dynamic_cast<LuaTreeItemTable*>(getParent());
if (ltit && ltit->_thisTable->hasMetatable(_name)) {
new LuaTreeItemTable(true, ltit->_thisTable->getMetatable(name), name, LUA_TTABLE, this);
new LuaTreeItemTable(_modelStyle, true, ltit->_thisTable->getMetatable(name), name, LUA_TTABLE, this);
}
auto& valueMap = thisTable->getValueMap();
for (auto it = valueMap.cbegin(); it != valueMap.cend(); ++it) {
const std::string& itemName = it->first;
int luaType = it->second.luaType;
if (itemName == "_G")
continue;
LuaTreeItem* lti = nullptr;
if (luaType == LUA_TTABLE)
lti = new LuaTreeItemTable(false, thisTable->getTable(itemName), itemName, luaType, this);
else
lti = new LuaTreeItemLeaf(thisTable, itemName, luaType, this);
// fill the table with values depending on model style
if (_modelStyle == FULL_MODEL) {
auto& valueMap = thisTable->getValueMap();
for (auto it = valueMap.cbegin(); it != valueMap.cend(); ++it) {
const std::string& itemName = it->first;
int luaType = it->second.luaType;
if (itemName == "_G")
continue;
LuaTreeItem* lti = nullptr;
if (luaType == LUA_TTABLE)
lti = new LuaTreeItemTable(_modelStyle, false, thisTable->getTable(itemName), itemName, luaType, this);
else
lti = new LuaTreeItemLeaf(_modelStyle, thisTable, itemName, luaType, this);
}
}
else if (_modelStyle == COMPLETER_MODEL) {
auto& valueMap = thisTable->getValueMap();
if (! _isMetatable) {
// for regular tables, just explore the whole table
for (auto it = valueMap.cbegin(); it != valueMap.cend(); ++it) {
const std::string& itemName = it->first;
int luaType = it->second.luaType;
if (itemName == "_G")
continue;
LuaTreeItem* lti = nullptr;
if (luaType == LUA_TTABLE)
lti = new LuaTreeItemTable(_modelStyle, false, thisTable->getTable(itemName), itemName, luaType, this);
else
lti = new LuaTreeItemLeaf(_modelStyle, thisTable, itemName, luaType, this);
}
}
else {
// for metatables, just gather all instance methods
auto fnTable = thisTable->getTable(".fn");
if (fnTable) {
recursiveGatherSwigMethods(thisTable, this);
}
auto instanceTable = thisTable->getTable(".instance");
if (instanceTable) {
recursiveGatherSwigMethods(instanceTable, this);
}
}
}
}
......@@ -181,13 +216,45 @@ namespace campvis {
QVariant LuaTreeItemTable::getData(int column, int role) const {
if (_isMetatable && column == COLUMN_NAME && (role == Qt::EditRole || role == Qt::DisplayRole)) {
return QVariant("[Metatable]");
switch (_modelStyle) {
case FULL_MODEL:
return QVariant("[Metatable]");
case COMPLETER_MODEL:
return QVariant("[Methods]");
}
}
else {
return LuaTreeItem::getData(column, role);
}
}
void LuaTreeItemTable::recursiveGatherSwigMethods(const std::shared_ptr<LuaTable>& baseTable, TreeItem* parent) {
// first get functions
auto fnTable = baseTable->getTable(".fn");
if (fnTable) {
auto& valueMap = fnTable->getValueMap();
for (auto it = valueMap.cbegin(); it != valueMap.cend(); ++it) {
const std::string& itemName = it->first;
int luaType = it->second.luaType;
if (luaType == LUA_TFUNCTION && itemName.substr(0, 2) != "__")
new LuaTreeItemLeaf(_modelStyle, fnTable, itemName, luaType, parent);
}
}
// now walk through base classes and recursively gather their methods
auto basesTable = baseTable->getTable(".bases");
if (basesTable) {
auto& valueMap = basesTable->getValueMap();
for (auto it = valueMap.cbegin(); it != valueMap.cend(); ++it) {
const std::string& itemName = it->first;
int luaType = it->second.luaType;
if (luaType == LUA_TTABLE)
recursiveGatherSwigMethods(basesTable->getTable(itemName), parent);
}
}
}
// = LuaTableTreeModel ============================================================================
LuaTableTreeModel::LuaTableTreeModel(QObject *parent /*= 0*/)
......@@ -287,7 +354,7 @@ namespace campvis {
return 3;
}
void LuaTableTreeModel::setData(LuaVmState* luaVmState) {
void LuaTableTreeModel::setData(LuaVmState* luaVmState, LuaTreeItem::ModelStyle modelStyle) {
beginResetModel();
_itemMap.clear();
......@@ -295,7 +362,7 @@ namespace campvis {
_rootItem = new LuaTreeRootItem();
if (luaVmState)
new LuaTreeItemTable(false, luaVmState->getGlobalTable(), "[Global Variables]", LUA_TTABLE, _rootItem);
new LuaTreeItemTable(modelStyle, false, luaVmState->getGlobalTable(), "[Global Variables]", LUA_TTABLE, _rootItem);
endResetModel();
}
......@@ -312,12 +379,13 @@ namespace campvis {
}
void LuaTableTreeWidget::update(LuaVmState* luaVmState) {
void LuaTableTreeWidget::update(LuaVmState* luaVmState, LuaTreeItem::ModelStyle modelStyle) {
// clear selection before setting the new data or we will encounter random crashes...
selectionModel()->clear();
// set new data
_treeModel->setData(luaVmState);
_treeModel->setData(luaVmState, modelStyle);
expandToDepth(0);
// adjust view
resizeColumnToContents(0);
......
......@@ -45,7 +45,9 @@ namespace campvis {
/// Base class for LuaTableTreeWidget items
class LuaTreeItem : public TreeItem {
public:
LuaTreeItem(const std::string& name, int type, TreeItem* parent = nullptr);
enum ModelStyle { FULL_MODEL, COMPLETER_MODEL };
LuaTreeItem(ModelStyle modelStyle, const std::string& name, int type, TreeItem* parent = nullptr);
// Virtual Destructor
virtual ~LuaTreeItem() {}
......@@ -54,8 +56,9 @@ namespace campvis {
virtual QVariant getData(int column, int role) const;
protected:
std::string _name; ///< Name of the variable
int _type; ///< Lua type of the variable
std::string _name; ///< Name of the variable
int _type; ///< Lua type of the variable
ModelStyle _modelStyle; ///< Model style for this tree item
private:
virtual QString getValue() const;
......@@ -80,7 +83,7 @@ namespace campvis {
* \param type Lua type of the variable
* \param parent Parent TreeItem
*/
LuaTreeItemLeaf(std::shared_ptr<LuaTable> parentTable, const std::string& name, int type, TreeItem* parent);
LuaTreeItemLeaf(ModelStyle modelStyle, std::shared_ptr<LuaTable> parentTable, const std::string& name, int type, TreeItem* parent);
/// Destructor
virtual ~LuaTreeItemLeaf();
......@@ -99,7 +102,7 @@ namespace campvis {
* \param type Lua type of the variable
* \param parent Parent TreeItem
*/
LuaTreeItemTable(bool isMetatable, std::shared_ptr<LuaTable> thisTable, const std::string& name, int type, TreeItem* parent);
LuaTreeItemTable(ModelStyle modelStyle, bool isMetatable, std::shared_ptr<LuaTable> thisTable, const std::string& name, int type, TreeItem* parent);
/// Destructor
virtual ~LuaTreeItemTable();
......@@ -108,6 +111,8 @@ namespace campvis {
virtual QVariant getData(int column, int role) const;
private:
void recursiveGatherSwigMethods(const std::shared_ptr<LuaTable>& baseTable, TreeItem* parent);
std::shared_ptr<LuaTable> _thisTable; ///< this item's LuaTable
bool _isMetatable; ///< Flag whether this item represents a Metatable (currently only used for printing purposes)
};
......@@ -124,7 +129,7 @@ namespace campvis {
explicit LuaTableTreeModel(QObject *parent = 0);
~LuaTableTreeModel();
void setData(LuaVmState* luaVmState);
void setData(LuaVmState* luaVmState, LuaTreeItem::ModelStyle modelStyle);
QVariant data(const QModelIndex &index, int role) const;
......@@ -181,7 +186,7 @@ namespace campvis {
* Updates the data in the tree view by the given collection of pipelines \a pipelines.
* \param pipelines
*/
void update(LuaVmState* luaVmState);
void update(LuaVmState* luaVmState, LuaTreeItem::ModelStyle modelStyle);
......
......@@ -451,7 +451,7 @@ namespace campvis {
_application->getLuaVmState()->getGlobalTable()->updateValueMap();
_scriptingConsoleWidget->_editCommand->setCompleter(new LuaCompleter(_application->getLuaVmState(), _scriptingConsoleWidget->_editCommand));
_scriptingConsoleWidget->_luaTreeWidget->update(_application->getLuaVmState());
_scriptingConsoleWidget->_luaTreeWidget->update(_application->getLuaVmState(), LuaTreeItem::FULL_MODEL);
}
#endif
}
......
......@@ -42,6 +42,8 @@ namespace campvis {
LuaTable::LuaTable(LuaVmState& luaVmState)
: _luaVmState(luaVmState)
, _luaTablePointer(nullptr)
, _tableDiscovered(false)
{}
LuaTable::~LuaTable() {
......@@ -49,6 +51,9 @@ namespace campvis {
}
std::shared_ptr<RegularLuaTable> LuaTable::getTable(const std::string& name) {
if (! _tableDiscovered)
populateValueMap();
// check whether this table has a field of given name and of type LUA_TTABLE
auto it = _valueMap.find(name);
if (it != _valueMap.end() && it->second.luaType == LUA_TTABLE) {
......@@ -64,6 +69,9 @@ namespace campvis {
}
std::shared_ptr<MetatableLuaTable> LuaTable::getMetatable(const std::string& name) {
if (! _tableDiscovered)
populateValueMap();
// check whether this table has a field of given name, which has a metatable
auto it = _valueMap.find(name);
if (it != _valueMap.end() && it->second.hasMetatable) {
......@@ -78,6 +86,9 @@ namespace campvis {
}
bool LuaTable::hasMetatable(const std::string& name) const {
if (! _tableDiscovered)
const_cast<LuaTable*>(this)->populateValueMap();
auto it = _valueMap.find(name);
if (it != _valueMap.end())
return it->second.hasMetatable;
......@@ -91,13 +102,15 @@ namespace campvis {
}
const std::map<std::string, LuaTable::ValueStruct>& LuaTable::getValueMap() const {
if (_valueMap.empty())
if (! _tableDiscovered)
const_cast<LuaTable*>(this)->populateValueMap();
return _valueMap;
}
void LuaTable::iterateOverTableAndPopulateValueMap(lua_State* L) {
_tableDiscovered = true;
void* tablePtr = hvalue(index2addr(L, -1));
if (!getParentTable() || !getParentTable()->checkIfAlreadyDiscovered(tablePtr)) {
_luaTablePointer = tablePtr;
......@@ -113,7 +126,6 @@ namespace campvis {
name = lua_tostring(L, -2);
}
else if (lua_type(L, -2) == LUA_TNUMBER) {
continue;
name = StringUtils::toString(lua_tonumber(L, -2));
keyIsNumber = true;
}
......@@ -128,9 +140,6 @@ namespace campvis {
ValueStruct vs = { luaType, nullptr, nullptr, keyIsNumber, hasMetatable };
_valueMap.insert(std::make_pair(name, vs));
if (luaType == LUA_TTABLE)
getTable(name);
}
}
else {
......
......@@ -231,7 +231,10 @@ namespace campvis {
void* _luaTablePointer;
/// value map of this lua table, mirroring the contents.
std::map<std::string, ValueStruct> _valueMap;
mutable std::map<std::string, ValueStruct> _valueMap;
/// Flag whether the elements in this table have already been discovered (i.e. whether _valueMap was populated)
mutable bool _tableDiscovered;
};
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment