Added ability to create brand new SCAN/STRG assets. Added ability to update old projects.
This commit is contained in:
parent
1e997dac46
commit
56843e214d
|
@ -1 +1 @@
|
||||||
Subproject commit c98f4b3dcef68724627af91ac4103de7f28d2a2b
|
Subproject commit 5c3bfbe57f6ef8a300933afdc053a445cabd5c7c
|
|
@ -626,7 +626,7 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||||
Name = rRes.ResourceID.ToString();
|
Name = rRes.ResourceID.ToString();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CResourceEntry *pEntry = mpStore->RegisterResource(rRes.ResourceID, CResTypeInfo::TypeForCookedExtension(mGame, rRes.ResourceType)->Type(), Directory, Name);
|
CResourceEntry *pEntry = mpStore->CreateNewResource(rRes.ResourceID, CResTypeInfo::TypeForCookedExtension(mGame, rRes.ResourceType)->Type(), Directory, Name);
|
||||||
|
|
||||||
// Set flags
|
// Set flags
|
||||||
pEntry->SetFlag(EResEntryFlag::IsBaseGameResource);
|
pEntry->SetFlag(EResEntryFlag::IsBaseGameResource);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "CGameProject.h"
|
#include "CGameProject.h"
|
||||||
|
#include "CResourceIterator.h"
|
||||||
#include "IUIRelay.h"
|
#include "IUIRelay.h"
|
||||||
#include "Core/Resource/Script/CGameTemplate.h"
|
#include "Core/Resource/Script/CGameTemplate.h"
|
||||||
#include <Common/Serialization/XML.h>
|
#include <Common/Serialization/XML.h>
|
||||||
|
@ -233,7 +234,11 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||||
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj);
|
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj);
|
||||||
LoadSuccess = pProj->mpResourceStore->LoadDatabaseCache();
|
LoadSuccess = pProj->mpResourceStore->LoadDatabaseCache();
|
||||||
|
|
||||||
// Validate resource database
|
// Removed database validation step. We used to do this on project load to make sure all data was correct, but this takes a long
|
||||||
|
// time and significantly extends how long it takes to open a project. In actual practice, this isn't needed most of the time, and
|
||||||
|
// in the odd case that it is needed, there is a button in the resource browser to rebuild the database. So in the interest of
|
||||||
|
// making project startup faster, we no longer validate the database.
|
||||||
|
#if 0
|
||||||
if (LoadSuccess)
|
if (LoadSuccess)
|
||||||
{
|
{
|
||||||
pProgress->Report("Validating resource database");
|
pProgress->Report("Validating resource database");
|
||||||
|
@ -253,6 +258,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||||
LoadSuccess = false;
|
LoadSuccess = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LoadSuccess)
|
if (!LoadSuccess)
|
||||||
|
@ -263,6 +269,34 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||||
|
|
||||||
pProj->mProjFileLock.Lock(ProjPath);
|
pProj->mProjFileLock.Lock(ProjPath);
|
||||||
pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
|
pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
|
||||||
|
|
||||||
|
// Perform update
|
||||||
|
if (Reader.FileVersion() < (uint16) EProjectVersion::Current)
|
||||||
|
{
|
||||||
|
pProgress->Report("Updating project");
|
||||||
|
|
||||||
|
CResourceStore* pOldStore = gpResourceStore;
|
||||||
|
gpResourceStore = pProj->mpResourceStore.get();
|
||||||
|
|
||||||
|
for (CResourceIterator It; It; ++It)
|
||||||
|
{
|
||||||
|
if (It->TypeInfo()->CanBeSerialized() && !It->HasRawVersion())
|
||||||
|
{
|
||||||
|
It->Save(true, false);
|
||||||
|
|
||||||
|
// Touch the cooked file to update its last modified time.
|
||||||
|
// This prevents PWE from erroneously thinking the cooked file is outdated
|
||||||
|
// (due to the raw file we just made having a more recent last modified time)
|
||||||
|
FileUtil::UpdateLastModifiedTime( It->CookedAssetPath() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pProj->mpResourceStore->ConditionalSaveStore();
|
||||||
|
pProj->Save();
|
||||||
|
|
||||||
|
gpResourceStore = pOldStore;
|
||||||
|
}
|
||||||
|
|
||||||
pProj->mpAudioManager->LoadAssets();
|
pProj->mpAudioManager->LoadAssets();
|
||||||
pProj->mpTweakManager->LoadTweaks();
|
pProj->mpTweakManager->LoadTweaks();
|
||||||
return pProj;
|
return pProj;
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace nod { class DiscWii; }
|
||||||
enum class EProjectVersion
|
enum class EProjectVersion
|
||||||
{
|
{
|
||||||
Initial,
|
Initial,
|
||||||
|
RawStrings,
|
||||||
// Add new versions before this line
|
// Add new versions before this line
|
||||||
|
|
||||||
Max,
|
Max,
|
||||||
|
|
|
@ -59,6 +59,16 @@ void CPackage::UpdateDependencyCache() const
|
||||||
mCacheDirty = false;
|
mCacheDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPackage::MarkDirty()
|
||||||
|
{
|
||||||
|
if (!mNeedsRecook)
|
||||||
|
{
|
||||||
|
mNeedsRecook = true;
|
||||||
|
Save();
|
||||||
|
UpdateDependencyCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CPackage::Cook(IProgressNotifier *pProgress)
|
void CPackage::Cook(IProgressNotifier *pProgress)
|
||||||
{
|
{
|
||||||
SCOPED_TIMER(CookPackage);
|
SCOPED_TIMER(CookPackage);
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
void Serialize(IArchive& rArc);
|
void Serialize(IArchive& rArc);
|
||||||
void AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType);
|
void AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType);
|
||||||
void UpdateDependencyCache() const;
|
void UpdateDependencyCache() const;
|
||||||
|
void MarkDirty();
|
||||||
|
|
||||||
void Cook(IProgressNotifier *pProgress);
|
void Cook(IProgressNotifier *pProgress);
|
||||||
void CompareOriginalAssetList(const std::list<CAssetID>& rkNewList);
|
void CompareOriginalAssetList(const std::list<CAssetID>& rkNewList);
|
||||||
|
@ -77,7 +78,6 @@ public:
|
||||||
inline bool NeedsRecook() const { return mNeedsRecook; }
|
inline bool NeedsRecook() const { return mNeedsRecook; }
|
||||||
|
|
||||||
inline void SetPakName(TString NewName) { mPakName = NewName; }
|
inline void SetPakName(TString NewName) { mPakName = NewName; }
|
||||||
inline void MarkDirty() { mNeedsRecook = true; Save(); UpdateDependencyCache(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CPACKAGE
|
#endif // CPACKAGE
|
||||||
|
|
|
@ -40,6 +40,15 @@ CResourceEntry* CResourceEntry::CreateNewResource(CResourceStore *pStore, const
|
||||||
pEntry->mpDirectory->AddChild("", pEntry);
|
pEntry->mpDirectory->AddChild("", pEntry);
|
||||||
|
|
||||||
pEntry->mMetadataDirty = true;
|
pEntry->mMetadataDirty = true;
|
||||||
|
|
||||||
|
// Check if the data exists or not. If so, then we are creating an entry for an existing resource (game exporter).
|
||||||
|
// If not, we want to initiate the new resource data and save it as soon as possible.
|
||||||
|
if (!pEntry->HasCookedVersion())
|
||||||
|
{
|
||||||
|
pEntry->mpResource = CResourceFactory::SpawnResource(pEntry);
|
||||||
|
pEntry->mpResource->InitializeNewResource();
|
||||||
|
}
|
||||||
|
|
||||||
return pEntry;
|
return pEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +270,7 @@ bool CResourceEntry::NeedsRecook() const
|
||||||
return (FileUtil::LastModifiedTime(CookedAssetPath()) < FileUtil::LastModifiedTime(RawAssetPath()));
|
return (FileUtil::LastModifiedTime(CookedAssetPath()) < FileUtil::LastModifiedTime(RawAssetPath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CResourceEntry::Save(bool SkipCacheSave /*= false*/)
|
bool CResourceEntry::Save(bool SkipCacheSave /*= false*/, bool FlagForRecook /*= true*/)
|
||||||
{
|
{
|
||||||
// SkipCacheSave argument tells us not to save the resource cache file. This is generally not advised because we don't
|
// SkipCacheSave argument tells us not to save the resource cache file. This is generally not advised because we don't
|
||||||
// want the actual resource data to desync from the cache data. However, there are occasions where we save multiple
|
// want the actual resource data to desync from the cache data. However, there are occasions where we save multiple
|
||||||
|
@ -270,7 +279,6 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/)
|
||||||
//
|
//
|
||||||
// For now, always save the resource when this function is called even if there's been no changes made to it in memory.
|
// For now, always save the resource when this function is called even if there's been no changes made to it in memory.
|
||||||
// In the future this might not be desired behavior 100% of the time.
|
// In the future this might not be desired behavior 100% of the time.
|
||||||
// We also might want this function to trigger a cook for certain resource types eventually.
|
|
||||||
bool ShouldCollectGarbage = false;
|
bool ShouldCollectGarbage = false;
|
||||||
|
|
||||||
// Save raw resource
|
// Save raw resource
|
||||||
|
@ -298,8 +306,11 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FlagForRecook)
|
||||||
|
{
|
||||||
SetFlag(EResEntryFlag::NeedsRecook);
|
SetFlag(EResEntryFlag::NeedsRecook);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This resource type doesn't have a raw format; save cooked instead
|
// This resource type doesn't have a raw format; save cooked instead
|
||||||
else
|
else
|
||||||
|
@ -324,13 +335,16 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flag dirty any packages that contain this resource.
|
// Flag dirty any packages that contain this resource.
|
||||||
|
if (FlagForRecook)
|
||||||
|
{
|
||||||
for (uint32 iPkg = 0; iPkg < mpStore->Project()->NumPackages(); iPkg++)
|
for (uint32 iPkg = 0; iPkg < mpStore->Project()->NumPackages(); iPkg++)
|
||||||
{
|
{
|
||||||
CPackage *pPkg = mpStore->Project()->PackageByIndex(iPkg);
|
CPackage *pPkg = mpStore->Project()->PackageByIndex(iPkg);
|
||||||
|
|
||||||
if (pPkg->ContainsAsset(ID()))
|
if (!pPkg->NeedsRecook() && pPkg->ContainsAsset(ID()))
|
||||||
pPkg->MarkDirty();
|
pPkg->MarkDirty();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ShouldCollectGarbage)
|
if (ShouldCollectGarbage)
|
||||||
mpStore->DestroyUnreferencedResources();
|
mpStore->DestroyUnreferencedResources();
|
||||||
|
|
|
@ -67,7 +67,7 @@ public:
|
||||||
bool IsInDirectory(CVirtualDirectory *pDir) const;
|
bool IsInDirectory(CVirtualDirectory *pDir) const;
|
||||||
uint64 Size() const;
|
uint64 Size() const;
|
||||||
bool NeedsRecook() const;
|
bool NeedsRecook() const;
|
||||||
bool Save(bool SkipCacheSave = false);
|
bool Save(bool SkipCacheSave = false, bool FlagForRecook = true);
|
||||||
bool Cook();
|
bool Cook();
|
||||||
CResource* Load();
|
CResource* Load();
|
||||||
CResource* LoadCooked(IInputStream& rInput);
|
CResource* LoadCooked(IInputStream& rInput);
|
||||||
|
@ -87,7 +87,7 @@ public:
|
||||||
inline void SetFlagEnabled(EResEntryFlag Flag, bool Enabled) { Enabled ? SetFlag(Flag) : ClearFlag(Flag); }
|
inline void SetFlagEnabled(EResEntryFlag Flag, bool Enabled) { Enabled ? SetFlag(Flag) : ClearFlag(Flag); }
|
||||||
|
|
||||||
inline void SetDirty() { SetFlag(EResEntryFlag::NeedsRecook); }
|
inline void SetDirty() { SetFlag(EResEntryFlag::NeedsRecook); }
|
||||||
inline void SetHidden(bool Hidden) { Hidden ? SetFlag(EResEntryFlag::Hidden) : ClearFlag(EResEntryFlag::Hidden); }
|
inline void SetHidden(bool Hidden) { SetFlagEnabled(EResEntryFlag::Hidden, Hidden); }
|
||||||
inline bool HasFlag(EResEntryFlag Flag) const { return mFlags.HasFlag(Flag); }
|
inline bool HasFlag(EResEntryFlag Flag) const { return mFlags.HasFlag(Flag); }
|
||||||
inline bool IsHidden() const { return HasFlag(EResEntryFlag::Hidden); }
|
inline bool IsHidden() const { return HasFlag(EResEntryFlag::Hidden); }
|
||||||
|
|
||||||
|
|
|
@ -284,7 +284,14 @@ void CResourceStore::ClearDatabase()
|
||||||
{
|
{
|
||||||
// THIS OPERATION REQUIRES THAT ALL RESOURCES ARE UNREFERENCED
|
// THIS OPERATION REQUIRES THAT ALL RESOURCES ARE UNREFERENCED
|
||||||
DestroyUnreferencedResources();
|
DestroyUnreferencedResources();
|
||||||
ASSERT(mLoadedResources.empty());
|
|
||||||
|
if (!mLoadedResources.empty())
|
||||||
|
{
|
||||||
|
debugf("ERROR: Resources still loaded:");
|
||||||
|
for (auto Iter = mLoadedResources.begin(); Iter != mLoadedResources.end(); Iter++)
|
||||||
|
debugf("\t[%s] %s", *Iter->first.ToString(), *Iter->second->CookedAssetPath(true));
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Clear out existing resource entries and directories
|
// Clear out existing resource entries and directories
|
||||||
for (auto Iter = mResourceEntries.begin(); Iter != mResourceEntries.end(); Iter++)
|
for (auto Iter = mResourceEntries.begin(); Iter != mResourceEntries.end(); Iter++)
|
||||||
|
@ -384,7 +391,7 @@ bool CResourceStore::IsResourceRegistered(const CAssetID& rkID) const
|
||||||
return FindEntry(rkID) != nullptr;
|
return FindEntry(rkID) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CResourceEntry* CResourceStore::RegisterResource(const CAssetID& rkID, EResourceType Type, const TString& rkDir, const TString& rkName)
|
CResourceEntry* CResourceStore::CreateNewResource(const CAssetID& rkID, EResourceType Type, const TString& rkDir, const TString& rkName)
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = FindEntry(rkID);
|
CResourceEntry *pEntry = FindEntry(rkID);
|
||||||
|
|
||||||
|
@ -398,6 +405,12 @@ CResourceEntry* CResourceStore::RegisterResource(const CAssetID& rkID, EResource
|
||||||
{
|
{
|
||||||
pEntry = CResourceEntry::CreateNewResource(this, rkID, rkDir, rkName, Type);
|
pEntry = CResourceEntry::CreateNewResource(this, rkID, rkDir, rkName, Type);
|
||||||
mResourceEntries[rkID] = pEntry;
|
mResourceEntries[rkID] = pEntry;
|
||||||
|
mDatabaseCacheDirty = true;
|
||||||
|
|
||||||
|
if (pEntry->IsLoaded())
|
||||||
|
{
|
||||||
|
TrackLoadedResource(pEntry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
TString DefaultResourceDirPath() const;
|
TString DefaultResourceDirPath() const;
|
||||||
|
|
||||||
bool IsResourceRegistered(const CAssetID& rkID) const;
|
bool IsResourceRegistered(const CAssetID& rkID) const;
|
||||||
CResourceEntry* RegisterResource(const CAssetID& rkID, EResourceType Type, const TString& rkDir, const TString& rkName);
|
CResourceEntry* CreateNewResource(const CAssetID& rkID, EResourceType Type, const TString& rkDir, const TString& rkName);
|
||||||
CResourceEntry* FindEntry(const CAssetID& rkID) const;
|
CResourceEntry* FindEntry(const CAssetID& rkID) const;
|
||||||
CResourceEntry* FindEntry(const TString& rkPath) const;
|
CResourceEntry* FindEntry(const TString& rkPath) const;
|
||||||
bool AreAllEntriesValid() const;
|
bool AreAllEntriesValid() const;
|
||||||
|
|
|
@ -92,7 +92,7 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
|
||||||
{
|
{
|
||||||
CAssetID::skInvalidID32.Write(rSCLY);
|
CAssetID::skInvalidID32.Write(rSCLY);
|
||||||
rSCLY.WriteLong(0);
|
rSCLY.WriteLong(0);
|
||||||
rSCLY.WriteLong(0);
|
rSCLY.WriteLong(mGame >= EGame::EchoesDemo ? 0 : 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ CResTypeInfo::CResTypeInfo(EResourceType Type, const TString& rkTypeName, const
|
||||||
, mRetroExtension(rkRetroExtension)
|
, mRetroExtension(rkRetroExtension)
|
||||||
, mCanBeSerialized(false)
|
, mCanBeSerialized(false)
|
||||||
, mCanHaveDependencies(true)
|
, mCanHaveDependencies(true)
|
||||||
|
, mCanBeCreated(false)
|
||||||
{
|
{
|
||||||
#if !PUBLIC_RELEASE
|
#if !PUBLIC_RELEASE
|
||||||
ASSERT(smTypeMap.find(Type) == smTypeMap.end());
|
ASSERT(smTypeMap.find(Type) == smTypeMap.end());
|
||||||
|
@ -332,6 +333,7 @@ void CResTypeInfo::CResTypeInfoFactory::InitTypes()
|
||||||
{
|
{
|
||||||
CResTypeInfo *pType = new CResTypeInfo(EResourceType::Scan, "Scan", "scan");
|
CResTypeInfo *pType = new CResTypeInfo(EResourceType::Scan, "Scan", "scan");
|
||||||
AddExtension(pType, "SCAN", EGame::PrimeDemo, EGame::Corruption);
|
AddExtension(pType, "SCAN", EGame::PrimeDemo, EGame::Corruption);
|
||||||
|
pType->mCanBeCreated = true;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
CResTypeInfo *pType = new CResTypeInfo(EResourceType::Skeleton, "Skeleton", "cin");
|
CResTypeInfo *pType = new CResTypeInfo(EResourceType::Skeleton, "Skeleton", "cin");
|
||||||
|
@ -382,6 +384,7 @@ void CResTypeInfo::CResTypeInfoFactory::InitTypes()
|
||||||
CResTypeInfo *pType = new CResTypeInfo(EResourceType::StringTable, "String Table", "strg");
|
CResTypeInfo *pType = new CResTypeInfo(EResourceType::StringTable, "String Table", "strg");
|
||||||
AddExtension(pType, "STRG", EGame::PrimeDemo, EGame::DKCReturns);
|
AddExtension(pType, "STRG", EGame::PrimeDemo, EGame::DKCReturns);
|
||||||
pType->mCanBeSerialized = true;
|
pType->mCanBeSerialized = true;
|
||||||
|
pType->mCanBeCreated = true;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
CResTypeInfo *pType = new CResTypeInfo(EResourceType::Texture, "Texture", "txtr");
|
CResTypeInfo *pType = new CResTypeInfo(EResourceType::Texture, "Texture", "txtr");
|
||||||
|
|
|
@ -23,6 +23,7 @@ class CResTypeInfo
|
||||||
TString mRetroExtension; // File extension in Retro's directory tree. We don't use it directly but it is needed for generating asset ID hashes
|
TString mRetroExtension; // File extension in Retro's directory tree. We don't use it directly but it is needed for generating asset ID hashes
|
||||||
bool mCanBeSerialized;
|
bool mCanBeSerialized;
|
||||||
bool mCanHaveDependencies;
|
bool mCanHaveDependencies;
|
||||||
|
bool mCanBeCreated;
|
||||||
|
|
||||||
static std::unordered_map<EResourceType, CResTypeInfo*> smTypeMap;
|
static std::unordered_map<EResourceType, CResTypeInfo*> smTypeMap;
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ public:
|
||||||
inline TString TypeName() const { return mTypeName; }
|
inline TString TypeName() const { return mTypeName; }
|
||||||
inline bool CanBeSerialized() const { return mCanBeSerialized; }
|
inline bool CanBeSerialized() const { return mCanBeSerialized; }
|
||||||
inline bool CanHaveDependencies() const { return mCanHaveDependencies; }
|
inline bool CanHaveDependencies() const { return mCanHaveDependencies; }
|
||||||
|
inline bool CanBeCreated() const { return mCanBeCreated; }
|
||||||
|
|
||||||
// Static
|
// Static
|
||||||
static void GetAllTypesInGame(EGame Game, std::list<CResTypeInfo*>& rOut);
|
static void GetAllTypesInGame(EGame Game, std::list<CResTypeInfo*>& rOut);
|
||||||
|
|
|
@ -43,6 +43,7 @@ public:
|
||||||
virtual ~CResource() {}
|
virtual ~CResource() {}
|
||||||
virtual CDependencyTree* BuildDependencyTree() const { return new CDependencyTree(); }
|
virtual CDependencyTree* BuildDependencyTree() const { return new CDependencyTree(); }
|
||||||
virtual void Serialize(IArchive& /*rArc*/) {}
|
virtual void Serialize(IArchive& /*rArc*/) {}
|
||||||
|
virtual void InitializeNewResource() {}
|
||||||
|
|
||||||
inline CResourceEntry* Entry() const { return mpEntry; }
|
inline CResourceEntry* Entry() const { return mpEntry; }
|
||||||
inline CResTypeInfo* TypeInfo() const { return mpEntry->TypeInfo(); }
|
inline CResTypeInfo* TypeInfo() const { return mpEntry->TypeInfo(); }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "CStringTable.h"
|
#include "CStringTable.h"
|
||||||
|
#include "Core/GameProject/CGameProject.h"
|
||||||
#include <Common/Math/MathUtil.h>
|
#include <Common/Math/MathUtil.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
@ -8,27 +9,27 @@
|
||||||
* This is also the order that languages appear in game STRG assets.
|
* This is also the order that languages appear in game STRG assets.
|
||||||
*/
|
*/
|
||||||
// Supported languages in the original NTSC release of Metroid Prime
|
// Supported languages in the original NTSC release of Metroid Prime
|
||||||
const ELanguage gkSupportedLanguagesMP1[] =
|
const std::vector<ELanguage> gkSupportedLanguagesMP1 =
|
||||||
{
|
{
|
||||||
ELanguage::English
|
ELanguage::English
|
||||||
};
|
};
|
||||||
|
|
||||||
// Supported languages in the PAL version of Metroid Prime, and also Metroid Prime 2
|
// Supported languages in the PAL version of Metroid Prime, and also Metroid Prime 2
|
||||||
const ELanguage gkSupportedLanguagesMP1PAL[] =
|
const std::vector<ELanguage> gkSupportedLanguagesMP1PAL =
|
||||||
{
|
{
|
||||||
ELanguage::English, ELanguage::French, ELanguage::German,
|
ELanguage::English, ELanguage::French, ELanguage::German,
|
||||||
ELanguage::Spanish, ELanguage::Italian, ELanguage::Japanese
|
ELanguage::Spanish, ELanguage::Italian, ELanguage::Japanese
|
||||||
};
|
};
|
||||||
|
|
||||||
// Supported languages in Metroid Prime 3
|
// Supported languages in Metroid Prime 3
|
||||||
const ELanguage gkSupportedLanguagesMP3[] =
|
const std::vector<ELanguage> gkSupportedLanguagesMP3 =
|
||||||
{
|
{
|
||||||
ELanguage::English, ELanguage::Japanese, ELanguage::German,
|
ELanguage::English, ELanguage::Japanese, ELanguage::German,
|
||||||
ELanguage::French, ELanguage::Spanish, ELanguage::Italian
|
ELanguage::French, ELanguage::Spanish, ELanguage::Italian
|
||||||
};
|
};
|
||||||
|
|
||||||
// Supported languages in DKCR
|
// Supported languages in DKCR
|
||||||
const ELanguage gkSupportedLanguagesDKCR[] =
|
const std::vector<ELanguage> gkSupportedLanguagesDKCR =
|
||||||
{
|
{
|
||||||
ELanguage::English, ELanguage::Japanese, ELanguage::German,
|
ELanguage::English, ELanguage::Japanese, ELanguage::German,
|
||||||
ELanguage::French, ELanguage::Spanish, ELanguage::Italian,
|
ELanguage::French, ELanguage::Spanish, ELanguage::Italian,
|
||||||
|
@ -36,6 +37,32 @@ const ELanguage gkSupportedLanguagesDKCR[] =
|
||||||
ELanguage::NAFrench, ELanguage::NASpanish
|
ELanguage::NAFrench, ELanguage::NASpanish
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Utility function - retrieve the language array for a given game/region
|
||||||
|
static const std::vector<ELanguage>& GetSupportedLanguages(EGame Game, ERegion Region)
|
||||||
|
{
|
||||||
|
switch (Game)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case EGame::PrimeDemo:
|
||||||
|
case EGame::Prime:
|
||||||
|
if (Region == ERegion::NTSC)
|
||||||
|
return gkSupportedLanguagesMP1;
|
||||||
|
else
|
||||||
|
return gkSupportedLanguagesMP1PAL;
|
||||||
|
|
||||||
|
case EGame::EchoesDemo:
|
||||||
|
case EGame::Echoes:
|
||||||
|
case EGame::CorruptionProto:
|
||||||
|
return gkSupportedLanguagesMP1PAL;
|
||||||
|
|
||||||
|
case EGame::Corruption:
|
||||||
|
return gkSupportedLanguagesMP3;
|
||||||
|
|
||||||
|
case EGame::DKCReturns:
|
||||||
|
return gkSupportedLanguagesDKCR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Utility function - retrieve the index of a given language
|
// Utility function - retrieve the index of a given language
|
||||||
static int FindLanguageIndex(const CStringTable* pkInTable, ELanguage InLanguage)
|
static int FindLanguageIndex(const CStringTable* pkInTable, ELanguage InLanguage)
|
||||||
{
|
{
|
||||||
|
@ -192,10 +219,19 @@ void CStringTable::RemoveString(uint StringIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Configures the string table with default languages for the game/region pairing of the resource */
|
/** Initialize new resource data */
|
||||||
void CStringTable::ConfigureDefaultLanguages()
|
void CStringTable::InitializeNewResource()
|
||||||
{
|
{
|
||||||
//@todo; this should be called on all newly created string tables
|
// Initialize data for whatever languages are supported by our game/region
|
||||||
|
ERegion Region = ( Entry() && Entry()->Project() ? Entry()->Project()->Region() : ERegion::NTSC );
|
||||||
|
const std::vector<ELanguage>& kLanguageArray = GetSupportedLanguages(Game(), Region);
|
||||||
|
mLanguages.resize( kLanguageArray.size() );
|
||||||
|
|
||||||
|
for (uint i=0; i < kLanguageArray.size(); i++)
|
||||||
|
{
|
||||||
|
mLanguages[i].Language = kLanguageArray[i];
|
||||||
|
mLanguages[i].Strings.resize(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Serialize resource data */
|
/** Serialize resource data */
|
||||||
|
@ -344,36 +380,12 @@ TString CStringTable::StripFormatting(const TString& kInString)
|
||||||
/** Static - Returns whether a given language is supported by the given game/region combination */
|
/** Static - Returns whether a given language is supported by the given game/region combination */
|
||||||
bool CStringTable::IsLanguageSupported(ELanguage Language, EGame Game, ERegion Region)
|
bool CStringTable::IsLanguageSupported(ELanguage Language, EGame Game, ERegion Region)
|
||||||
{
|
{
|
||||||
// Pick the correct array to iterate based on which game/region was requested.
|
const std::vector<ELanguage>& kLanguageArray = GetSupportedLanguages(Game, Region);
|
||||||
const ELanguage* pkSupportedLanguages = nullptr;
|
|
||||||
uint NumLanguages = 0;
|
|
||||||
|
|
||||||
if (Game <= EGame::Prime && Region == ERegion::NTSC)
|
|
||||||
{
|
|
||||||
return (Language == ELanguage::English);
|
|
||||||
}
|
|
||||||
else if (Game <= EGame::CorruptionProto)
|
|
||||||
{
|
|
||||||
pkSupportedLanguages = &gkSupportedLanguagesMP1PAL[0];
|
|
||||||
NumLanguages = ARRAY_SIZE( gkSupportedLanguagesMP1PAL );
|
|
||||||
}
|
|
||||||
else if (Game <= EGame::Corruption)
|
|
||||||
{
|
|
||||||
pkSupportedLanguages = &gkSupportedLanguagesMP3[0];
|
|
||||||
NumLanguages = ARRAY_SIZE( gkSupportedLanguagesMP3 );
|
|
||||||
}
|
|
||||||
else if (Game <= EGame::DKCReturns)
|
|
||||||
{
|
|
||||||
pkSupportedLanguages = &gkSupportedLanguagesDKCR[0];
|
|
||||||
NumLanguages = ARRAY_SIZE( gkSupportedLanguagesDKCR );
|
|
||||||
}
|
|
||||||
ASSERT(pkSupportedLanguages);
|
|
||||||
ASSERT(NumLanguages > 0);
|
|
||||||
|
|
||||||
// Check if the requested language is in the array.
|
// Check if the requested language is in the array.
|
||||||
for (uint LanguageIdx = 0; LanguageIdx < NumLanguages; LanguageIdx++)
|
for (uint LanguageIdx = 0; LanguageIdx < kLanguageArray.size(); LanguageIdx++)
|
||||||
{
|
{
|
||||||
if (pkSupportedLanguages[LanguageIdx] == Language)
|
if (kLanguageArray[LanguageIdx] == Language)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,14 +84,14 @@ public:
|
||||||
/** Remove a string from the table */
|
/** Remove a string from the table */
|
||||||
void RemoveString(uint StringIndex);
|
void RemoveString(uint StringIndex);
|
||||||
|
|
||||||
/** Configures the string table with default languages for the game/region pairing of the resource */
|
/** Initialize new resource data */
|
||||||
void ConfigureDefaultLanguages();
|
virtual void InitializeNewResource() override;
|
||||||
|
|
||||||
/** Serialize resource data */
|
/** Serialize resource data */
|
||||||
virtual void Serialize(IArchive& Arc);
|
virtual void Serialize(IArchive& Arc) override;
|
||||||
|
|
||||||
/** Build the dependency tree for this resource */
|
/** Build the dependency tree for this resource */
|
||||||
virtual CDependencyTree* BuildDependencyTree() const;
|
virtual CDependencyTree* BuildDependencyTree() const override;
|
||||||
|
|
||||||
/** Static - Strip all formatting tags for a given string */
|
/** Static - Strip all formatting tags for a given string */
|
||||||
static TString StripFormatting(const TString& kInString);
|
static TString StripFormatting(const TString& kInString);
|
||||||
|
|
|
@ -9,6 +9,11 @@ CTweakManager::CTweakManager(CGameProject* pInProject)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CTweakManager::~CTweakManager()
|
||||||
|
{
|
||||||
|
ClearTweaks();
|
||||||
|
}
|
||||||
|
|
||||||
void CTweakManager::LoadTweaks()
|
void CTweakManager::LoadTweaks()
|
||||||
{
|
{
|
||||||
ASSERT( mTweakObjects.empty() );
|
ASSERT( mTweakObjects.empty() );
|
||||||
|
@ -33,21 +38,6 @@ void CTweakManager::LoadTweaks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CTweakManager::~CTweakManager()
|
|
||||||
{
|
|
||||||
for (CTweakData* pTweakData : mTweakObjects)
|
|
||||||
{
|
|
||||||
if (pTweakData->Entry() != nullptr)
|
|
||||||
{
|
|
||||||
pTweakData->Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
delete pTweakData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CTweakManager::SaveTweaks()
|
bool CTweakManager::SaveTweaks()
|
||||||
{
|
{
|
||||||
// MP1 - Save all tweak assets
|
// MP1 - Save all tweak assets
|
||||||
|
@ -82,3 +72,19 @@ bool CTweakManager::SaveTweaks()
|
||||||
return CTweakCooker::CookNTWK(mTweakObjects, StandardNTWK);
|
return CTweakCooker::CookNTWK(mTweakObjects, StandardNTWK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CTweakManager::ClearTweaks()
|
||||||
|
{
|
||||||
|
for (CTweakData* pTweakData : mTweakObjects)
|
||||||
|
{
|
||||||
|
if (pTweakData->Entry() != nullptr)
|
||||||
|
{
|
||||||
|
pTweakData->Release();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete pTweakData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mTweakObjects.clear();
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
~CTweakManager();
|
~CTweakManager();
|
||||||
void LoadTweaks();
|
void LoadTweaks();
|
||||||
bool SaveTweaks();
|
bool SaveTweaks();
|
||||||
|
void ClearTweaks();
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
inline const std::vector<CTweakData*>& TweakObjects() const
|
inline const std::vector<CTweakData*>& TweakObjects() const
|
||||||
|
|
|
@ -249,6 +249,7 @@ bool CEditorApplication::RebuildResourceDatabase()
|
||||||
{
|
{
|
||||||
// Fake-close the project, but keep it in memory so we can modify the resource store
|
// Fake-close the project, but keep it in memory so we can modify the resource store
|
||||||
CGameProject *pProj = mpActiveProject;
|
CGameProject *pProj = mpActiveProject;
|
||||||
|
mpActiveProject->TweakManager()->ClearTweaks();
|
||||||
mpActiveProject = nullptr;
|
mpActiveProject = nullptr;
|
||||||
emit ActiveProjectChanged(nullptr);
|
emit ActiveProjectChanged(nullptr);
|
||||||
|
|
||||||
|
@ -263,6 +264,7 @@ bool CEditorApplication::RebuildResourceDatabase()
|
||||||
|
|
||||||
// Set project to active again
|
// Set project to active again
|
||||||
mpActiveProject = pProj;
|
mpActiveProject = pProj;
|
||||||
|
mpActiveProject->TweakManager()->LoadTweaks();
|
||||||
emit ActiveProjectChanged(pProj);
|
emit ActiveProjectChanged(pProj);
|
||||||
|
|
||||||
UICommon::InfoMsg(mpWorldEditor, "Success", "Resource database rebuilt successfully!");
|
UICommon::InfoMsg(mpWorldEditor, "Success", "Resource database rebuilt successfully!");
|
||||||
|
|
|
@ -34,7 +34,12 @@ CPropertyDelegate::CPropertyDelegate(QObject* pParent /*= 0*/)
|
||||||
, mEditInProgress(false)
|
, mEditInProgress(false)
|
||||||
, mRelaysBlocked(false)
|
, mRelaysBlocked(false)
|
||||||
{
|
{
|
||||||
mpEditor = UICommon::FindAncestor<IEditor>(this);
|
mpEditor = UICommon::FindAncestor<IEditor>(pParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPropertyDelegate::SetEditor(IEditor* pEditor)
|
||||||
|
{
|
||||||
|
mpEditor = pEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPropertyDelegate::SetPropertyModel(CPropertyModel* pModel)
|
void CPropertyDelegate::SetPropertyModel(CPropertyModel* pModel)
|
||||||
|
|
|
@ -83,6 +83,11 @@ bool CPropertyView::event(QEvent *pEvent)
|
||||||
else return QTreeView::event(pEvent);
|
else return QTreeView::event(pEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPropertyView::SetEditor(IEditor* pEditor)
|
||||||
|
{
|
||||||
|
mpDelegate->SetEditor(pEditor);
|
||||||
|
}
|
||||||
|
|
||||||
void CPropertyView::InitColumnWidths(float NameColumnPercentage, float ValueColumnPercentage)
|
void CPropertyView::InitColumnWidths(float NameColumnPercentage, float ValueColumnPercentage)
|
||||||
{
|
{
|
||||||
header()->resizeSection(0, width() * NameColumnPercentage);
|
header()->resizeSection(0, width() * NameColumnPercentage);
|
||||||
|
|
|
@ -25,6 +25,7 @@ public:
|
||||||
CPropertyView(QWidget* pParent = 0);
|
CPropertyView(QWidget* pParent = 0);
|
||||||
void setModel(QAbstractItemModel* pModel);
|
void setModel(QAbstractItemModel* pModel);
|
||||||
bool event(QEvent* pEvent);
|
bool event(QEvent* pEvent);
|
||||||
|
void SetEditor(IEditor* pEditor);
|
||||||
void InitColumnWidths(float NameColumnPercentage, float ValueColumnPercentage);
|
void InitColumnWidths(float NameColumnPercentage, float ValueColumnPercentage);
|
||||||
void ClearProperties();
|
void ClearProperties();
|
||||||
void SetIntrinsicProperties(CStructRef InProperties);
|
void SetIntrinsicProperties(CStructRef InProperties);
|
||||||
|
|
|
@ -28,6 +28,7 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
|
||||||
, mEditorStore(false)
|
, mEditorStore(false)
|
||||||
, mAssetListMode(false)
|
, mAssetListMode(false)
|
||||||
, mSearching(false)
|
, mSearching(false)
|
||||||
|
, mpAddMenu(nullptr)
|
||||||
, mpInspectedEntry(nullptr)
|
, mpInspectedEntry(nullptr)
|
||||||
{
|
{
|
||||||
mpUI->setupUi(this);
|
mpUI->setupUi(this);
|
||||||
|
@ -150,7 +151,6 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
|
||||||
connect(mpUI->ResourceTreeButton, SIGNAL(pressed()), this, SLOT(SetResourceTreeView()));
|
connect(mpUI->ResourceTreeButton, SIGNAL(pressed()), this, SLOT(SetResourceTreeView()));
|
||||||
connect(mpUI->ResourceListButton, SIGNAL(pressed()), this, SLOT(SetResourceListView()));
|
connect(mpUI->ResourceListButton, SIGNAL(pressed()), this, SLOT(SetResourceListView()));
|
||||||
connect(mpUI->SortComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSortModeChanged(int)));
|
connect(mpUI->SortComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSortModeChanged(int)));
|
||||||
connect(mpUI->NewFolderButton, SIGNAL(pressed()), this, SLOT(CreateDirectory()));
|
|
||||||
connect(mpUI->ClearButton, SIGNAL(pressed()), this, SLOT(OnClearButtonPressed()));
|
connect(mpUI->ClearButton, SIGNAL(pressed()), this, SLOT(OnClearButtonPressed()));
|
||||||
|
|
||||||
connect(mpUI->DirectoryTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex)));
|
connect(mpUI->DirectoryTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex)));
|
||||||
|
@ -281,6 +281,50 @@ void CResourceBrowser::CreateFilterCheckboxes()
|
||||||
mpFilterBoxesLayout->addSpacerItem(pSpacer);
|
mpFilterBoxesLayout->addSpacerItem(pSpacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CResourceBrowser::CreateAddMenu()
|
||||||
|
{
|
||||||
|
// Delete any existing menu
|
||||||
|
if (mpAddMenu)
|
||||||
|
{
|
||||||
|
delete mpAddMenu;
|
||||||
|
mpAddMenu = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new one, only if we have a valid resource store.
|
||||||
|
if (mpStore)
|
||||||
|
{
|
||||||
|
mpAddMenu = new QMenu(this);
|
||||||
|
mpAddMenu->addAction("New Folder", this, SLOT(CreateDirectory()));
|
||||||
|
mpAddMenu->addSeparator();
|
||||||
|
|
||||||
|
QMenu* pCreateMenu = new QMenu("Create...");
|
||||||
|
mpAddMenu->addMenu(pCreateMenu);
|
||||||
|
AddCreateAssetMenuActions(pCreateMenu);
|
||||||
|
|
||||||
|
mpUI->AddButton->setMenu(mpAddMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
mpUI->AddButton->setEnabled( mpAddMenu != nullptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceBrowser::AddCreateAssetMenuActions(QMenu* pMenu)
|
||||||
|
{
|
||||||
|
std::list<CResTypeInfo*> TypeInfos;
|
||||||
|
CResTypeInfo::GetAllTypesInGame(mpStore->Game(), TypeInfos);
|
||||||
|
|
||||||
|
for (auto Iter = TypeInfos.begin(); Iter != TypeInfos.end(); Iter++)
|
||||||
|
{
|
||||||
|
CResTypeInfo* pTypeInfo = *Iter;
|
||||||
|
|
||||||
|
if (pTypeInfo->CanBeCreated())
|
||||||
|
{
|
||||||
|
QString TypeName = TO_QSTRING( pTypeInfo->TypeName() );
|
||||||
|
QAction* pAction = pMenu->addAction(TypeName, this, SLOT(OnCreateAssetAction()));
|
||||||
|
pAction->setProperty("TypeInfo", QVariant((int) pTypeInfo->Type()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CResourceBrowser::RenameResource(CResourceEntry *pEntry, const TString& rkNewName)
|
bool CResourceBrowser::RenameResource(CResourceEntry *pEntry, const TString& rkNewName)
|
||||||
{
|
{
|
||||||
if (pEntry->Name() == rkNewName)
|
if (pEntry->Name() == rkNewName)
|
||||||
|
@ -400,6 +444,49 @@ bool CResourceBrowser::MoveResources(const QList<CResourceEntry*>& rkResources,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CResourceEntry* CResourceBrowser::CreateNewResource(EResourceType Type)
|
||||||
|
{
|
||||||
|
// Create new asset ID. Sanity check to make sure the ID is unused.
|
||||||
|
CAssetID NewAssetID;
|
||||||
|
|
||||||
|
while (!NewAssetID.IsValid() || mpStore->FindEntry(NewAssetID) != nullptr)
|
||||||
|
{
|
||||||
|
NewAssetID = CAssetID::RandomID( mpStore->Game() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boring generic default name - user will immediately be prompted to change this
|
||||||
|
TString BaseName = TString::Format(
|
||||||
|
"New %s", *CResTypeInfo::FindTypeInfo(Type)->TypeName()
|
||||||
|
);
|
||||||
|
|
||||||
|
TString Name = BaseName;
|
||||||
|
int Num = 0;
|
||||||
|
|
||||||
|
while (mpSelectedDir->FindChildResource(Name, Type) != nullptr)
|
||||||
|
{
|
||||||
|
Num++;
|
||||||
|
Name = TString::Format("%s (%d)", *BaseName, Num);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit ResourceAboutToBeCreated(mpSelectedDir);
|
||||||
|
|
||||||
|
// Create the actual resource
|
||||||
|
CResourceEntry* pEntry = mpStore->CreateNewResource(NewAssetID, Type, mpSelectedDir->FullPath(), Name);
|
||||||
|
pEntry->Save();
|
||||||
|
|
||||||
|
emit ResourceCreated(pEntry);
|
||||||
|
|
||||||
|
// Select new resource so user can enter a name
|
||||||
|
QModelIndex Index = mpModel->GetIndexForEntry(pEntry);
|
||||||
|
ASSERT(Index.isValid());
|
||||||
|
|
||||||
|
QModelIndex ProxyIndex = mpProxyModel->mapFromSource(Index);
|
||||||
|
mpUI->ResourceTableView->selectionModel()->select(ProxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||||
|
mpUI->ResourceTableView->edit(ProxyIndex);
|
||||||
|
|
||||||
|
return pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
bool CResourceBrowser::eventFilter(QObject *pWatched, QEvent *pEvent)
|
bool CResourceBrowser::eventFilter(QObject *pWatched, QEvent *pEvent)
|
||||||
{
|
{
|
||||||
if (pWatched == mpUI->ResourceTableView)
|
if (pWatched == mpUI->ResourceTableView)
|
||||||
|
@ -498,6 +585,23 @@ void CResourceBrowser::OnSortModeChanged(int Index)
|
||||||
mpProxyModel->SetSortMode(Mode);
|
mpProxyModel->SetSortMode(Mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CResourceBrowser::OnCreateAssetAction()
|
||||||
|
{
|
||||||
|
// Attempt to retrieve the asset type from the sender. If successful, create the asset.
|
||||||
|
QAction* pSender = qobject_cast<QAction*>(sender());
|
||||||
|
|
||||||
|
if (pSender)
|
||||||
|
{
|
||||||
|
bool Ok;
|
||||||
|
EResourceType Type = (EResourceType) pSender->property("TypeInfo").toInt(&Ok);
|
||||||
|
|
||||||
|
if (Ok)
|
||||||
|
{
|
||||||
|
CreateNewResource(Type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CResourceBrowser::CreateDirectory()
|
bool CResourceBrowser::CreateDirectory()
|
||||||
{
|
{
|
||||||
if (mpSelectedDir)
|
if (mpSelectedDir)
|
||||||
|
@ -685,7 +789,8 @@ void CResourceBrowser::UpdateStore()
|
||||||
mpUI->SearchBar->clear();
|
mpUI->SearchBar->clear();
|
||||||
mSearching = false;
|
mSearching = false;
|
||||||
|
|
||||||
// Refresh type filter list
|
// Refresh project-specific UI
|
||||||
|
CreateAddMenu();
|
||||||
CreateFilterCheckboxes();
|
CreateFilterCheckboxes();
|
||||||
|
|
||||||
// Refresh directory tree
|
// Refresh directory tree
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
#include "CResourceProxyModel.h"
|
#include "CResourceProxyModel.h"
|
||||||
#include "CResourceTableModel.h"
|
#include "CResourceTableModel.h"
|
||||||
#include "CVirtualDirectoryModel.h"
|
#include "CVirtualDirectoryModel.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QMenu>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QUndoStack>
|
#include <QUndoStack>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
@ -29,6 +31,9 @@ class CResourceBrowser : public QWidget
|
||||||
bool mAssetListMode;
|
bool mAssetListMode;
|
||||||
bool mSearching;
|
bool mSearching;
|
||||||
|
|
||||||
|
// Add Menu
|
||||||
|
QMenu *mpAddMenu;
|
||||||
|
|
||||||
// Type Filter
|
// Type Filter
|
||||||
QWidget *mpFilterBoxesContainerWidget;
|
QWidget *mpFilterBoxesContainerWidget;
|
||||||
QVBoxLayout *mpFilterBoxesLayout;
|
QVBoxLayout *mpFilterBoxesLayout;
|
||||||
|
@ -59,11 +64,16 @@ public:
|
||||||
void SelectResource(CResourceEntry *pEntry, bool ClearFiltersIfNecessary = false);
|
void SelectResource(CResourceEntry *pEntry, bool ClearFiltersIfNecessary = false);
|
||||||
void SelectDirectory(CVirtualDirectory *pDir);
|
void SelectDirectory(CVirtualDirectory *pDir);
|
||||||
void CreateFilterCheckboxes();
|
void CreateFilterCheckboxes();
|
||||||
|
void CreateAddMenu();
|
||||||
|
|
||||||
|
void AddCreateAssetMenuActions(QMenu* pMenu);
|
||||||
|
|
||||||
bool RenameResource(CResourceEntry *pEntry, const TString& rkNewName);
|
bool RenameResource(CResourceEntry *pEntry, const TString& rkNewName);
|
||||||
bool RenameDirectory(CVirtualDirectory *pDir, const TString& rkNewName);
|
bool RenameDirectory(CVirtualDirectory *pDir, const TString& rkNewName);
|
||||||
bool MoveResources(const QList<CResourceEntry*>& rkResources, const QList<CVirtualDirectory*>& rkDirectories, CVirtualDirectory *pNewDir);
|
bool MoveResources(const QList<CResourceEntry*>& rkResources, const QList<CVirtualDirectory*>& rkDirectories, CVirtualDirectory *pNewDir);
|
||||||
|
|
||||||
|
CResourceEntry* CreateNewResource(EResourceType Type);
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
bool eventFilter(QObject *pWatched, QEvent *pEvent);
|
bool eventFilter(QObject *pWatched, QEvent *pEvent);
|
||||||
|
|
||||||
|
@ -82,6 +92,7 @@ public slots:
|
||||||
void SetResourceListView();
|
void SetResourceListView();
|
||||||
void OnClearButtonPressed();
|
void OnClearButtonPressed();
|
||||||
void OnSortModeChanged(int Index);
|
void OnSortModeChanged(int Index);
|
||||||
|
void OnCreateAssetAction();
|
||||||
bool CreateDirectory();
|
bool CreateDirectory();
|
||||||
bool DeleteDirectories(const QList<CVirtualDirectory*>& rkDirs);
|
bool DeleteDirectories(const QList<CVirtualDirectory*>& rkDirs);
|
||||||
void OnSearchStringChanged(QString SearchString);
|
void OnSearchStringChanged(QString SearchString);
|
||||||
|
@ -116,6 +127,12 @@ signals:
|
||||||
void ResourceAboutToBeMoved(CResourceEntry *pRes, QString NewPath);
|
void ResourceAboutToBeMoved(CResourceEntry *pRes, QString NewPath);
|
||||||
void ResourceMoved(CResourceEntry *pRes, CVirtualDirectory *pOldDir, TString OldName);
|
void ResourceMoved(CResourceEntry *pRes, CVirtualDirectory *pOldDir, TString OldName);
|
||||||
|
|
||||||
|
void ResourceAboutToBeCreated(CVirtualDirectory* pInDir);
|
||||||
|
void ResourceCreated(CResourceEntry *pRes);
|
||||||
|
|
||||||
|
void ResourceAboutToBeDeleted(CResourceEntry *pRes);
|
||||||
|
void ResourceDeleted();
|
||||||
|
|
||||||
void DirectoryAboutToBeMoved(CVirtualDirectory *pDir, QString NewPath);
|
void DirectoryAboutToBeMoved(CVirtualDirectory *pDir, QString NewPath);
|
||||||
void DirectoryMoved(CVirtualDirectory *pDir, CVirtualDirectory *pOldDir, TString OldName);
|
void DirectoryMoved(CVirtualDirectory *pDir, CVirtualDirectory *pOldDir, TString OldName);
|
||||||
|
|
||||||
|
|
|
@ -141,9 +141,18 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="NewFolderButton">
|
<widget class="QPushButton" name="AddButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string> New Folder</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../Icons.qrc">
|
<iconset resource="../Icons.qrc">
|
||||||
|
@ -151,8 +160,8 @@
|
||||||
</property>
|
</property>
|
||||||
<property name="iconSize">
|
<property name="iconSize">
|
||||||
<size>
|
<size>
|
||||||
<width>16</width>
|
<width>24</width>
|
||||||
<height>16</height>
|
<height>24</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -9,180 +9,252 @@ CResourceTableContextMenu::CResourceTableContextMenu(CResourceBrowser *pBrowser,
|
||||||
, mpTable(pView)
|
, mpTable(pView)
|
||||||
, mpModel(pModel)
|
, mpModel(pModel)
|
||||||
, mpProxy(pProxy)
|
, mpProxy(pProxy)
|
||||||
, mpEntry(nullptr)
|
, mpClickedEntry(nullptr)
|
||||||
, mpDirectory(nullptr)
|
, mpClickedDirectory(nullptr)
|
||||||
{
|
{
|
||||||
// Connect to the view
|
// Connect to the view
|
||||||
connect(pView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowMenu(QPoint)));
|
connect(pView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowMenu(QPoint)));
|
||||||
|
}
|
||||||
|
|
||||||
// Create actions
|
void CResourceTableContextMenu::InitMenu()
|
||||||
|
{
|
||||||
|
// Clear existing menu items
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (mpClickedEntry)
|
||||||
|
{
|
||||||
#if WIN32
|
#if WIN32
|
||||||
QString OpenInExplorerString = "Show in Explorer";
|
const QString kOpenInExplorerString = "Show in Explorer";
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
QString OpenInExplorerString = "Show in Finder";
|
const QString kOpenInExplorerString = "Show in Finder";
|
||||||
#else
|
#else
|
||||||
QString OpenInExplorerString = "Show in file manager";
|
const QString kOpenInExplorerString = "Show in file manager";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mpOpenAction = addAction("Open", this, SLOT(Open()));
|
addAction("Open", this, SLOT(Open()));
|
||||||
mpOpenInExternalAppAction = addAction("Open in External Application", this, SLOT(OpenInExternalApp()));
|
addAction("Open in External Application", this, SLOT(OpenInExternalApp()));
|
||||||
mpOpenInExplorerAction = addAction(OpenInExplorerString, this, SLOT(OpenInExplorer()));
|
addAction(kOpenInExplorerString, this, SLOT(OpenInExplorer()));
|
||||||
addSeparator();
|
addSeparator();
|
||||||
mpRenameAction = addAction("Rename", this, SLOT(Rename()));
|
}
|
||||||
mpSelectFolderAction = addAction("Select Folder", this, SLOT(SelectFolder()));
|
|
||||||
mpShowReferencersAction = addAction("Show Referencers", this, SLOT(ShowReferencers()));
|
if (mpClickedEntry || mpClickedDirectory)
|
||||||
mpShowDependenciesAction = addAction("Show Dependencies", this, SLOT(ShowDependencies()));
|
{
|
||||||
mpDeleteAction = addAction("Delete", this, SLOT(Delete()));
|
addAction("Rename", this, SLOT(Rename()));
|
||||||
|
|
||||||
|
if (mpModel->IsDisplayingAssetList())
|
||||||
|
{
|
||||||
|
addAction("Select Folder", this, SLOT(SelectFolder()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mpClickedEntry)
|
||||||
|
{
|
||||||
|
addAction("Show Referencers", this, SLOT(ShowReferencers()));
|
||||||
|
addAction("Show Dependencies", this, SLOT(ShowDependencies()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mpClickedEntry || mpClickedDirectory || !mSelectedIndexes.isEmpty())
|
||||||
|
{
|
||||||
|
addAction("Delete", this, SLOT(Delete()));
|
||||||
|
}
|
||||||
|
|
||||||
addSeparator();
|
addSeparator();
|
||||||
mpCopyNameAction = addAction("Copy Name", this, SLOT(CopyName()));
|
|
||||||
mpCopyPathAction = addAction("Copy Path", this, SLOT(CopyPath()));
|
if (mpClickedEntry)
|
||||||
mpCopyIDAction = addAction("Copy Asset ID", this, SLOT(CopyID()));
|
{
|
||||||
|
addAction("Copy Name", this, SLOT(CopyName()));
|
||||||
|
addAction("Copy Path", this, SLOT(CopyPath()));
|
||||||
|
addAction("Copy ID", this, SLOT(CopyID()));
|
||||||
|
addSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu* pCreate = addMenu("Create...");
|
||||||
|
mpBrowser->AddCreateAssetMenuActions(pCreate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::ShowMenu(const QPoint& rkPos)
|
void CResourceTableContextMenu::ShowMenu(const QPoint& rkPos)
|
||||||
{
|
{
|
||||||
|
if (mpBrowser->CurrentStore() == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
// Fetch the entry/directory
|
// Fetch the entry/directory
|
||||||
mProxyIndex = mpTable->indexAt(rkPos);
|
mClickedProxyIndex = mpTable->indexAt(rkPos);
|
||||||
|
|
||||||
if (mProxyIndex.isValid())
|
if (mClickedProxyIndex.isValid())
|
||||||
{
|
{
|
||||||
mIndex = mpProxy->mapToSource(mProxyIndex);
|
mClickedIndex = mpProxy->mapToSource(mClickedProxyIndex);
|
||||||
mpEntry = mpModel->IndexEntry(mIndex);
|
mpClickedEntry = mpModel->IndexEntry(mClickedIndex);
|
||||||
mpDirectory = mpModel->IndexDirectory(mIndex);
|
mpClickedDirectory = mpModel->IndexDirectory(mClickedIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mClickedIndex = QModelIndex();
|
||||||
|
mpClickedEntry = nullptr;
|
||||||
|
mpClickedDirectory = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Show/hide menu options
|
// Fetch the list of selected indexes
|
||||||
bool IsRes = (mpEntry != nullptr);
|
QItemSelection Selection = mpProxy->mapSelectionToSource( mpTable->selectionModel()->selection() );
|
||||||
mpOpenInExternalAppAction->setVisible(IsRes);
|
mSelectedIndexes = Selection.indexes();
|
||||||
mpSelectFolderAction->setVisible(mpModel->IsDisplayingAssetList());
|
|
||||||
mpShowDependenciesAction->setVisible(IsRes);
|
InitMenu();
|
||||||
mpShowReferencersAction->setVisible(IsRes);
|
|
||||||
mpDeleteAction->setVisible(mpDirectory && mpDirectory->IsEmpty(true));
|
|
||||||
mpCopyIDAction->setVisible(IsRes);
|
|
||||||
|
|
||||||
// Exec menu
|
// Exec menu
|
||||||
QPoint GlobalPos = mpTable->viewport()->mapToGlobal(rkPos);
|
QPoint GlobalPos = mpTable->viewport()->mapToGlobal(rkPos);
|
||||||
exec(GlobalPos);
|
exec(GlobalPos);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Menu Options
|
// Menu Options
|
||||||
void CResourceTableContextMenu::Open()
|
void CResourceTableContextMenu::Open()
|
||||||
{
|
{
|
||||||
if (mpEntry)
|
if (mpClickedEntry)
|
||||||
gpEdApp->EditResource(mpEntry);
|
gpEdApp->EditResource(mpClickedEntry);
|
||||||
else
|
else
|
||||||
mpBrowser->SetActiveDirectory(mpDirectory);
|
mpBrowser->SetActiveDirectory(mpClickedDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::OpenInExternalApp()
|
void CResourceTableContextMenu::OpenInExternalApp()
|
||||||
{
|
{
|
||||||
ASSERT(mpEntry);
|
ASSERT(mpClickedEntry);
|
||||||
UICommon::OpenInExternalApplication( TO_QSTRING(mpEntry->CookedAssetPath()) );
|
UICommon::OpenInExternalApplication( TO_QSTRING(mpClickedEntry->CookedAssetPath()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::OpenInExplorer()
|
void CResourceTableContextMenu::OpenInExplorer()
|
||||||
{
|
{
|
||||||
if (mpEntry)
|
if (mpClickedEntry)
|
||||||
{
|
{
|
||||||
QString Path = TO_QSTRING( mpEntry->CookedAssetPath() );
|
QString Path = TO_QSTRING( mpClickedEntry->CookedAssetPath() );
|
||||||
UICommon::OpenContainingFolder(Path);
|
UICommon::OpenContainingFolder(Path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TString BasePath = mpBrowser->CurrentStore()->ResourcesDir();
|
TString BasePath = mpBrowser->CurrentStore()->ResourcesDir();
|
||||||
QString Path = TO_QSTRING( BasePath + mpDirectory->FullPath() );
|
QString Path = TO_QSTRING( BasePath + mpClickedDirectory->FullPath() );
|
||||||
UICommon::OpenContainingFolder(Path);
|
UICommon::OpenContainingFolder(Path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::Rename()
|
void CResourceTableContextMenu::Rename()
|
||||||
{
|
{
|
||||||
mpTable->edit(mProxyIndex);
|
mpTable->edit(mClickedProxyIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::SelectFolder()
|
void CResourceTableContextMenu::SelectFolder()
|
||||||
{
|
{
|
||||||
CVirtualDirectory *pDir = (mpEntry ? mpEntry->Directory() : mpDirectory->Parent());
|
CVirtualDirectory *pDir = (mpClickedEntry ? mpClickedEntry->Directory() : mpClickedDirectory->Parent());
|
||||||
mpBrowser->SetActiveDirectory(pDir);
|
mpBrowser->SetActiveDirectory(pDir);
|
||||||
|
|
||||||
if (mpEntry)
|
if (mpClickedEntry)
|
||||||
mpBrowser->SelectResource(mpEntry);
|
mpBrowser->SelectResource(mpClickedEntry);
|
||||||
else
|
else
|
||||||
mpBrowser->SelectDirectory(mpDirectory);
|
mpBrowser->SelectDirectory(mpClickedDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::ShowReferencers()
|
void CResourceTableContextMenu::ShowReferencers()
|
||||||
{
|
{
|
||||||
ASSERT(mpEntry);
|
ASSERT(mpClickedEntry);
|
||||||
|
|
||||||
QList<CResourceEntry*> EntryList;
|
QList<CResourceEntry*> EntryList;
|
||||||
|
|
||||||
for (CResourceIterator Iter(mpEntry->ResourceStore()); Iter; ++Iter)
|
for (CResourceIterator Iter(mpClickedEntry->ResourceStore()); Iter; ++Iter)
|
||||||
{
|
{
|
||||||
if (Iter->Dependencies()->HasDependency(mpEntry->ID()))
|
if (Iter->Dependencies()->HasDependency(mpClickedEntry->ID()))
|
||||||
EntryList << *Iter;
|
EntryList << *Iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpModel->IsDisplayingUserEntryList())
|
if (!mpModel->IsDisplayingUserEntryList())
|
||||||
mpBrowser->SetInspectedEntry(mpEntry);
|
mpBrowser->SetInspectedEntry(mpClickedEntry);
|
||||||
|
|
||||||
QString ListDesc = QString("Referencers of \"%1\"").arg( TO_QSTRING(mpEntry->CookedAssetPath().GetFileName()) );
|
QString ListDesc = QString("Referencers of \"%1\"").arg( TO_QSTRING(mpClickedEntry->CookedAssetPath().GetFileName()) );
|
||||||
mpModel->DisplayEntryList(EntryList, ListDesc);
|
mpModel->DisplayEntryList(EntryList, ListDesc);
|
||||||
mpBrowser->ClearFilters();
|
mpBrowser->ClearFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::ShowDependencies()
|
void CResourceTableContextMenu::ShowDependencies()
|
||||||
{
|
{
|
||||||
ASSERT(mpEntry);
|
ASSERT(mpClickedEntry);
|
||||||
|
|
||||||
std::set<CAssetID> Dependencies;
|
std::set<CAssetID> Dependencies;
|
||||||
mpEntry->Dependencies()->GetAllResourceReferences(Dependencies);
|
mpClickedEntry->Dependencies()->GetAllResourceReferences(Dependencies);
|
||||||
|
|
||||||
QList<CResourceEntry*> EntryList;
|
QList<CResourceEntry*> EntryList;
|
||||||
|
|
||||||
for (auto Iter = Dependencies.begin(); Iter != Dependencies.end(); Iter++)
|
for (auto Iter = Dependencies.begin(); Iter != Dependencies.end(); Iter++)
|
||||||
{
|
{
|
||||||
CResourceEntry *pEntry = mpEntry->ResourceStore()->FindEntry(*Iter);
|
CResourceEntry *pEntry = mpClickedEntry->ResourceStore()->FindEntry(*Iter);
|
||||||
|
|
||||||
if (pEntry)
|
if (pEntry)
|
||||||
EntryList << pEntry;
|
EntryList << pEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpModel->IsDisplayingUserEntryList())
|
if (!mpModel->IsDisplayingUserEntryList())
|
||||||
mpBrowser->SetInspectedEntry(mpEntry);
|
mpBrowser->SetInspectedEntry(mpClickedEntry);
|
||||||
|
|
||||||
QString ListDesc = QString("Dependencies of \"%1\"").arg( TO_QSTRING(mpEntry->CookedAssetPath().GetFileName()) );
|
QString ListDesc = QString("Dependencies of \"%1\"").arg( TO_QSTRING(mpClickedEntry->CookedAssetPath().GetFileName()) );
|
||||||
mpModel->DisplayEntryList(EntryList, ListDesc);
|
mpModel->DisplayEntryList(EntryList, ListDesc);
|
||||||
mpBrowser->ClearFilters();
|
mpBrowser->ClearFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::Delete()
|
void CResourceTableContextMenu::Delete()
|
||||||
{
|
{
|
||||||
ASSERT(mpDirectory && mpDirectory->IsEmpty(true));
|
// Create confirmation message
|
||||||
|
uint NumResources = 0, NumDirectories = 0;
|
||||||
|
|
||||||
|
foreach (const QModelIndex& kIndex, mSelectedIndexes)
|
||||||
|
{
|
||||||
|
if (mpModel->IsIndexDirectory(kIndex))
|
||||||
|
NumDirectories++;
|
||||||
|
else
|
||||||
|
NumResources++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NumResources == 0 && NumDirectories == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString ConfirmMsg = QString("Are you sure you want to permanently delete ");
|
||||||
|
|
||||||
|
if (NumResources > 0)
|
||||||
|
{
|
||||||
|
ConfirmMsg += QString("%d resource%s").arg(NumResources).arg(NumResources == 1 ? "" : "s");
|
||||||
|
|
||||||
|
if (NumDirectories > 0)
|
||||||
|
{
|
||||||
|
ConfirmMsg += " and ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (NumDirectories > 0)
|
||||||
|
{
|
||||||
|
ConfirmMsg += QString("%d %s").arg(NumDirectories).arg(NumDirectories == 1 ? "directory" : "directories");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the user to confirm the action before performing it
|
||||||
|
if (UICommon::YesNoQuestion(mpBrowser, "Warning", ConfirmMsg))
|
||||||
|
{
|
||||||
|
//@todo this is wrong lol
|
||||||
QList<CVirtualDirectory*> List;
|
QList<CVirtualDirectory*> List;
|
||||||
List << mpDirectory;
|
List << mpClickedDirectory;
|
||||||
mpBrowser->DeleteDirectories(List);
|
mpBrowser->DeleteDirectories(List);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::CopyName()
|
void CResourceTableContextMenu::CopyName()
|
||||||
{
|
{
|
||||||
if (mpEntry)
|
if (mpClickedEntry)
|
||||||
gpEdApp->clipboard()->setText( TO_QSTRING(mpEntry->Name()) );
|
gpEdApp->clipboard()->setText( TO_QSTRING(mpClickedEntry->Name()) );
|
||||||
else
|
else
|
||||||
gpEdApp->clipboard()->setText( TO_QSTRING(mpDirectory->Name()) );
|
gpEdApp->clipboard()->setText( TO_QSTRING(mpClickedDirectory->Name()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::CopyPath()
|
void CResourceTableContextMenu::CopyPath()
|
||||||
{
|
{
|
||||||
if (mpEntry)
|
if (mpClickedEntry)
|
||||||
gpEdApp->clipboard()->setText( TO_QSTRING(mpEntry->CookedAssetPath(true)) );
|
gpEdApp->clipboard()->setText( TO_QSTRING(mpClickedEntry->CookedAssetPath(true)) );
|
||||||
else
|
else
|
||||||
gpEdApp->clipboard()->setText( TO_QSTRING(mpDirectory->FullPath()) );
|
gpEdApp->clipboard()->setText( TO_QSTRING(mpClickedDirectory->FullPath()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::CopyID()
|
void CResourceTableContextMenu::CopyID()
|
||||||
{
|
{
|
||||||
ASSERT(mpEntry);
|
ASSERT(mpClickedEntry);
|
||||||
gpEdApp->clipboard()->setText( TO_QSTRING(mpEntry->ID().ToString()) );
|
gpEdApp->clipboard()->setText( TO_QSTRING(mpClickedEntry->ID().ToString()) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,30 +16,17 @@ class CResourceTableContextMenu : public QMenu
|
||||||
CResourceTableModel *mpModel;
|
CResourceTableModel *mpModel;
|
||||||
CResourceProxyModel *mpProxy;
|
CResourceProxyModel *mpProxy;
|
||||||
|
|
||||||
QModelIndex mProxyIndex;
|
QModelIndexList mSelectedIndexes;
|
||||||
QModelIndex mIndex;
|
QModelIndex mClickedIndex;
|
||||||
CResourceEntry *mpEntry;
|
QModelIndex mClickedProxyIndex;
|
||||||
CVirtualDirectory *mpDirectory;
|
CResourceEntry *mpClickedEntry;
|
||||||
|
CVirtualDirectory *mpClickedDirectory;
|
||||||
// Actions
|
|
||||||
QAction *mpOpenAction;
|
|
||||||
QAction *mpOpenInExternalAppAction;
|
|
||||||
QAction *mpOpenInExplorerAction;
|
|
||||||
QAction *mpSelectFolderAction;
|
|
||||||
|
|
||||||
QAction *mpRenameAction;
|
|
||||||
QAction *mpShowReferencersAction;
|
|
||||||
QAction *mpShowDependenciesAction;
|
|
||||||
QAction *mpDeleteAction;
|
|
||||||
|
|
||||||
QAction *mpCopyNameAction;
|
|
||||||
QAction *mpCopyPathAction;
|
|
||||||
QAction *mpCopyIDAction;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CResourceTableContextMenu(CResourceBrowser *pBrowser, QTableView *pView, CResourceTableModel *pModel, CResourceProxyModel *pProxy);
|
CResourceTableContextMenu(CResourceBrowser *pBrowser, QTableView *pView, CResourceTableModel *pModel, CResourceProxyModel *pProxy);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void InitMenu();
|
||||||
void ShowMenu(const QPoint& rkPos);
|
void ShowMenu(const QPoint& rkPos);
|
||||||
|
|
||||||
// Menu Options
|
// Menu Options
|
||||||
|
|
|
@ -7,6 +7,7 @@ CResourceTableModel::CResourceTableModel(CResourceBrowser *pBrowser, QObject *pP
|
||||||
, mpCurrentDir(nullptr)
|
, mpCurrentDir(nullptr)
|
||||||
, mIsDisplayingUserEntryList(false)
|
, mIsDisplayingUserEntryList(false)
|
||||||
{
|
{
|
||||||
|
connect(pBrowser, SIGNAL(ResourceCreated(CResourceEntry*)), this, SLOT(CheckAddResource(CResourceEntry*)));
|
||||||
connect(pBrowser, SIGNAL(DirectoryCreated(CVirtualDirectory*)), this, SLOT(CheckAddDirectory(CVirtualDirectory*)));
|
connect(pBrowser, SIGNAL(DirectoryCreated(CVirtualDirectory*)), this, SLOT(CheckAddDirectory(CVirtualDirectory*)));
|
||||||
connect(pBrowser, SIGNAL(DirectoryAboutToBeDeleted(CVirtualDirectory*)), this, SLOT(CheckRemoveDirectory(CVirtualDirectory*)));
|
connect(pBrowser, SIGNAL(DirectoryAboutToBeDeleted(CVirtualDirectory*)), this, SLOT(CheckRemoveDirectory(CVirtualDirectory*)));
|
||||||
connect(pBrowser, SIGNAL(ResourceMoved(CResourceEntry*,CVirtualDirectory*,TString)), this, SLOT(OnResourceMoved(CResourceEntry*,CVirtualDirectory*,TString)));
|
connect(pBrowser, SIGNAL(ResourceMoved(CResourceEntry*,CVirtualDirectory*,TString)), this, SLOT(OnResourceMoved(CResourceEntry*,CVirtualDirectory*,TString)));
|
||||||
|
@ -155,7 +156,7 @@ Qt::DropActions CResourceTableModel::supportedDropActions() const
|
||||||
// ************ FUNCTIONALITY ************
|
// ************ FUNCTIONALITY ************
|
||||||
QModelIndex CResourceTableModel::GetIndexForEntry(CResourceEntry *pEntry) const
|
QModelIndex CResourceTableModel::GetIndexForEntry(CResourceEntry *pEntry) const
|
||||||
{
|
{
|
||||||
auto Iter = qBinaryFind(mEntries, pEntry);
|
auto Iter = std::find(mEntries.begin(), mEntries.end(), pEntry);
|
||||||
|
|
||||||
if (Iter == mEntries.end())
|
if (Iter == mEntries.end())
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
@ -289,6 +290,32 @@ void CResourceTableModel::RefreshAllIndices()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CResourceTableModel::CheckAddResource(CResourceEntry *pEntry)
|
||||||
|
{
|
||||||
|
if ( (mIsAssetListMode && pEntry->IsInDirectory(mpCurrentDir)) ||
|
||||||
|
(!mIsAssetListMode && pEntry->Directory() == mpCurrentDir) )
|
||||||
|
{
|
||||||
|
// Append to the end, let the proxy handle sorting
|
||||||
|
int NumRows = mDirectories.size() + mEntries.size();
|
||||||
|
beginInsertRows(QModelIndex(), NumRows, NumRows);
|
||||||
|
mEntries << pEntry;
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceTableModel::CheckRemoveResource(CResourceEntry *pEntry)
|
||||||
|
{
|
||||||
|
int Index = mEntries.indexOf(pEntry);
|
||||||
|
|
||||||
|
if (Index != -1)
|
||||||
|
{
|
||||||
|
Index += mDirectories.size();
|
||||||
|
beginRemoveRows(QModelIndex(), Index, Index);
|
||||||
|
mEntries.removeAt(Index);
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CResourceTableModel::CheckAddDirectory(CVirtualDirectory *pDir)
|
void CResourceTableModel::CheckAddDirectory(CVirtualDirectory *pDir)
|
||||||
{
|
{
|
||||||
if (pDir->Parent() == mpCurrentDir)
|
if (pDir->Parent() == mpCurrentDir)
|
||||||
|
|
|
@ -59,6 +59,8 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void RefreshAllIndices();
|
void RefreshAllIndices();
|
||||||
|
void CheckAddResource(CResourceEntry *pEntry);
|
||||||
|
void CheckRemoveResource(CResourceEntry *pEntry);
|
||||||
void CheckAddDirectory(CVirtualDirectory *pDir);
|
void CheckAddDirectory(CVirtualDirectory *pDir);
|
||||||
void CheckRemoveDirectory(CVirtualDirectory *pDir);
|
void CheckRemoveDirectory(CVirtualDirectory *pDir);
|
||||||
void OnResourceMoved(CResourceEntry *pEntry, CVirtualDirectory *pOldDir, TString OldName);
|
void OnResourceMoved(CResourceEntry *pEntry, CVirtualDirectory *pOldDir, TString OldName);
|
||||||
|
|
|
@ -14,9 +14,24 @@ CScanEditor::CScanEditor(CScan* pScan, QWidget* pParent /*= 0*/)
|
||||||
QString WindowTitle = "%APP_FULL_NAME% - Scan Editor - %1[*]";
|
QString WindowTitle = "%APP_FULL_NAME% - Scan Editor - %1[*]";
|
||||||
WindowTitle = WindowTitle.arg( TO_QSTRING(mpScan->Entry()->CookedAssetPath(true).GetFileName()) );
|
WindowTitle = WindowTitle.arg( TO_QSTRING(mpScan->Entry()->CookedAssetPath(true).GetFileName()) );
|
||||||
SET_WINDOWTITLE_APPVARS(WindowTitle);
|
SET_WINDOWTITLE_APPVARS(WindowTitle);
|
||||||
|
|
||||||
|
connect( mpUI->ActionSave, SIGNAL(toggled(bool)), this, SLOT(Save()) );
|
||||||
|
connect( mpUI->ActionSaveAndCook, SIGNAL(toggled(bool)), this, SLOT(SaveAndRepack()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
CScanEditor::~CScanEditor()
|
CScanEditor::~CScanEditor()
|
||||||
{
|
{
|
||||||
delete mpUI;
|
delete mpUI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CScanEditor::Save()
|
||||||
|
{
|
||||||
|
if (mpScan->Entry()->Save())
|
||||||
|
{
|
||||||
|
UndoStack().setClean();
|
||||||
|
setWindowModified(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@ class CScanEditor : public IEditor
|
||||||
public:
|
public:
|
||||||
explicit CScanEditor(CScan* pScan, QWidget* pParent = 0);
|
explicit CScanEditor(CScan* pScan, QWidget* pParent = 0);
|
||||||
~CScanEditor();
|
~CScanEditor();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual bool Save() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CSCANEDITOR_H
|
#endif // CSCANEDITOR_H
|
||||||
|
|
|
@ -46,7 +46,7 @@ CStringEditor::CStringEditor(CStringTable* pStringTable, QWidget* pParent)
|
||||||
, mpUI(new Ui::CStringEditor)
|
, mpUI(new Ui::CStringEditor)
|
||||||
, mpStringTable(pStringTable)
|
, mpStringTable(pStringTable)
|
||||||
, mCurrentLanguage(ELanguage::English)
|
, mCurrentLanguage(ELanguage::English)
|
||||||
, mCurrentStringIndex(0)
|
, mCurrentStringIndex(-1)
|
||||||
, mCurrentStringCount(0)
|
, mCurrentStringCount(0)
|
||||||
, mIsEditingStringName(false)
|
, mIsEditingStringName(false)
|
||||||
, mIsEditingStringData(false)
|
, mIsEditingStringData(false)
|
||||||
|
|
|
@ -17,6 +17,7 @@ WModifyTab::WModifyTab(CWorldEditor *pEditor, QWidget *pParent)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->PropertyView->InitColumnWidths(0.3f, 0.3f);
|
ui->PropertyView->InitColumnWidths(0.3f, 0.3f);
|
||||||
|
ui->PropertyView->SetEditor(pEditor);
|
||||||
|
|
||||||
mpWorldEditor = pEditor;
|
mpWorldEditor = pEditor;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue