Added support for deleting resources + minor fixes
This commit is contained in:
parent
56843e214d
commit
96c1aae27f
|
@ -1 +1 @@
|
|||
Subproject commit 5c3bfbe57f6ef8a300933afdc053a445cabd5c7c
|
||||
Subproject commit 3c6a40742551d7afd0737d1293d036df69f34ec6
|
|
@ -297,6 +297,15 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
|||
gpResourceStore = pOldStore;
|
||||
}
|
||||
|
||||
// Create hidden files directory, if needed
|
||||
TString HiddenDir = pProj->HiddenFilesDir();
|
||||
|
||||
if (!FileUtil::Exists(HiddenDir))
|
||||
{
|
||||
FileUtil::MakeDirectory(HiddenDir);
|
||||
FileUtil::MarkHidden(HiddenDir, true);
|
||||
}
|
||||
|
||||
pProj->mpAudioManager->LoadAssets();
|
||||
pProj->mpTweakManager->LoadTweaks();
|
||||
return pProj;
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
// Directory Handling
|
||||
inline TString ProjectRoot() const { return mProjectRoot; }
|
||||
inline TString ProjectPath() const { return mProjectRoot + FileUtil::SanitizeName(mProjectName, false) + ".prj"; }
|
||||
inline TString HiddenFilesDir() const { return mProjectRoot + ".project/"; }
|
||||
inline TString DiscDir(bool Relative) const { return Relative ? "Disc/" : mProjectRoot + "Disc/"; }
|
||||
inline TString PackagesDir(bool Relative) const { return Relative ? "Packages/" : mProjectRoot + "Packages/"; }
|
||||
inline TString ResourcesDir(bool Relative) const { return Relative ? "Resources/" : mProjectRoot + "Resources/"; }
|
||||
|
|
|
@ -113,6 +113,9 @@ bool CResourceEntry::LoadMetadata()
|
|||
|
||||
bool CResourceEntry::SaveMetadata(bool ForceSave /*= false*/)
|
||||
{
|
||||
// Make sure we aren't saving a deleted resource
|
||||
ASSERT( !HasFlag(EResEntryFlag::MarkedForDeletion) );
|
||||
|
||||
if (mMetadataDirty || ForceSave)
|
||||
{
|
||||
TString Path = MetadataFilePath();
|
||||
|
@ -491,6 +494,9 @@ bool CResourceEntry::CanMoveTo(const TString& rkDir, const TString& rkName)
|
|||
|
||||
bool CResourceEntry::MoveAndRename(const TString& rkDir, const TString& rkName, bool IsAutoGenDir /*= false*/, bool IsAutoGenName /*= false*/)
|
||||
{
|
||||
// Make sure we are not moving a deleted resource.
|
||||
ASSERT( !IsMarkedForDeletion() );
|
||||
|
||||
if (!CanMoveTo(rkDir, rkName)) return false;
|
||||
|
||||
// Store old paths
|
||||
|
@ -501,7 +507,15 @@ bool CResourceEntry::MoveAndRename(const TString& rkDir, const TString& rkName,
|
|||
TString OldMetaPath = MetadataFilePath();
|
||||
|
||||
// Set new directory and name
|
||||
CVirtualDirectory *pNewDir = mpStore->GetVirtualDirectory(rkDir, true);
|
||||
bool DirAlreadyExisted = true;
|
||||
CVirtualDirectory *pNewDir = mpStore->GetVirtualDirectory(rkDir, false);
|
||||
|
||||
if (!pNewDir)
|
||||
{
|
||||
pNewDir = mpStore->GetVirtualDirectory(rkDir, true);
|
||||
DirAlreadyExisted = false;
|
||||
}
|
||||
|
||||
if (pNewDir == mpDirectory && rkName == mName) return false;
|
||||
|
||||
// Check if we can legally move to this spot
|
||||
|
@ -580,7 +594,7 @@ bool CResourceEntry::MoveAndRename(const TString& rkDir, const TString& rkName,
|
|||
// If we succeeded, finish the move
|
||||
if (FSMoveSuccess)
|
||||
{
|
||||
if (mpDirectory != pOldDir)
|
||||
if (mpDirectory != pOldDir && pOldDir != nullptr)
|
||||
{
|
||||
FSMoveSuccess = pOldDir->RemoveChildResource(this);
|
||||
ASSERT(FSMoveSuccess == true); // this shouldn't be able to fail
|
||||
|
@ -605,7 +619,11 @@ bool CResourceEntry::MoveAndRename(const TString& rkDir, const TString& rkName,
|
|||
errorf("MOVE FAILED: %s", *MoveFailReason);
|
||||
mpDirectory = pOldDir;
|
||||
mName = OldName;
|
||||
mpStore->ConditionalDeleteDirectory(pNewDir, false);
|
||||
|
||||
if (!DirAlreadyExisted)
|
||||
{
|
||||
mpStore->ConditionalDeleteDirectory(pNewDir, true);
|
||||
}
|
||||
|
||||
if (FileUtil::Exists(NewRawPath))
|
||||
FileUtil::MoveFile(NewRawPath, OldRawPath);
|
||||
|
@ -627,6 +645,96 @@ bool CResourceEntry::Rename(const TString& rkName, bool IsAutoGenName /*= false*
|
|||
return MoveAndRename(mpDirectory->FullPath(), rkName, false, IsAutoGenName);
|
||||
}
|
||||
|
||||
void CResourceEntry::MarkDeleted(bool InDeleted)
|
||||
{
|
||||
// Flags resource for future deletion. "Deleted" resources remain in memory (which
|
||||
// allows them to easily be un-deleted) but cannot be looked up in the resource
|
||||
// store and will not save back out to the resource database. Their file data is
|
||||
// stored in a temporary directory, which allows them to be moved back if the user
|
||||
// un-does the deletion.
|
||||
if (IsMarkedForDeletion() != InDeleted)
|
||||
{
|
||||
SetFlagEnabled(EResEntryFlag::MarkedForDeletion, InDeleted);
|
||||
|
||||
// Restore old name/directory if un-deleting
|
||||
if (!InDeleted)
|
||||
{
|
||||
// Our directory path is stored in the Name field - see below for explanation
|
||||
int NameEnd = mName.IndexOf('|');
|
||||
ASSERT( NameEnd != -1 );
|
||||
|
||||
TString DirPath = mName.ChopFront(NameEnd + 1);
|
||||
mName = mName.ChopBack( mName.Size() - NameEnd);
|
||||
mpDirectory = mpStore->GetVirtualDirectory( DirPath, true );
|
||||
ASSERT( mpDirectory != nullptr );
|
||||
mpDirectory->AddChild("", this);
|
||||
}
|
||||
|
||||
TString CookedPath = CookedAssetPath();
|
||||
TString RawPath = RawAssetPath();
|
||||
TString MetaPath = MetadataFilePath();
|
||||
|
||||
TString PathBase = mpStore->DeletedResourcePath() + mID.ToString() + ".";
|
||||
TString DelCookedPath = PathBase + CookedExtension().ToString();
|
||||
TString DelRawPath = DelCookedPath + ".rsraw";
|
||||
TString DelMetaPath = DelCookedPath + ".rsmeta";
|
||||
|
||||
// If we are deleting...
|
||||
if (InDeleted)
|
||||
{
|
||||
// Temporarily store our directory path in the name string.
|
||||
// This is a hack, but we can't store the directory pointer because it may have been
|
||||
// deleted and remade by the user by the time the resource is un-deleted, which
|
||||
// means it is not safe to access later. Separating the name and the path with
|
||||
// the '|' character is safe because this character is not allowed in filenames
|
||||
// (which is enforced in FileUtil::IsValidName()).
|
||||
mName = mName + "|" + mpDirectory->FullPath();
|
||||
|
||||
// Remove from parent directory.
|
||||
mpDirectory->RemoveChildResource(this);
|
||||
mpDirectory = nullptr;
|
||||
|
||||
// Move any resource files out of the project into a temporary folder.
|
||||
FileUtil::MakeDirectory(DelMetaPath.GetFileDirectory());
|
||||
|
||||
if (FileUtil::Exists(MetaPath))
|
||||
{
|
||||
FileUtil::MoveFile(MetaPath, DelMetaPath);
|
||||
}
|
||||
if (FileUtil::Exists(RawPath))
|
||||
{
|
||||
FileUtil::MoveFile(RawPath, DelRawPath);
|
||||
}
|
||||
if (FileUtil::Exists(CookedPath))
|
||||
{
|
||||
FileUtil::MoveFile(CookedPath, DelCookedPath);
|
||||
}
|
||||
}
|
||||
// If we are un-deleting...
|
||||
else
|
||||
{
|
||||
// Move any resource files out of the temporary folder back into the project.
|
||||
FileUtil::MakeDirectory(MetaPath.GetFileDirectory());
|
||||
|
||||
if (FileUtil::Exists(DelMetaPath))
|
||||
{
|
||||
FileUtil::MoveFile(DelMetaPath, MetaPath);
|
||||
}
|
||||
if (FileUtil::Exists(DelRawPath))
|
||||
{
|
||||
FileUtil::MoveFile(DelRawPath, RawPath);
|
||||
}
|
||||
if (FileUtil::Exists(DelCookedPath))
|
||||
{
|
||||
FileUtil::MoveFile(DelCookedPath, CookedPath);
|
||||
}
|
||||
}
|
||||
|
||||
mpStore->SetCacheDirty();
|
||||
debugf("%s FOR DELETION: [%s] %s", InDeleted ? "MARKED" : "UNMARKED", *ID().ToString(), *CookedPath.GetFileName());
|
||||
}
|
||||
}
|
||||
|
||||
CGameProject* CResourceEntry::Project() const
|
||||
{
|
||||
return mpStore ? mpStore->Project() : nullptr;
|
||||
|
|
|
@ -21,6 +21,7 @@ enum class EResEntryFlag
|
|||
HasBeenModified = 0x00000008, // Resource has been modified and resaved by the user
|
||||
AutoResName = 0x00000010, // Resource name is auto-generated
|
||||
AutoResDir = 0x00000020, // Resource directory name is auto-generated
|
||||
MarkedForDeletion = 0x00000040, // Resource has been marked for deletion by the user
|
||||
};
|
||||
DECLARE_FLAGS(EResEntryFlag, FResEntryFlags)
|
||||
|
||||
|
@ -76,6 +77,7 @@ public:
|
|||
bool MoveAndRename(const TString& rkDir, const TString& rkName, bool IsAutoGenDir = false, bool IsAutoGenName = false);
|
||||
bool Move(const TString& rkDir, bool IsAutoGenDir = false);
|
||||
bool Rename(const TString& rkName, bool IsAutoGenName = false);
|
||||
void MarkDeleted(bool InDeleted);
|
||||
|
||||
CGameProject* Project() const;
|
||||
EGame Game() const;
|
||||
|
@ -90,6 +92,7 @@ public:
|
|||
inline void SetHidden(bool Hidden) { SetFlagEnabled(EResEntryFlag::Hidden, Hidden); }
|
||||
inline bool HasFlag(EResEntryFlag Flag) const { return mFlags.HasFlag(Flag); }
|
||||
inline bool IsHidden() const { return HasFlag(EResEntryFlag::Hidden); }
|
||||
inline bool IsMarkedForDeletion() const { return HasFlag(EResEntryFlag::MarkedForDeletion); }
|
||||
|
||||
inline bool IsLoaded() const { return mpResource != nullptr; }
|
||||
inline bool IsCategorized() const { return mpDirectory && !mpDirectory->FullPath().CaseInsensitiveCompare( mpStore->DefaultResourceDirPath() ); }
|
||||
|
|
|
@ -22,12 +22,16 @@ public:
|
|||
|
||||
virtual CResourceEntry* Next()
|
||||
{
|
||||
if (mIter != mpkStore->mResourceEntries.end())
|
||||
do
|
||||
{
|
||||
mpCurEntry = mIter->second;
|
||||
mIter++;
|
||||
if (mIter != mpkStore->mResourceEntries.end())
|
||||
{
|
||||
mpCurEntry = mIter->second;
|
||||
mIter++;
|
||||
}
|
||||
else mpCurEntry = nullptr;
|
||||
}
|
||||
else mpCurEntry = nullptr;
|
||||
while (mpCurEntry && mpCurEntry->IsMarkedForDeletion());
|
||||
|
||||
return mpCurEntry;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,22 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
|||
{
|
||||
// Serialize resources
|
||||
uint32 ResourceCount = mResourceEntries.size();
|
||||
|
||||
if (rArc.IsWriter())
|
||||
{
|
||||
// Make sure deleted resources aren't included in the count.
|
||||
// We can't use CResourceIterator because it skips MarkedForDeletion resources.
|
||||
for (auto Iter = mResourceEntries.begin(); Iter != mResourceEntries.end(); Iter++)
|
||||
{
|
||||
CResourceEntry* pEntry = Iter->second;
|
||||
|
||||
if (pEntry->IsMarkedForDeletion())
|
||||
{
|
||||
ResourceCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rArc << SerialParameter("ResourceCount", ResourceCount);
|
||||
|
||||
if (rArc.IsReader())
|
||||
|
@ -85,10 +101,13 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
|||
{
|
||||
for (CResourceIterator It(this); It; ++It)
|
||||
{
|
||||
if (rArc.ParamBegin("Resource", 0))
|
||||
if (!It->IsMarkedForDeletion())
|
||||
{
|
||||
It->SerializeEntryInfo(rArc, false);
|
||||
rArc.ParamEnd();
|
||||
if (rArc.ParamBegin("Resource", 0))
|
||||
{
|
||||
It->SerializeEntryInfo(rArc, false);
|
||||
rArc.ParamEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,18 +159,22 @@ bool CResourceStore::LoadDatabaseCache()
|
|||
}
|
||||
else
|
||||
{
|
||||
// Database is succesfully loaded at this point
|
||||
// Database is successfully loaded at this point
|
||||
if (mpProj)
|
||||
{
|
||||
ASSERT(mpProj->Game() == Reader.Game());
|
||||
}
|
||||
|
||||
mGame = Reader.Game();
|
||||
}
|
||||
|
||||
mGame = Reader.Game();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CResourceStore::SaveDatabaseCache()
|
||||
{
|
||||
TString Path = DatabasePath();
|
||||
debugf("Saving database cache...");
|
||||
|
||||
CBasicBinaryWriter Writer(Path, FOURCC('CACH'), 0, mGame);
|
||||
|
||||
|
@ -182,6 +205,14 @@ void CResourceStore::SetProject(CGameProject *pProj)
|
|||
mDatabasePath = mpProj->ProjectRoot();
|
||||
mpDatabaseRoot = new CVirtualDirectory(this);
|
||||
mGame = mpProj->Game();
|
||||
|
||||
// Clear deleted files from previous runs
|
||||
TString DeletedPath = DeletedResourcePath();
|
||||
|
||||
if (FileUtil::Exists(DeletedPath))
|
||||
{
|
||||
FileUtil::ClearDirectory(DeletedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,6 +246,14 @@ void CResourceStore::CloseProject()
|
|||
It = mResourceEntries.erase(It);
|
||||
}
|
||||
|
||||
// Clear deleted files from previous runs
|
||||
TString DeletedPath = DeletedResourcePath();
|
||||
|
||||
if (FileUtil::Exists(DeletedPath))
|
||||
{
|
||||
FileUtil::ClearDirectory(DeletedPath);
|
||||
}
|
||||
|
||||
delete mpDatabaseRoot;
|
||||
mpDatabaseRoot = nullptr;
|
||||
mpProj = nullptr;
|
||||
|
@ -256,12 +295,27 @@ TString CResourceStore::DefaultResourceDirPath() const
|
|||
return StaticDefaultResourceDirPath( mGame );
|
||||
}
|
||||
|
||||
TString CResourceStore::DeletedResourcePath() const
|
||||
{
|
||||
return mpProj->HiddenFilesDir() / "delete/";
|
||||
}
|
||||
|
||||
CResourceEntry* CResourceStore::FindEntry(const CAssetID& rkID) const
|
||||
{
|
||||
if (!rkID.IsValid()) return nullptr;
|
||||
auto Found = mResourceEntries.find(rkID);
|
||||
if (Found == mResourceEntries.end()) return nullptr;
|
||||
else return Found->second;
|
||||
if (rkID.IsValid())
|
||||
{
|
||||
auto Found = mResourceEntries.find(rkID);
|
||||
|
||||
if (Found != mResourceEntries.end())
|
||||
{
|
||||
CResourceEntry* pEntry = Found->second;
|
||||
|
||||
if (!pEntry->IsMarkedForDeletion())
|
||||
return pEntry;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CResourceEntry* CResourceStore::FindEntry(const TString& rkPath) const
|
||||
|
@ -411,6 +465,8 @@ CResourceEntry* CResourceStore::CreateNewResource(const CAssetID& rkID, EResourc
|
|||
{
|
||||
TrackLoadedResource(pEntry);
|
||||
}
|
||||
|
||||
debugf("CREATED NEW RESOURCE: [%s] %s", *rkID.ToString(), *pEntry->CookedAssetPath());
|
||||
}
|
||||
|
||||
else
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
void CreateVirtualDirectory(const TString& rkPath);
|
||||
void ConditionalDeleteDirectory(CVirtualDirectory *pDir, bool Recurse);
|
||||
TString DefaultResourceDirPath() const;
|
||||
TString DeletedResourcePath() const;
|
||||
|
||||
bool IsResourceRegistered(const CAssetID& rkID) const;
|
||||
CResourceEntry* CreateNewResource(const CAssetID& rkID, EResourceType Type, const TString& rkDir, const TString& rkName);
|
||||
|
|
|
@ -46,6 +46,28 @@ bool CVirtualDirectory::IsDescendantOf(CVirtualDirectory *pDir) const
|
|||
return (this == pDir) || (mpParent && pDir && (mpParent == pDir || mpParent->IsDescendantOf(pDir)));
|
||||
}
|
||||
|
||||
bool CVirtualDirectory::IsSafeToDelete() const
|
||||
{
|
||||
// Return false if we contain any referenced assets.
|
||||
for (CResourceEntry* pEntry : mResources)
|
||||
{
|
||||
if (pEntry->IsLoaded() && pEntry->Resource()->IsReferenced())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (CVirtualDirectory* pSubdir : mSubdirectories)
|
||||
{
|
||||
if (!pSubdir->IsSafeToDelete())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TString CVirtualDirectory::FullPath() const
|
||||
{
|
||||
if (IsRoot())
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
|
||||
bool IsEmpty(bool CheckFilesystem) const;
|
||||
bool IsDescendantOf(CVirtualDirectory *pDir) const;
|
||||
bool IsSafeToDelete() const;
|
||||
TString FullPath() const;
|
||||
TString AbsolutePath() const;
|
||||
CVirtualDirectory* GetRoot();
|
||||
|
|
|
@ -64,19 +64,6 @@ bool CTweakEditor::Save()
|
|||
}
|
||||
}
|
||||
|
||||
void CTweakEditor::showEvent(QShowEvent* pEvent)
|
||||
{
|
||||
// Perform first-time UI initialization
|
||||
// Property view cannot initialize correctly until first show due to window width not being configured
|
||||
if (!mHasBeenShown)
|
||||
{
|
||||
mpUI->PropertyView->InitColumnWidths(0.6f, 0.3f);
|
||||
mHasBeenShown = true;
|
||||
}
|
||||
|
||||
IEditor::showEvent(pEvent);
|
||||
}
|
||||
|
||||
void CTweakEditor::SetActiveTweakData(CTweakData* pTweakData)
|
||||
{
|
||||
for( int TweakIdx = 0; TweakIdx < mTweakAssets.size(); TweakIdx++ )
|
||||
|
|
|
@ -29,7 +29,6 @@ public:
|
|||
bool HasTweaks();
|
||||
|
||||
virtual bool Save() override;
|
||||
virtual void showEvent(QShowEvent* pEvent) override;
|
||||
|
||||
public slots:
|
||||
void SetActiveTweakData(CTweakData* pTweakData);
|
||||
|
|
|
@ -203,7 +203,9 @@ HEADERS += \
|
|||
Undo/CEditIntrinsicPropertyCommand.h \
|
||||
Undo/TSerializeUndoCommand.h \
|
||||
StringEditor/CStringMimeData.h \
|
||||
ScanEditor/CScanEditor.h
|
||||
ScanEditor/CScanEditor.h \
|
||||
Undo/ICreateDeleteResourceCommand.h \
|
||||
Undo/CSaveStoreCommand.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
|
|
@ -79,8 +79,20 @@ bool CPropertyView::event(QEvent *pEvent)
|
|||
pEvent->ignore();
|
||||
return true;
|
||||
}
|
||||
else if (pEvent->type() == QEvent::Resize && !isVisible())
|
||||
{
|
||||
resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
else return QTreeView::event(pEvent);
|
||||
return QTreeView::event(pEvent);
|
||||
}
|
||||
|
||||
int CPropertyView::sizeHintForColumn(int Column) const
|
||||
{
|
||||
if (Column == 0)
|
||||
return width() * 0.6f;
|
||||
else
|
||||
return width() * 0.4f;
|
||||
}
|
||||
|
||||
void CPropertyView::SetEditor(IEditor* pEditor)
|
||||
|
@ -88,13 +100,6 @@ void CPropertyView::SetEditor(IEditor* pEditor)
|
|||
mpDelegate->SetEditor(pEditor);
|
||||
}
|
||||
|
||||
void CPropertyView::InitColumnWidths(float NameColumnPercentage, float ValueColumnPercentage)
|
||||
{
|
||||
header()->resizeSection(0, width() * NameColumnPercentage);
|
||||
header()->resizeSection(1, width() * ValueColumnPercentage);
|
||||
header()->setSectionResizeMode(1, QHeaderView::Fixed);
|
||||
}
|
||||
|
||||
void CPropertyView::ClearProperties()
|
||||
{
|
||||
mpObject = nullptr;
|
||||
|
|
|
@ -25,8 +25,9 @@ public:
|
|||
CPropertyView(QWidget* pParent = 0);
|
||||
void setModel(QAbstractItemModel* pModel);
|
||||
bool event(QEvent* pEvent);
|
||||
int sizeHintForColumn(int Column) const;
|
||||
|
||||
void SetEditor(IEditor* pEditor);
|
||||
void InitColumnWidths(float NameColumnPercentage, float ValueColumnPercentage);
|
||||
void ClearProperties();
|
||||
void SetIntrinsicProperties(CStructRef InProperties);
|
||||
void SetInstance(CScriptObject* pObj);
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
#include "Editor/Undo/CMoveResourceCommand.h"
|
||||
#include "Editor/Undo/CRenameDirectoryCommand.h"
|
||||
#include "Editor/Undo/CRenameResourceCommand.h"
|
||||
#include "Editor/Undo/CSaveStoreCommand.h"
|
||||
#include "Editor/Undo/ICreateDeleteDirectoryCommand.h"
|
||||
#include "Editor/Undo/ICreateDeleteResourceCommand.h"
|
||||
#include <Core/GameProject/AssetNameGeneration.h>
|
||||
#include <Core/GameProject/CAssetNameMap.h>
|
||||
|
||||
|
@ -346,7 +348,11 @@ bool CResourceBrowser::RenameResource(CResourceEntry *pEntry, const TString& rkN
|
|||
}
|
||||
|
||||
// Everything seems to be valid; proceed with the rename
|
||||
mUndoStack.beginMacro("Rename Resource");
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.push( new CRenameResourceCommand(pEntry, rkNewName) );
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.endMacro();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -369,7 +375,11 @@ bool CResourceBrowser::RenameDirectory(CVirtualDirectory *pDir, const TString& r
|
|||
}
|
||||
|
||||
// No conflicts, proceed with the rename
|
||||
mUndoStack.beginMacro("Rename Directory");
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.push( new CRenameDirectoryCommand(pDir, rkNewName) );
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.endMacro();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -431,6 +441,7 @@ bool CResourceBrowser::MoveResources(const QList<CResourceEntry*>& rkResources,
|
|||
if (!ValidResources.isEmpty() || !ValidDirs.isEmpty())
|
||||
{
|
||||
mUndoStack.beginMacro("Move Resources");
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
|
||||
foreach (CVirtualDirectory *pDir, ValidDirs)
|
||||
mUndoStack.push( new CMoveDirectoryCommand(mpStore, pDir, pNewDir) );
|
||||
|
@ -438,43 +449,59 @@ bool CResourceBrowser::MoveResources(const QList<CResourceEntry*>& rkResources,
|
|||
foreach (CResourceEntry *pEntry, ValidResources)
|
||||
mUndoStack.push( new CMoveResourceCommand(pEntry, pNewDir) );
|
||||
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.endMacro();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CResourceEntry* CResourceBrowser::CreateNewResource(EResourceType Type)
|
||||
CResourceEntry* CResourceBrowser::CreateNewResource(EResourceType Type,
|
||||
TString Name /*= ""*/,
|
||||
CVirtualDirectory* pDir /*= nullptr*/,
|
||||
CAssetID ID /*= CAssetID()*/)
|
||||
{
|
||||
// Create new asset ID. Sanity check to make sure the ID is unused.
|
||||
CAssetID NewAssetID;
|
||||
|
||||
while (!NewAssetID.IsValid() || mpStore->FindEntry(NewAssetID) != nullptr)
|
||||
if (!pDir)
|
||||
{
|
||||
NewAssetID = CAssetID::RandomID( mpStore->Game() );
|
||||
pDir = mpSelectedDir;
|
||||
}
|
||||
|
||||
// Create new asset ID. Sanity check to make sure the ID is unused.
|
||||
while (!ID.IsValid() || mpStore->FindEntry(ID) != nullptr)
|
||||
{
|
||||
ID = CAssetID::RandomID( mpStore->Game() );
|
||||
}
|
||||
|
||||
// Boring generic default name - user will immediately be prompted to change this
|
||||
TString BaseName = TString::Format(
|
||||
TString BaseName = Name;
|
||||
|
||||
if (BaseName.IsEmpty())
|
||||
{
|
||||
BaseName = TString::Format(
|
||||
"New %s", *CResTypeInfo::FindTypeInfo(Type)->TypeName()
|
||||
);
|
||||
}
|
||||
|
||||
TString Name = BaseName;
|
||||
Name = BaseName;
|
||||
int Num = 0;
|
||||
|
||||
while (mpSelectedDir->FindChildResource(Name, Type) != nullptr)
|
||||
while (pDir->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();
|
||||
CResourceEntry* pEntry = mpStore->CreateNewResource(ID, Type, pDir->FullPath(), Name);
|
||||
|
||||
emit ResourceCreated(pEntry);
|
||||
// Push undo command
|
||||
mUndoStack.beginMacro("Create Resource");
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.push( new CCreateResourceCommand(pEntry) );
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.endMacro();
|
||||
|
||||
pEntry->Save();
|
||||
|
||||
// Select new resource so user can enter a name
|
||||
QModelIndex Index = mpModel->GetIndexForEntry(pEntry);
|
||||
|
@ -617,8 +644,12 @@ bool CResourceBrowser::CreateDirectory()
|
|||
}
|
||||
|
||||
// Push create command to actually create the directory
|
||||
mUndoStack.beginMacro("Create Directory");
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
CCreateDirectoryCommand *pCmd = new CCreateDirectoryCommand(mpStore, mpSelectedDir->FullPath(), DirName);
|
||||
mUndoStack.push(pCmd);
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.endMacro();
|
||||
|
||||
// Now fetch the new directory and start editing it so the user can enter a name
|
||||
CVirtualDirectory *pNewDir = mpSelectedDir->FindChildDirectory(DirName, false);
|
||||
|
@ -641,28 +672,101 @@ bool CResourceBrowser::CreateDirectory()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CResourceBrowser::DeleteDirectories(const QList<CVirtualDirectory*>& rkDirs)
|
||||
bool CResourceBrowser::Delete(QVector<CResourceEntry*> Resources, QVector<CVirtualDirectory*> Directories)
|
||||
{
|
||||
QList<CVirtualDirectory*> DeletableDirs;
|
||||
// Don't delete any resources/directories that are still referenced.
|
||||
// This is kind of a hack but there's no good way to clear out these references right now.
|
||||
QString ErrorPaths;
|
||||
|
||||
foreach (CVirtualDirectory *pDir, rkDirs)
|
||||
for (int DirIdx = 0; DirIdx < Directories.size(); DirIdx++)
|
||||
{
|
||||
if (pDir && pDir->IsEmpty(true))
|
||||
DeletableDirs << pDir;
|
||||
if (!Directories[DirIdx]->IsSafeToDelete())
|
||||
{
|
||||
ErrorPaths += TO_QSTRING( Directories[DirIdx]->FullPath() ) + '\n';
|
||||
Directories.removeAt(DirIdx);
|
||||
DirIdx--;
|
||||
}
|
||||
}
|
||||
|
||||
if (DeletableDirs.size() > 0)
|
||||
for (int ResIdx = 0; ResIdx < Resources.size(); ResIdx++)
|
||||
{
|
||||
mUndoStack.beginMacro("Delete Directories");
|
||||
if (Resources[ResIdx]->IsLoaded() && Resources[ResIdx]->Resource()->IsReferenced())
|
||||
{
|
||||
ErrorPaths += TO_QSTRING( Resources[ResIdx]->CookedAssetPath(true) ) + '\n';
|
||||
Resources.removeAt(ResIdx);
|
||||
ResIdx--;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CVirtualDirectory *pDir, DeletableDirs)
|
||||
if (!ErrorPaths.isEmpty())
|
||||
{
|
||||
// Remove trailing newline
|
||||
ErrorPaths.chop(1);
|
||||
UICommon::ErrorMsg(this, QString("The following resources/directories are still referenced and cannot be deleted:\n\n%1")
|
||||
.arg(ErrorPaths));
|
||||
}
|
||||
|
||||
// Gather a complete list of resources in subdirectories
|
||||
for (int DirIdx = 0; DirIdx < Directories.size(); DirIdx++)
|
||||
{
|
||||
CVirtualDirectory* pDir = Directories[DirIdx];
|
||||
Resources.reserve( Resources.size() + pDir->NumResources() );
|
||||
Directories.reserve( Directories.size() + pDir->NumSubdirectories() );
|
||||
|
||||
for (uint ResourceIdx = 0; ResourceIdx < pDir->NumResources(); ResourceIdx++)
|
||||
Resources << pDir->ResourceByIndex(ResourceIdx);
|
||||
|
||||
for (uint SubdirIdx = 0; SubdirIdx < pDir->NumSubdirectories(); SubdirIdx++)
|
||||
Directories << pDir->SubdirectoryByIndex(SubdirIdx);
|
||||
}
|
||||
|
||||
// Exit if we have nothing to do.
|
||||
if (Resources.isEmpty() && Directories.isEmpty())
|
||||
return false;
|
||||
|
||||
// Allow the user to confirm before proceeding.
|
||||
QString ConfirmMsg = QString("Are you sure you want to permanently delete ");
|
||||
|
||||
if (Resources.size() > 0)
|
||||
{
|
||||
ConfirmMsg += QString("%1 resource%2").arg(Resources.size()).arg(Resources.size() == 1 ? "" : "s");
|
||||
|
||||
if (Directories.size() > 0)
|
||||
{
|
||||
ConfirmMsg += " and ";
|
||||
}
|
||||
}
|
||||
if (Directories.size() > 0)
|
||||
{
|
||||
ConfirmMsg += QString("%1 %2").arg(Directories.size()).arg(Directories.size() == 1 ? "directory" : "directories");
|
||||
}
|
||||
ConfirmMsg += "?";
|
||||
|
||||
if (UICommon::YesNoQuestion(this, "Warning", ConfirmMsg))
|
||||
{
|
||||
// Note that the undo stack will undo actions in the reverse order they are pushed
|
||||
// So we need to push commands last that we want to be undone first
|
||||
// We want to delete subdirectories first, then parent directories, then resources
|
||||
mUndoStack.beginMacro("Delete");
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
|
||||
// Delete resources first.
|
||||
foreach (CResourceEntry* pEntry, Resources)
|
||||
mUndoStack.push( new CDeleteResourceCommand(pEntry) );
|
||||
|
||||
// Now delete directories in reverse order (so subdirectories delete first)
|
||||
for (int DirIdx = Directories.size()-1; DirIdx >= 0; DirIdx--)
|
||||
{
|
||||
CVirtualDirectory* pDir = Directories[DirIdx];
|
||||
mUndoStack.push( new CDeleteDirectoryCommand(mpStore, pDir->Parent()->FullPath(), pDir->Name()) );
|
||||
}
|
||||
|
||||
mUndoStack.push( new CSaveStoreCommand(mpStore) );
|
||||
mUndoStack.endMacro();
|
||||
return true;
|
||||
}
|
||||
|
||||
else return false;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void CResourceBrowser::OnSearchStringChanged(QString SearchString)
|
||||
|
|
|
@ -72,7 +72,10 @@ public:
|
|||
bool RenameDirectory(CVirtualDirectory *pDir, const TString& rkNewName);
|
||||
bool MoveResources(const QList<CResourceEntry*>& rkResources, const QList<CVirtualDirectory*>& rkDirectories, CVirtualDirectory *pNewDir);
|
||||
|
||||
CResourceEntry* CreateNewResource(EResourceType Type);
|
||||
CResourceEntry* CreateNewResource(EResourceType Type,
|
||||
TString Name = "",
|
||||
CVirtualDirectory* pDir = nullptr,
|
||||
CAssetID ID = CAssetID());
|
||||
|
||||
// Interface
|
||||
bool eventFilter(QObject *pWatched, QEvent *pEvent);
|
||||
|
@ -94,7 +97,7 @@ public slots:
|
|||
void OnSortModeChanged(int Index);
|
||||
void OnCreateAssetAction();
|
||||
bool CreateDirectory();
|
||||
bool DeleteDirectories(const QList<CVirtualDirectory*>& rkDirs);
|
||||
bool Delete(QVector<CResourceEntry*> Resources, QVector<CVirtualDirectory*> Directories);
|
||||
void OnSearchStringChanged(QString SearchString);
|
||||
void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex);
|
||||
void OnDoubleClickTable(QModelIndex Index);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include "CResourceTableContextMenu.h"
|
||||
#include "CResourceBrowser.h"
|
||||
#include "Editor/CEditorApplication.h"
|
||||
|
||||
#include <Core/Resource/Scan/CScan.h>
|
||||
|
||||
#include <QClipboard>
|
||||
|
||||
CResourceTableContextMenu::CResourceTableContextMenu(CResourceBrowser *pBrowser, QTableView *pView, CResourceTableModel *pModel, CResourceProxyModel *pProxy)
|
||||
|
@ -70,6 +73,17 @@ void CResourceTableContextMenu::InitMenu()
|
|||
|
||||
QMenu* pCreate = addMenu("Create...");
|
||||
mpBrowser->AddCreateAssetMenuActions(pCreate);
|
||||
|
||||
// Asset-specific
|
||||
if (mpClickedEntry)
|
||||
{
|
||||
switch (mpClickedEntry->ResourceType())
|
||||
{
|
||||
case EResourceType::StringTable:
|
||||
addAction("Create Scan", this, SLOT(CreateSCAN()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CResourceTableContextMenu::ShowMenu(const QPoint& rkPos)
|
||||
|
@ -198,43 +212,18 @@ void CResourceTableContextMenu::ShowDependencies()
|
|||
void CResourceTableContextMenu::Delete()
|
||||
{
|
||||
// Create confirmation message
|
||||
uint NumResources = 0, NumDirectories = 0;
|
||||
QVector<CResourceEntry*> Resources;
|
||||
QVector<CVirtualDirectory*> Directories;
|
||||
|
||||
foreach (const QModelIndex& kIndex, mSelectedIndexes)
|
||||
{
|
||||
if (mpModel->IsIndexDirectory(kIndex))
|
||||
NumDirectories++;
|
||||
Directories << mpModel->IndexDirectory(kIndex);
|
||||
else
|
||||
NumResources++;
|
||||
Resources << mpModel->IndexEntry(kIndex);
|
||||
}
|
||||
|
||||
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;
|
||||
List << mpClickedDirectory;
|
||||
mpBrowser->DeleteDirectories(List);
|
||||
}
|
||||
mpBrowser->Delete(Resources, Directories);
|
||||
}
|
||||
|
||||
void CResourceTableContextMenu::CopyName()
|
||||
|
@ -258,3 +247,22 @@ void CResourceTableContextMenu::CopyID()
|
|||
ASSERT(mpClickedEntry);
|
||||
gpEdApp->clipboard()->setText( TO_QSTRING(mpClickedEntry->ID().ToString()) );
|
||||
}
|
||||
|
||||
|
||||
// Asset Specific
|
||||
void CResourceTableContextMenu::CreateSCAN()
|
||||
{
|
||||
// Create a SCAN asset to go along with a selected STRG asset
|
||||
ASSERT( mpClickedEntry && mpClickedEntry->ResourceType() == EResourceType::StringTable );
|
||||
|
||||
CResourceEntry* pNewEntry = mpBrowser->CreateNewResource(EResourceType::Scan,
|
||||
mpClickedEntry->Name(),
|
||||
mpClickedEntry->Directory());
|
||||
|
||||
if (pNewEntry)
|
||||
{
|
||||
CScan* pScan = (CScan*) pNewEntry->Load();
|
||||
pScan->ScanStringPropertyRef().Set( mpClickedEntry->ID() );
|
||||
pNewEntry->Save();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ public slots:
|
|||
void CopyName();
|
||||
void CopyPath();
|
||||
void CopyID();
|
||||
|
||||
// Asset Specific
|
||||
void CreateSCAN();
|
||||
};
|
||||
|
||||
#endif // CRESOURCETABLECONTEXTMENU_H
|
||||
|
|
|
@ -8,6 +8,7 @@ CResourceTableModel::CResourceTableModel(CResourceBrowser *pBrowser, QObject *pP
|
|||
, mIsDisplayingUserEntryList(false)
|
||||
{
|
||||
connect(pBrowser, SIGNAL(ResourceCreated(CResourceEntry*)), this, SLOT(CheckAddResource(CResourceEntry*)));
|
||||
connect(pBrowser, SIGNAL(ResourceAboutToBeDeleted(CResourceEntry*)), this, SLOT(CheckRemoveResource(CResourceEntry*)));
|
||||
connect(pBrowser, SIGNAL(DirectoryCreated(CVirtualDirectory*)), this, SLOT(CheckAddDirectory(CVirtualDirectory*)));
|
||||
connect(pBrowser, SIGNAL(DirectoryAboutToBeDeleted(CVirtualDirectory*)), this, SLOT(CheckRemoveDirectory(CVirtualDirectory*)));
|
||||
connect(pBrowser, SIGNAL(ResourceMoved(CResourceEntry*,CVirtualDirectory*,TString)), this, SLOT(OnResourceMoved(CResourceEntry*,CVirtualDirectory*,TString)));
|
||||
|
@ -309,8 +310,8 @@ void CResourceTableModel::CheckRemoveResource(CResourceEntry *pEntry)
|
|||
|
||||
if (Index != -1)
|
||||
{
|
||||
Index += mDirectories.size();
|
||||
beginRemoveRows(QModelIndex(), Index, Index);
|
||||
int RowIndex = Index + mDirectories.size();
|
||||
beginRemoveRows(QModelIndex(), RowIndex, RowIndex);
|
||||
mEntries.removeAt(Index);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
|
|
@ -44,34 +44,20 @@ void CResourceTableView::DeleteSelected()
|
|||
// Figure out which indices can actually be deleted
|
||||
CResourceProxyModel *pProxy = static_cast<CResourceProxyModel*>(model());
|
||||
CResourceTableModel *pModel = static_cast<CResourceTableModel*>(pProxy->sourceModel());
|
||||
QList<CVirtualDirectory*> DirsToDelete;
|
||||
bool HasNonEmptyDirSelected = false;
|
||||
QVector<CResourceEntry*> ResourcesToDelete;
|
||||
QVector<CVirtualDirectory*> DirsToDelete;
|
||||
|
||||
foreach (QModelIndex Index, List)
|
||||
{
|
||||
QModelIndex SourceIndex = pProxy->mapToSource(Index);
|
||||
|
||||
if (pModel->IsIndexDirectory(SourceIndex))
|
||||
{
|
||||
CVirtualDirectory *pDir = pModel->IndexDirectory(SourceIndex);
|
||||
DirsToDelete << pModel->IndexDirectory(SourceIndex);
|
||||
else
|
||||
ResourcesToDelete << pModel->IndexEntry(SourceIndex);
|
||||
|
||||
if (pDir)
|
||||
{
|
||||
if (pDir->IsEmpty(true))
|
||||
DirsToDelete << pDir;
|
||||
else
|
||||
HasNonEmptyDirSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Let the user know if all selected directories are non empty
|
||||
if (HasNonEmptyDirSelected && DirsToDelete.isEmpty())
|
||||
{
|
||||
UICommon::ErrorMsg(parentWidget(), "Unable to delete; one or more of the selected directories is non-empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete
|
||||
gpEdApp->ResourceBrowser()->DeleteDirectories(DirsToDelete);
|
||||
gpEdApp->ResourceBrowser()->Delete(ResourcesToDelete, DirsToDelete);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef CSAVESTORECOMMAND_H
|
||||
#define CSAVESTORECOMMAND_H
|
||||
|
||||
#include "IUndoCommand.h"
|
||||
#include <Core/GameProject/CResourceStore.h>
|
||||
|
||||
/** Command that calls ConditionalSaveStore on a resource store.
|
||||
* This is meant to be added to undo macros that modify the resource store
|
||||
* in order to trigger the store to resave when the macro is complete.
|
||||
*/
|
||||
class CSaveStoreCommand : public IUndoCommand
|
||||
{
|
||||
CResourceStore* mpStore;
|
||||
|
||||
public:
|
||||
CSaveStoreCommand(CResourceStore* pInStore)
|
||||
: IUndoCommand("Save Store")
|
||||
, mpStore(pInStore)
|
||||
{}
|
||||
|
||||
virtual void undo() override { mpStore->ConditionalSaveStore(); }
|
||||
virtual void redo() override { mpStore->ConditionalSaveStore(); }
|
||||
virtual bool AffectsCleanState() const override { return false; }
|
||||
};
|
||||
|
||||
#endif // CSAVESTORECOMMAND_H
|
|
@ -16,8 +16,8 @@ protected:
|
|||
CVirtualDirectory *mpDir;
|
||||
|
||||
public:
|
||||
ICreateDeleteDirectoryCommand(CResourceStore *pStore, TString ParentPath, TString DirName)
|
||||
: IUndoCommand("Create Directory")
|
||||
ICreateDeleteDirectoryCommand(const QString& rkText, CResourceStore *pStore, TString ParentPath, TString DirName)
|
||||
: IUndoCommand(rkText)
|
||||
, mpStore(pStore)
|
||||
, mParentPath(ParentPath)
|
||||
, mDirName(DirName)
|
||||
|
@ -64,7 +64,7 @@ class CCreateDirectoryCommand : public ICreateDeleteDirectoryCommand
|
|||
{
|
||||
public:
|
||||
CCreateDirectoryCommand(CResourceStore *pStore, TString ParentPath, TString DirName)
|
||||
: ICreateDeleteDirectoryCommand(pStore, ParentPath, DirName)
|
||||
: ICreateDeleteDirectoryCommand("Create Directory", pStore, ParentPath, DirName)
|
||||
{}
|
||||
|
||||
void undo() { DoDelete(); }
|
||||
|
@ -75,7 +75,7 @@ class CDeleteDirectoryCommand : public ICreateDeleteDirectoryCommand
|
|||
{
|
||||
public:
|
||||
CDeleteDirectoryCommand(CResourceStore *pStore, TString ParentPath, TString DirName)
|
||||
: ICreateDeleteDirectoryCommand(pStore, ParentPath, DirName)
|
||||
: ICreateDeleteDirectoryCommand("Delete Directory", pStore, ParentPath, DirName)
|
||||
{
|
||||
mpDir = pStore->GetVirtualDirectory(ParentPath + DirName, false);
|
||||
ASSERT(mpDir);
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef ICREATEDELETERESOURCECOMMAND_H
|
||||
#define ICREATEDELETERESOURCECOMMAND_H
|
||||
|
||||
#include "IUndoCommand.h"
|
||||
#include "Editor/CEditorApplication.h"
|
||||
#include "Editor/ResourceBrowser/CResourceBrowser.h"
|
||||
#include <Core/GameProject/CResourceEntry.h>
|
||||
#include <Core/GameProject/CResourceStore.h>
|
||||
|
||||
class ICreateDeleteResourceCommand : public IUndoCommand
|
||||
{
|
||||
protected:
|
||||
CResourceEntry* mpEntry;
|
||||
TString mDirPath;
|
||||
|
||||
public:
|
||||
ICreateDeleteResourceCommand(const QString& kText, CResourceEntry* pEntry)
|
||||
: IUndoCommand(kText)
|
||||
, mpEntry(pEntry)
|
||||
{
|
||||
mDirPath = mpEntry->Directory()->FullPath();
|
||||
}
|
||||
|
||||
void DoCreate()
|
||||
{
|
||||
CVirtualDirectory* pDir = mpEntry->ResourceStore()->GetVirtualDirectory(mDirPath, true);
|
||||
gpEdApp->ResourceBrowser()->ResourceAboutToBeCreated(pDir);
|
||||
|
||||
// restore directory and undelete
|
||||
mpEntry->MarkDeleted(false);
|
||||
|
||||
gpEdApp->ResourceBrowser()->ResourceCreated(mpEntry);
|
||||
}
|
||||
|
||||
void DoDelete()
|
||||
{
|
||||
gpEdApp->ResourceBrowser()->ResourceAboutToBeDeleted(mpEntry);
|
||||
|
||||
// save directory and delete
|
||||
mpEntry->MarkDeleted(true);
|
||||
|
||||
gpEdApp->ResourceBrowser()->ResourceDeleted();
|
||||
}
|
||||
|
||||
bool AffectsCleanState() const { return false; }
|
||||
};
|
||||
|
||||
class CCreateResourceCommand : public ICreateDeleteResourceCommand
|
||||
{
|
||||
public:
|
||||
CCreateResourceCommand(CResourceEntry* pEntry)
|
||||
: ICreateDeleteResourceCommand("Create Resource", pEntry)
|
||||
{}
|
||||
|
||||
void undo() { DoDelete(); }
|
||||
void redo() { DoCreate(); }
|
||||
};
|
||||
|
||||
class CDeleteResourceCommand : public ICreateDeleteResourceCommand
|
||||
{
|
||||
public:
|
||||
CDeleteResourceCommand(CResourceEntry* pEntry)
|
||||
: ICreateDeleteResourceCommand("Delete Resource", pEntry)
|
||||
{}
|
||||
|
||||
void undo() { DoCreate(); }
|
||||
void redo() { DoDelete(); }
|
||||
};
|
||||
|
||||
#endif // ICREATEDELETERESOURCECOMMAND_H
|
|
@ -16,7 +16,6 @@ WModifyTab::WModifyTab(CWorldEditor *pEditor, QWidget *pParent)
|
|||
, mIsPicking(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->PropertyView->InitColumnWidths(0.3f, 0.3f);
|
||||
ui->PropertyView->SetEditor(pEditor);
|
||||
|
||||
mpWorldEditor = pEditor;
|
||||
|
|
|
@ -36795,7 +36795,7 @@
|
|||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xC915686F" Type="float"/>
|
||||
<Value Name="Unknown"/>
|
||||
<Value Name="DeathBallDamageDelay"/>
|
||||
</Element>
|
||||
<Element>
|
||||
<Key ID="0xC91B0946" Type="int"/>
|
||||
|
|
Loading…
Reference in New Issue