/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "StdAfx.h" #include "BaseLibraryManager.h" #include "BaseLibrary.h" #include "BaseLibraryItem.h" #include "ErrorReport.h" #include "Undo/IUndoObject.h" #include "Undo/Undo.h" #include /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 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 >& 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 undo = new LibUndoNode(); undo->fileName = file; undo->node = node; undos.push_back(undo); } } } void UnserializeFrom(std::vector<_smart_ptr >& undos) // Load Library Undo { for (int i = 0; i < undos.size(); i++) { _smart_ptr 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 > m_undos; std::vector<_smart_ptr > 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 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 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 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, bool bReload) { if (auto lib = FindLibrary(inFilename)) { return lib; } TSmartPtr 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(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 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(FindItemByName(fullName)); if (!pOldItem) { AZStd::lock_guard 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(FindItemByName(fullName)); if (!pOldItem) { AZStd::lock_guard 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 lock(m_itemsNameMapMutex); auto findIter = m_itemsNameMap.find(pItem->GetFullName()); if (findIter != m_itemsNameMap.end()) { _smart_ptr 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(&m_itemsNameMap); } else { return new CDataBaseItemEnumerator(&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_OnMissionChange: SetSelectedItem(0); 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 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; }