You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
938 lines
27 KiB
C++
938 lines
27 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#include "EditorDefs.h"
|
|
|
|
#include "BaseLibraryManager.h"
|
|
|
|
// Editor
|
|
#include "BaseLibraryItem.h"
|
|
#include "ErrorReport.h"
|
|
#include "Undo/IUndoObject.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Undo functionality for Managers, including add library, remove library, and rename library -- Vera, Confetti
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CUndoBaseLibraryManager
|
|
: public IUndoObject
|
|
{
|
|
public:
|
|
CUndoBaseLibraryManager(CBaseLibraryManager* pMngr, const QString& description, const QString& modifiedManager = 0)
|
|
: m_pMngr(pMngr)
|
|
, m_description(description)
|
|
, m_editorObject(modifiedManager)
|
|
{
|
|
assert(m_pMngr);
|
|
SerializeTo(m_undos);
|
|
}
|
|
|
|
virtual QString GetEditorObjectName()
|
|
{
|
|
return m_editorObject;
|
|
}
|
|
|
|
protected:
|
|
virtual int GetSize() { return sizeof(CUndoBaseLibraryManager); }
|
|
virtual QString GetDescription() { return m_description; };
|
|
|
|
virtual void Undo(bool bUndo)
|
|
{
|
|
if (bUndo)
|
|
{
|
|
SerializeTo(m_redos);
|
|
}
|
|
m_pMngr->ClearAll();
|
|
UnserializeFrom(m_undos);
|
|
GetIEditor()->Notify(eNotify_OnDataBaseUpdate);
|
|
}
|
|
|
|
virtual void Redo()
|
|
{
|
|
m_pMngr->ClearAll();
|
|
UnserializeFrom(m_redos);
|
|
GetIEditor()->Notify(eNotify_OnDataBaseUpdate);
|
|
}
|
|
|
|
private:
|
|
struct LibUndoNode
|
|
: public _i_reference_target_t
|
|
{
|
|
LibUndoNode()
|
|
{
|
|
node = nullptr;
|
|
fileName = "";
|
|
}
|
|
XmlNodeRef node;
|
|
QString fileName;
|
|
};
|
|
|
|
static const char* const LIBRARY_TAG;
|
|
static const char* const LEVEL_LIBRARY_TAG;
|
|
|
|
void SerializeTo(std::vector<_smart_ptr<LibUndoNode> >& undos) // Save Library Undo
|
|
{
|
|
undos.clear();
|
|
for (int i = 0; i < m_pMngr->GetLibraryCount(); i++)
|
|
{
|
|
IDataBaseLibrary* library = m_pMngr->GetLibrary(i);
|
|
|
|
const char* tag = library->IsLevelLibrary() ? LEVEL_LIBRARY_TAG : LIBRARY_TAG;
|
|
XmlNodeRef node = GetIEditor()->GetSystem()->CreateXmlNode(tag);
|
|
QString file = library->GetFilename().isEmpty() ? library->GetFilename() : library->GetName();
|
|
library->Serialize(node, false);
|
|
if (node && !file.isEmpty())
|
|
{
|
|
_smart_ptr<LibUndoNode> undo = new LibUndoNode();
|
|
undo->fileName = file;
|
|
undo->node = node;
|
|
undos.push_back(undo);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UnserializeFrom(std::vector<_smart_ptr<LibUndoNode> >& undos) // Load Library Undo
|
|
{
|
|
for (int i = 0; i < undos.size(); i++)
|
|
{
|
|
_smart_ptr<LibUndoNode> undo = undos[i];
|
|
if (undo->node && !undo->fileName.isEmpty())
|
|
{
|
|
//AddLibrary adds a .xml to the end of the library path, this will remove the extra for compatibility
|
|
undo->fileName.replace(m_pMngr->GetLibsPath().toLower(), "");
|
|
undo->fileName.replace(".xml", "");
|
|
|
|
const bool isLevelLibrary = (strcmp(undo->node->getTag(), LEVEL_LIBRARY_TAG) == 0);
|
|
|
|
IDataBaseLibrary* library = m_pMngr->AddLibrary(undo->fileName, isLevelLibrary);
|
|
library->Serialize(undo->node, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
QString m_description;
|
|
QString m_editorObject;
|
|
CBaseLibraryManager* m_pMngr;
|
|
std::vector<_smart_ptr<LibUndoNode> > m_undos;
|
|
std::vector<_smart_ptr<LibUndoNode> > m_redos;
|
|
};
|
|
|
|
const char* const CUndoBaseLibraryManager::LIBRARY_TAG = "UndoLibrary";
|
|
const char* const CUndoBaseLibraryManager::LEVEL_LIBRARY_TAG = "UndoLevelLibrary";
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CBaseLibraryManager implementation.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CBaseLibraryManager::CBaseLibraryManager()
|
|
{
|
|
m_bUniqNameMap = false;
|
|
m_bUniqGuidMap = true;
|
|
GetIEditor()->RegisterNotifyListener(this);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CBaseLibraryManager::~CBaseLibraryManager()
|
|
{
|
|
ClearAll();
|
|
GetIEditor()->UnregisterNotifyListener(this);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::ClearAll()
|
|
{
|
|
// Delete all items from all libraries.
|
|
for (int i = 0; i < m_libs.size(); i++)
|
|
{
|
|
m_libs[i]->RemoveAllItems();
|
|
}
|
|
|
|
// if we will not copy maps locally then destructors of the elements of
|
|
// the map will operate on the already invalid map object
|
|
// see:
|
|
// CBaseLibraryManager::UnregisterItem()
|
|
// CBaseLibraryManager::DeleteItem()
|
|
// CMaterial::~CMaterial()
|
|
|
|
ItemsGUIDMap itemsGuidMap;
|
|
ItemsNameMap itemsNameMap;
|
|
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
|
|
std::swap(itemsGuidMap, m_itemsGuidMap);
|
|
std::swap(itemsNameMap, m_itemsNameMap);
|
|
|
|
m_libs.clear();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseLibrary* CBaseLibraryManager::FindLibrary(const QString& library)
|
|
{
|
|
const int index = FindLibraryIndex(library);
|
|
return index == -1 ? nullptr : m_libs[index];
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CBaseLibraryManager::FindLibraryIndex(const QString& library)
|
|
{
|
|
QString lib = library;
|
|
lib.replace('\\', '/');
|
|
for (int i = 0; i < m_libs.size(); i++)
|
|
{
|
|
QString _lib = m_libs[i]->GetFilename();
|
|
_lib.replace('\\', '/');
|
|
if (QString::compare(lib, m_libs[i]->GetName(), Qt::CaseInsensitive) == 0 || QString::compare(lib, _lib, Qt::CaseInsensitive) == 0)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItem* CBaseLibraryManager::FindItem(REFGUID guid) const
|
|
{
|
|
CBaseLibraryItem* pMtl = stl::find_in_map(m_itemsGuidMap, guid, (CBaseLibraryItem*)0);
|
|
return pMtl;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::SplitFullItemName(const QString& fullItemName, QString& libraryName, QString& itemName)
|
|
{
|
|
int p;
|
|
p = fullItemName.indexOf('.');
|
|
if (p < 0 || !QString::compare(fullItemName.mid(p + 1), "mtl", Qt::CaseInsensitive))
|
|
{
|
|
libraryName = "";
|
|
itemName = fullItemName;
|
|
return;
|
|
}
|
|
libraryName = fullItemName.mid(0, p);
|
|
itemName = fullItemName.mid(p + 1);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItem* CBaseLibraryManager::FindItemByName(const QString& fullItemName)
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
|
|
return stl::find_in_map(m_itemsNameMap, fullItemName, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItem* CBaseLibraryManager::LoadItemByName(const QString& fullItemName)
|
|
{
|
|
QString libraryName, itemName;
|
|
SplitFullItemName(fullItemName, libraryName, itemName);
|
|
|
|
if (!FindLibrary(libraryName))
|
|
{
|
|
LoadLibrary(MakeFilename(libraryName));
|
|
}
|
|
|
|
return FindItemByName(fullItemName);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItem* CBaseLibraryManager::FindItemByName(const char* fullItemName)
|
|
{
|
|
return FindItemByName(QString(fullItemName));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItem* CBaseLibraryManager::LoadItemByName(const char* fullItemName)
|
|
{
|
|
return LoadItemByName(QString(fullItemName));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItem* CBaseLibraryManager::CreateItem(IDataBaseLibrary* pLibrary)
|
|
{
|
|
assert(pLibrary);
|
|
|
|
// Add item to this library.
|
|
TSmartPtr<CBaseLibraryItem> pItem = MakeNewItem();
|
|
pLibrary->AddItem(pItem);
|
|
return pItem;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::DeleteItem(IDataBaseItem* pItem)
|
|
{
|
|
assert(pItem);
|
|
|
|
UnregisterItem((CBaseLibraryItem*)pItem);
|
|
if (pItem->GetLibrary())
|
|
{
|
|
pItem->GetLibrary()->RemoveItem(pItem);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseLibrary* CBaseLibraryManager::LoadLibrary(const QString& inFilename, [[maybe_unused]] bool bReload)
|
|
{
|
|
if (auto lib = FindLibrary(inFilename))
|
|
{
|
|
return lib;
|
|
}
|
|
|
|
TSmartPtr<CBaseLibrary> pLib = MakeNewLibrary();
|
|
if (!pLib->Load(MakeFilename(inFilename)))
|
|
{
|
|
Error(QObject::tr("Failed to Load Item Library: %1").arg(inFilename).toUtf8().data());
|
|
return nullptr;
|
|
}
|
|
|
|
m_libs.push_back(pLib);
|
|
return pLib;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CBaseLibraryManager::GetModifiedLibraryCount() const
|
|
{
|
|
int count = 0;
|
|
for (int i = 0; i < m_libs.size(); i++)
|
|
{
|
|
if (m_libs[i]->IsModified())
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseLibrary* CBaseLibraryManager::AddLibrary(const QString& library, bool bIsLevelLibrary, bool bIsLoading)
|
|
{
|
|
// Make a filename from name of library.
|
|
QString filename = library;
|
|
|
|
if (filename.indexOf(".xml") == -1) // if its already a filename, we don't do anything
|
|
{
|
|
filename.replace(' ', '_');
|
|
if (!bIsLevelLibrary)
|
|
{
|
|
filename = MakeFilename(library);
|
|
}
|
|
else
|
|
{
|
|
// if its the level library it gets saved in the level and should not be concatenated with any other file name
|
|
filename = filename + ".xml";
|
|
}
|
|
}
|
|
|
|
IDataBaseLibrary* pBaseLib = FindLibrary(library); //library name
|
|
if (!pBaseLib)
|
|
{
|
|
pBaseLib = FindLibrary(filename); //library file name
|
|
}
|
|
if (pBaseLib)
|
|
{
|
|
return pBaseLib;
|
|
}
|
|
|
|
CBaseLibrary* lib = MakeNewLibrary();
|
|
lib->SetName(library);
|
|
lib->SetLevelLibrary(bIsLevelLibrary);
|
|
lib->SetFilename(filename, !bIsLoading);
|
|
// set modified to true, so even empty particle libraries get saved
|
|
lib->SetModified(true);
|
|
|
|
m_libs.push_back(lib);
|
|
return lib;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString CBaseLibraryManager::MakeFilename(const QString& library)
|
|
{
|
|
QString filename = library;
|
|
filename.replace(' ', '_');
|
|
filename.replace(".xml", "");
|
|
|
|
// make it contain the canonical libs path:
|
|
Path::ConvertBackSlashToSlash(filename);
|
|
|
|
QString LibsPath(GetLibsPath());
|
|
Path::ConvertBackSlashToSlash(LibsPath);
|
|
|
|
if (filename.left(LibsPath.length()).compare(LibsPath, Qt::CaseInsensitive) == 0)
|
|
{
|
|
filename = filename.mid(LibsPath.length());
|
|
}
|
|
|
|
return LibsPath + filename + ".xml";
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CBaseLibraryManager::IsUniqueFilename(const QString& library)
|
|
{
|
|
QString resultPath = MakeFilename(library);
|
|
CCryFile xmlFile;
|
|
// If we can find a file for the path
|
|
return !xmlFile.Open(resultPath.toUtf8().data(), "rb");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::DeleteLibrary(const QString& library, bool forceDeleteLevel)
|
|
{
|
|
for (int i = 0; i < m_libs.size(); i++)
|
|
{
|
|
if (QString::compare(library, m_libs[i]->GetName(), Qt::CaseInsensitive) == 0)
|
|
{
|
|
CBaseLibrary* pLibrary = m_libs[i];
|
|
// Check if not level library, they cannot be deleted.
|
|
if (!pLibrary->IsLevelLibrary() || forceDeleteLevel)
|
|
{
|
|
for (int j = 0; j < pLibrary->GetItemCount(); j++)
|
|
{
|
|
UnregisterItem((CBaseLibraryItem*)pLibrary->GetItem(j));
|
|
}
|
|
pLibrary->RemoveAllItems();
|
|
|
|
if (pLibrary->IsLevelLibrary())
|
|
{
|
|
m_pLevelLibrary = nullptr;
|
|
}
|
|
m_libs.erase(m_libs.begin() + i);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseLibrary* CBaseLibraryManager::GetLibrary(int index) const
|
|
{
|
|
assert(index >= 0 && index < m_libs.size());
|
|
return m_libs[index];
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseLibrary* CBaseLibraryManager::GetLevelLibrary() const
|
|
{
|
|
IDataBaseLibrary* pLevelLib = NULL;
|
|
|
|
for (int i = 0; i < GetLibraryCount(); i++)
|
|
{
|
|
if (GetLibrary(i)->IsLevelLibrary())
|
|
{
|
|
pLevelLib = GetLibrary(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return pLevelLib;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::SaveAllLibs()
|
|
{
|
|
for (int i = 0; i < GetLibraryCount(); i++)
|
|
{
|
|
// Check if library is modified.
|
|
IDataBaseLibrary* pLibrary = GetLibrary(i);
|
|
|
|
//Level library is saved when the level is saved
|
|
if (pLibrary->IsLevelLibrary())
|
|
{
|
|
continue;
|
|
}
|
|
if (pLibrary->IsModified())
|
|
{
|
|
if (pLibrary->Save())
|
|
{
|
|
pLibrary->SetModified(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::Serialize(XmlNodeRef& node, bool bLoading)
|
|
{
|
|
static const char* const LEVEL_LIBRARY_TAG = "LevelLibrary";
|
|
|
|
QString rootNodeName = GetRootNodeName();
|
|
if (bLoading)
|
|
{
|
|
XmlNodeRef libs = node->findChild(rootNodeName.toUtf8().data());
|
|
if (libs)
|
|
{
|
|
for (int i = 0; i < libs->getChildCount(); i++)
|
|
{
|
|
// Load only library name.
|
|
XmlNodeRef libNode = libs->getChild(i);
|
|
if (strcmp(libNode->getTag(), LEVEL_LIBRARY_TAG) == 0)
|
|
{
|
|
if (!m_pLevelLibrary)
|
|
{
|
|
QString libName;
|
|
libNode->getAttr("Name", libName);
|
|
m_pLevelLibrary = static_cast<CBaseLibrary*>(AddLibrary(libName, true));
|
|
}
|
|
m_pLevelLibrary->Serialize(libNode, bLoading);
|
|
}
|
|
else
|
|
{
|
|
QString libName;
|
|
if (libNode->getAttr("Name", libName))
|
|
{
|
|
// Load this library.
|
|
if (!FindLibrary(libName))
|
|
{
|
|
LoadLibrary(MakeFilename(libName));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Save all libraries.
|
|
XmlNodeRef libs = node->newChild(rootNodeName.toUtf8().data());
|
|
for (int i = 0; i < GetLibraryCount(); i++)
|
|
{
|
|
IDataBaseLibrary* pLib = GetLibrary(i);
|
|
if (pLib->IsLevelLibrary())
|
|
{
|
|
// Level libraries are saved in in level.
|
|
XmlNodeRef libNode = libs->newChild(LEVEL_LIBRARY_TAG);
|
|
pLib->Serialize(libNode, bLoading);
|
|
}
|
|
else
|
|
{
|
|
// Save only library name.
|
|
XmlNodeRef libNode = libs->newChild("Library");
|
|
libNode->setAttr("Name", pLib->GetName().toUtf8().data());
|
|
}
|
|
}
|
|
SaveAllLibs();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString CBaseLibraryManager::MakeUniqueItemName(const QString& srcName, const QString& libName)
|
|
{
|
|
// unlikely we'll ever encounter more than 16
|
|
std::vector<string> possibleDuplicates;
|
|
possibleDuplicates.reserve(16);
|
|
|
|
// search for strings in the database that might have a similar name (ignore case)
|
|
IDataBaseItemEnumerator* pEnum = GetItemEnumerator();
|
|
for (IDataBaseItem* pItem = pEnum->GetFirst(); pItem != NULL; pItem = pEnum->GetNext())
|
|
{
|
|
//Check if the item is in the target library first.
|
|
IDataBaseLibrary* itemLibrary = pItem->GetLibrary();
|
|
QString itemLibraryName;
|
|
if (itemLibrary)
|
|
{
|
|
itemLibraryName = itemLibrary->GetName();
|
|
}
|
|
|
|
// Item is not in the library so there cannot be a naming conflict.
|
|
if (!libName.isEmpty() && !itemLibraryName.isEmpty() && itemLibraryName != libName)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const QString& name = pItem->GetName();
|
|
if (name.startsWith(srcName, Qt::CaseInsensitive))
|
|
{
|
|
possibleDuplicates.push_back(string(name.toUtf8().data()));
|
|
}
|
|
}
|
|
pEnum->Release();
|
|
|
|
if (possibleDuplicates.empty())
|
|
{
|
|
return srcName;
|
|
}
|
|
|
|
std::sort(possibleDuplicates.begin(), possibleDuplicates.end(), [](const string& strOne, const string& strTwo)
|
|
{
|
|
// I can assume size sorting since if the length is different, either one of the two strings doesn't
|
|
// closely match the string we are trying to duplicate, or it's a bigger number (X1 vs X10)
|
|
if (strOne.size() != strTwo.size())
|
|
{
|
|
return strOne.size() < strTwo.size();
|
|
}
|
|
else
|
|
{
|
|
return azstricmp(strOne.c_str(), strTwo.c_str()) < 0;
|
|
}
|
|
}
|
|
);
|
|
|
|
int num = 0;
|
|
QString returnValue = srcName;
|
|
while (num < possibleDuplicates.size() && QString::compare(possibleDuplicates[num].c_str(), returnValue, Qt::CaseInsensitive) == 0)
|
|
{
|
|
returnValue = QStringLiteral("%1%2%3").arg(srcName).arg("_").arg(num);
|
|
++num;
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::Validate()
|
|
{
|
|
IDataBaseItemEnumerator* pEnum = GetItemEnumerator();
|
|
for (IDataBaseItem* pItem = pEnum->GetFirst(); pItem != NULL; pItem = pEnum->GetNext())
|
|
{
|
|
pItem->Validate();
|
|
}
|
|
pEnum->Release();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::RegisterItem(CBaseLibraryItem* pItem, REFGUID newGuid)
|
|
{
|
|
assert(pItem);
|
|
|
|
bool bNotify = false;
|
|
|
|
if (m_bUniqGuidMap)
|
|
{
|
|
bool bNewItem = true;
|
|
REFGUID oldGuid = pItem->GetGUID();
|
|
if (!GuidUtil::IsEmpty(oldGuid))
|
|
{
|
|
bNewItem = false;
|
|
m_itemsGuidMap.erase(oldGuid);
|
|
}
|
|
if (GuidUtil::IsEmpty(newGuid))
|
|
{
|
|
return;
|
|
}
|
|
CBaseLibraryItem* pOldItem = stl::find_in_map(m_itemsGuidMap, newGuid, (CBaseLibraryItem*)0);
|
|
if (!pOldItem)
|
|
{
|
|
pItem->m_guid = newGuid;
|
|
m_itemsGuidMap[newGuid] = pItem;
|
|
pItem->m_bRegistered = true;
|
|
bNotify = true;
|
|
}
|
|
else
|
|
{
|
|
if (pOldItem != pItem)
|
|
{
|
|
ReportDuplicateItem(pItem, pOldItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_bUniqNameMap)
|
|
{
|
|
QString fullName = pItem->GetFullName();
|
|
if (!pItem->GetName().isEmpty())
|
|
{
|
|
CBaseLibraryItem* pOldItem = static_cast<CBaseLibraryItem*>(FindItemByName(fullName));
|
|
if (!pOldItem)
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
|
|
m_itemsNameMap[fullName] = pItem;
|
|
pItem->m_bRegistered = true;
|
|
bNotify = true;
|
|
}
|
|
else
|
|
{
|
|
if (pOldItem != pItem)
|
|
{
|
|
ReportDuplicateItem(pItem, pOldItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Notify listeners.
|
|
if (bNotify)
|
|
{
|
|
NotifyItemEvent(pItem, EDB_ITEM_EVENT_ADD);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::RegisterItem(CBaseLibraryItem* pItem)
|
|
{
|
|
assert(pItem);
|
|
|
|
bool bNotify = false;
|
|
|
|
if (m_bUniqGuidMap)
|
|
{
|
|
if (GuidUtil::IsEmpty(pItem->GetGUID()))
|
|
{
|
|
return;
|
|
}
|
|
CBaseLibraryItem* pOldItem = stl::find_in_map(m_itemsGuidMap, pItem->GetGUID(), (CBaseLibraryItem*)0);
|
|
if (!pOldItem)
|
|
{
|
|
m_itemsGuidMap[pItem->GetGUID()] = pItem;
|
|
pItem->m_bRegistered = true;
|
|
bNotify = true;
|
|
}
|
|
else
|
|
{
|
|
if (pOldItem != pItem)
|
|
{
|
|
ReportDuplicateItem(pItem, pOldItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_bUniqNameMap)
|
|
{
|
|
QString fullName = pItem->GetFullName();
|
|
if (!fullName.isEmpty())
|
|
{
|
|
CBaseLibraryItem* pOldItem = static_cast<CBaseLibraryItem*>(FindItemByName(fullName));
|
|
if (!pOldItem)
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
|
|
m_itemsNameMap[fullName] = pItem;
|
|
pItem->m_bRegistered = true;
|
|
bNotify = true;
|
|
}
|
|
else
|
|
{
|
|
if (pOldItem != pItem)
|
|
{
|
|
ReportDuplicateItem(pItem, pOldItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Notify listeners.
|
|
if (bNotify)
|
|
{
|
|
NotifyItemEvent(pItem, EDB_ITEM_EVENT_ADD);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::SetRegisteredFlag(CBaseLibraryItem* pItem, bool bFlag)
|
|
{
|
|
pItem->m_bRegistered = bFlag;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::ReportDuplicateItem(CBaseLibraryItem* pItem, CBaseLibraryItem* pOldItem)
|
|
{
|
|
QString sLibName;
|
|
if (pOldItem->GetLibrary())
|
|
{
|
|
sLibName = pOldItem->GetLibrary()->GetName();
|
|
}
|
|
CErrorRecord err;
|
|
err.pItem = pItem;
|
|
err.error = QStringLiteral("Item %1 with duplicate GUID to loaded item %2 ignored").arg(pItem->GetFullName(), pOldItem->GetFullName());
|
|
GetIEditor()->GetErrorReport()->ReportError(err);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::UnregisterItem(CBaseLibraryItem* pItem)
|
|
{
|
|
// Notify listeners.
|
|
NotifyItemEvent(pItem, EDB_ITEM_EVENT_DELETE);
|
|
|
|
if (!pItem)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_bUniqGuidMap)
|
|
{
|
|
m_itemsGuidMap.erase(pItem->GetGUID());
|
|
}
|
|
if (m_bUniqNameMap && !pItem->GetFullName().isEmpty())
|
|
{
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
|
|
auto findIter = m_itemsNameMap.find(pItem->GetFullName());
|
|
if (findIter != m_itemsNameMap.end())
|
|
{
|
|
_smart_ptr<CBaseLibraryItem> item = findIter->second;
|
|
m_itemsNameMap.erase(findIter);
|
|
}
|
|
}
|
|
|
|
pItem->m_bRegistered = false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QString CBaseLibraryManager::MakeFullItemName(IDataBaseLibrary* pLibrary, const QString& group, const QString& itemName)
|
|
{
|
|
assert(pLibrary);
|
|
QString name = pLibrary->GetName() + ".";
|
|
if (!group.isEmpty())
|
|
{
|
|
name += group + ".";
|
|
}
|
|
name += itemName;
|
|
return name;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::GatherUsedResources(CUsedResources& resources)
|
|
{
|
|
IDataBaseItemEnumerator* pEnum = GetItemEnumerator();
|
|
for (IDataBaseItem* pItem = pEnum->GetFirst(); pItem != NULL; pItem = pEnum->GetNext())
|
|
{
|
|
pItem->GatherUsedResources(resources);
|
|
}
|
|
pEnum->Release();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItemEnumerator* CBaseLibraryManager::GetItemEnumerator()
|
|
{
|
|
if (m_bUniqNameMap)
|
|
{
|
|
return new CDataBaseItemEnumerator<ItemsNameMap>(&m_itemsNameMap);
|
|
}
|
|
else
|
|
{
|
|
return new CDataBaseItemEnumerator<ItemsGUIDMap>(&m_itemsGuidMap);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::OnEditorNotifyEvent(EEditorNotifyEvent event)
|
|
{
|
|
switch (event)
|
|
{
|
|
case eNotify_OnBeginNewScene:
|
|
SetSelectedItem(0);
|
|
ClearAll();
|
|
break;
|
|
case eNotify_OnBeginSceneOpen:
|
|
SetSelectedItem(0);
|
|
ClearAll();
|
|
break;
|
|
case eNotify_OnCloseScene:
|
|
SetSelectedItem(0);
|
|
ClearAll();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::OnRenameItem(CBaseLibraryItem* pItem, const QString& oldName)
|
|
{
|
|
m_itemsNameMapMutex.lock();
|
|
if (!oldName.isEmpty())
|
|
{
|
|
m_itemsNameMap.erase(oldName);
|
|
}
|
|
if (!pItem->GetFullName().isEmpty())
|
|
{
|
|
m_itemsNameMap[pItem->GetFullName()] = pItem;
|
|
}
|
|
m_itemsNameMapMutex.unlock();
|
|
|
|
OnItemChanged(pItem);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::AddListener(IDataBaseManagerListener* pListener)
|
|
{
|
|
stl::push_back_unique(m_listeners, pListener);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::RemoveListener(IDataBaseManagerListener* pListener)
|
|
{
|
|
stl::find_and_erase(m_listeners, pListener);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::NotifyItemEvent(IDataBaseItem* pItem, EDataBaseItemEvent event)
|
|
{
|
|
// Notify listeners.
|
|
if (!m_listeners.empty())
|
|
{
|
|
for (int i = 0; i < m_listeners.size(); i++)
|
|
{
|
|
m_listeners[i]->OnDataBaseItemEvent(pItem, event);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::OnItemChanged(IDataBaseItem* pItem)
|
|
{
|
|
NotifyItemEvent(pItem, EDB_ITEM_EVENT_CHANGED);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::OnUpdateProperties(IDataBaseItem* pItem, bool bRefresh)
|
|
{
|
|
NotifyItemEvent(pItem, bRefresh ? EDB_ITEM_EVENT_UPDATE_PROPERTIES
|
|
: EDB_ITEM_EVENT_UPDATE_PROPERTIES_NO_EDITOR_REFRESH);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CBaseLibraryManager::SetSelectedItem(IDataBaseItem* pItem)
|
|
{
|
|
if (m_pSelectedItem == pItem)
|
|
{
|
|
return;
|
|
}
|
|
m_pSelectedItem = (CBaseLibraryItem*)pItem;
|
|
NotifyItemEvent(m_pSelectedItem, EDB_ITEM_EVENT_SELECTED);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItem* CBaseLibraryManager::GetSelectedItem() const
|
|
{
|
|
return m_pSelectedItem;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IDataBaseItem* CBaseLibraryManager::GetSelectedParentItem() const
|
|
{
|
|
return m_pSelectedParent;
|
|
}
|
|
|
|
void CBaseLibraryManager::ChangeLibraryOrder(IDataBaseLibrary* lib, unsigned int newLocation)
|
|
{
|
|
if (!lib || newLocation >= m_libs.size() || lib == m_libs[newLocation])
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < m_libs.size(); i++)
|
|
{
|
|
if (lib == m_libs[i])
|
|
{
|
|
_smart_ptr<CBaseLibrary> curLib = m_libs[i];
|
|
m_libs.erase(m_libs.begin() + i);
|
|
m_libs.insert(m_libs.begin() + newLocation, curLib);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CBaseLibraryManager::SetLibraryName(CBaseLibrary* lib, const QString& name)
|
|
{
|
|
// SetFilename will validate if the name is duplicate with exist libraries.
|
|
if (lib->SetFilename(MakeFilename(name)))
|
|
{
|
|
lib->SetName(name);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|