2010-05-06 00:08:41 +00:00
|
|
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as
|
|
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
2012-05-23 02:13:58 +00:00
|
|
|
#include "nel/gui/reflect.h"
|
2010-05-06 00:08:41 +00:00
|
|
|
|
|
|
|
// Yoyo: Act like a singleton, else registerClass may crash.
|
|
|
|
CReflectSystem::TClassMap *CReflectSystem::_ClassMap= NULL;
|
|
|
|
|
|
|
|
// hack to register the root class at startup
|
|
|
|
static const struct CRootReflectableClassRegister
|
|
|
|
{
|
|
|
|
CRootReflectableClassRegister()
|
|
|
|
{
|
|
|
|
TReflectedProperties props;
|
|
|
|
CReflectSystem::registerClass("CReflectable", "", props);
|
|
|
|
}
|
|
|
|
} _RootReflectableClassRegisterInstance;
|
|
|
|
|
|
|
|
|
|
|
|
//===================================================================================
|
|
|
|
// release memory
|
|
|
|
void CReflectSystem::release()
|
|
|
|
{
|
|
|
|
delete _ClassMap;
|
|
|
|
_ClassMap = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===================================================================================
|
|
|
|
void CReflectSystem::registerClass(const std::string &className, const std::string &parentName, const TReflectedProperties properties)
|
|
|
|
{
|
|
|
|
if(!_ClassMap) _ClassMap= new TClassMap;
|
|
|
|
|
|
|
|
TClassMap::const_iterator it = _ClassMap->find(className);
|
|
|
|
if (it != _ClassMap->end())
|
|
|
|
{
|
|
|
|
nlerror("CReflectSystem::registerClass : Class registered twice : %s!", className.c_str());
|
|
|
|
}
|
|
|
|
CClassInfo &ci = (*_ClassMap)[className];
|
|
|
|
ci.Properties = properties;
|
|
|
|
ci.ClassName = className;
|
|
|
|
for(uint k = 0; k < ci.Properties.size(); ++k)
|
|
|
|
{
|
|
|
|
ci.Properties[k].ParentClass = &ci;
|
|
|
|
}
|
|
|
|
if (parentName.empty())
|
|
|
|
{
|
|
|
|
ci.ParentClass = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
it = _ClassMap->find(parentName);
|
|
|
|
if (it == _ClassMap->end())
|
|
|
|
{
|
|
|
|
nlerror("CReflectSystem::registerClass : Parent class %s not found", parentName.c_str());
|
|
|
|
}
|
|
|
|
ci.ParentClass = &(it->second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===================================================================================
|
|
|
|
const CReflectedProperty *CReflectSystem::getProperty(const std::string &className, const std::string &propertyName, bool dspWarning)
|
|
|
|
{
|
|
|
|
if(!_ClassMap) _ClassMap= new TClassMap;
|
|
|
|
|
|
|
|
TClassMap::const_iterator it = _ClassMap->find(className);
|
|
|
|
if (it == _ClassMap->end())
|
|
|
|
{
|
|
|
|
nlwarning("CReflectSystem::getProperty : Unkwown class : %s", className.c_str());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
const CClassInfo *ci = &it->second;
|
|
|
|
while (ci)
|
|
|
|
{
|
|
|
|
// Linear search should suffice for now
|
|
|
|
for(uint k = 0; k < ci->Properties.size(); ++k)
|
|
|
|
{
|
|
|
|
if (ci->Properties[k].Name == propertyName)
|
|
|
|
{
|
|
|
|
return &(ci->Properties[k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// search in parent
|
|
|
|
ci = ci->ParentClass;
|
|
|
|
}
|
|
|
|
//\ TODO nico : possible optimization : instead of going up in the parents when
|
|
|
|
// searching for a property, it would be simpler to concatenate properties
|
|
|
|
// from parent class at registration.
|
|
|
|
// All that would be left at the end would be a hash_map of properties ...
|
|
|
|
|
|
|
|
if(dspWarning)
|
|
|
|
nlwarning("CReflectSystem::getProperty : %s is not a property of class : %s", propertyName.c_str(), className.c_str());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===================================================================================
|
|
|
|
const CClassInfo *CReflectable::getClassInfo()
|
|
|
|
{
|
|
|
|
if (!CReflectSystem::getClassMap()) return NULL;
|
|
|
|
// TODO nico : a possible optimization would be to use the address of the static function
|
|
|
|
// 'getReflectedProperties' as a key into the CClassInfo map. This pointer uniquely identify
|
|
|
|
// classes that export properties
|
|
|
|
CReflectSystem::TClassMap::const_iterator it = CReflectSystem::getClassMap()->find(this->getReflectedClassName());
|
|
|
|
if (it == CReflectSystem::getClassMap()->end())
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return &(it->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===================================================================================
|
|
|
|
const CReflectedProperty *CReflectable::getReflectedProperty(const std::string &propertyName, bool dspWarning) const
|
|
|
|
{
|
|
|
|
return CReflectSystem::getProperty(this->getReflectedClassName(), propertyName, dspWarning);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-23 02:13:58 +00:00
|
|
|
#include "nel/gui/lua_manager.h"
|
2012-05-23 00:41:43 +00:00
|
|
|
|
|
|
|
CReflectableRefPtrTarget::~CReflectableRefPtrTarget()
|
|
|
|
{
|
|
|
|
CLuaState *lua= CLuaManager::getInstance().getLuaState();
|
|
|
|
if(!lua)
|
|
|
|
return;
|
|
|
|
CLuaStackChecker lsc(lua);
|
|
|
|
// remove from the lua registry if i'm in
|
|
|
|
lua->pushLightUserData((void *) this);
|
|
|
|
lua->getTable(LUA_REGISTRYINDEX);
|
|
|
|
if (!lua->isNil(-1))
|
|
|
|
{
|
|
|
|
lua->pop();
|
|
|
|
lua->pushLightUserData((void *) this);
|
|
|
|
lua->pushNil();
|
|
|
|
lua->setTable(LUA_REGISTRYINDEX);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lua->pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data structure pushed in lua (a userdata) to access CReflectableRefPtrTarget derived objects
|
|
|
|
* These includes element of the GUI.
|
|
|
|
* if holds a pointer to the reflectable object, and
|
|
|
|
* a cache to its CClassInfo for fast access to exported properties
|
|
|
|
* \see reflect.h
|
|
|
|
*/
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
inline const CClassInfo &CReflectableLuaRef::getClassInfo() const
|
|
|
|
{
|
|
|
|
nlassert(Ptr); // class info should not be accessed for a null ptr
|
|
|
|
if (_ClassInfo) return *_ClassInfo;
|
|
|
|
_ClassInfo = Ptr->getClassInfo();
|
|
|
|
return *_ClassInfo;
|
|
|
|
}
|
2010-05-06 00:08:41 +00:00
|
|
|
|
2012-05-23 00:41:43 +00:00
|
|
|
const CReflectedProperty *CReflectableLuaRef::getProp(const char *luaStringPtr) const
|
|
|
|
{
|
|
|
|
const CClassInfo &ci = getClassInfo();
|
|
|
|
CClassInfo::TLuaStrToPropMap::const_iterator it = ci.LuaStrToProp.find(luaStringPtr);
|
|
|
|
if (it != ci.LuaStrToProp.end())
|
|
|
|
{
|
|
|
|
return it->second.Prop;
|
|
|
|
}
|
|
|
|
// slowly retrieve property, and store in cache
|
|
|
|
// NB nico : this could also be done at startup...
|
|
|
|
const CReflectedProperty *prop = CReflectSystem::getProperty(ci.ClassName, luaStringPtr, false);
|
|
|
|
if (!prop) return NULL;
|
|
|
|
CLuaIndexedProperty lip;
|
|
|
|
lip.Id = CLuaString(luaStringPtr); // keep a ref on the lua string to ensure that its pointer always remains valid
|
|
|
|
lip.Prop = prop;
|
|
|
|
ci.LuaStrToProp[luaStringPtr] = lip;
|
|
|
|
return prop;
|
|
|
|
}
|