mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-05-30 03:01:32 +00:00
Added ability to rename resources/directories in the resource table view
This commit is contained in:
parent
932e2bff7a
commit
db277d7a15
@ -112,9 +112,8 @@ bool MoveFile(const TString& rkOldPath, const TString& rkNewPath)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: check return value? Docs don't say what the return value actually is
|
int Result = rename(*rkOldPath, *rkNewPath);
|
||||||
rename(*rkOldPath, *rkNewPath);
|
return (Result == 0);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveDirectory(const TString& rkOldPath, const TString& rkNewPath)
|
bool MoveDirectory(const TString& rkOldPath, const TString& rkNewPath)
|
||||||
@ -131,9 +130,8 @@ bool MoveDirectory(const TString& rkOldPath, const TString& rkNewPath)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: check return value? Docs don't say what the return value actually is
|
int Result = rename(*rkOldPath, *rkNewPath);
|
||||||
rename(*rkOldPath, *rkNewPath);
|
return (Result == 0);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeleteFile(const TString& rkFilePath)
|
bool DeleteFile(const TString& rkFilePath)
|
||||||
@ -305,8 +303,13 @@ TString SimplifyRelativePath(const TString& rkPath)
|
|||||||
return Out;
|
return Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 MaxFileNameLength()
|
||||||
|
{
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
static const char gskIllegalNameChars[] = {
|
static const char gskIllegalNameChars[] = {
|
||||||
'<', '>', '\"', '/', '\\', '|', '?', '*'
|
'<', '>', '\"', '/', '\\', '|', '?', '*', ':'
|
||||||
};
|
};
|
||||||
|
|
||||||
TString SanitizeName(TString Name, bool Directory, bool RootDir /*= false*/)
|
TString SanitizeName(TString Name, bool Directory, bool RootDir /*= false*/)
|
||||||
@ -316,8 +319,6 @@ TString SanitizeName(TString Name, bool Directory, bool RootDir /*= false*/)
|
|||||||
return Name;
|
return Name;
|
||||||
|
|
||||||
// Remove illegal characters from path
|
// Remove illegal characters from path
|
||||||
u32 NumIllegalChars = sizeof(gskIllegalNameChars) / sizeof(char);
|
|
||||||
|
|
||||||
for (u32 iChr = 0; iChr < Name.Size(); iChr++)
|
for (u32 iChr = 0; iChr < Name.Size(); iChr++)
|
||||||
{
|
{
|
||||||
char Chr = Name[iChr];
|
char Chr = Name[iChr];
|
||||||
@ -326,21 +327,11 @@ TString SanitizeName(TString Name, bool Directory, bool RootDir /*= false*/)
|
|||||||
if (Chr >= 0 && Chr <= 31)
|
if (Chr >= 0 && Chr <= 31)
|
||||||
Remove = true;
|
Remove = true;
|
||||||
|
|
||||||
// For root, allow colon only as the last character of the name
|
// Allow colon only as the last character of root
|
||||||
else if (Chr == ':' && (!RootDir || iChr != Name.Size() - 1))
|
bool IsLegalColon = (Chr == ':' && RootDir && iChr == Name.Size() - 1);
|
||||||
Remove = true;
|
|
||||||
|
|
||||||
else
|
if (!IsLegalColon && !IsValidFileNameCharacter(Chr))
|
||||||
{
|
Remove = true;
|
||||||
for (u32 iBan = 0; iBan < NumIllegalChars; iBan++)
|
|
||||||
{
|
|
||||||
if (Chr == gskIllegalNameChars[iBan])
|
|
||||||
{
|
|
||||||
Remove = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Remove)
|
if (Remove)
|
||||||
{
|
{
|
||||||
@ -376,9 +367,9 @@ TString SanitizeName(TString Name, bool Directory, bool RootDir /*= false*/)
|
|||||||
Name = Name.ChopFront(NumLeadingSpaces);
|
Name = Name.ChopFront(NumLeadingSpaces);
|
||||||
|
|
||||||
// Ensure the name is below the character limit
|
// Ensure the name is below the character limit
|
||||||
if (Name.Size() > 255)
|
if (Name.Size() > MaxFileNameLength())
|
||||||
{
|
{
|
||||||
u32 ChopNum = Name.Size() - 255;
|
u32 ChopNum = Name.Size() - MaxFileNameLength();
|
||||||
Name = Name.ChopBack(ChopNum);
|
Name = Name.ChopBack(ChopNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,6 +397,22 @@ TString SanitizePath(TString Path, bool Directory)
|
|||||||
return Path;
|
return Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsValidFileNameCharacter(char Chr)
|
||||||
|
{
|
||||||
|
static const u32 skNumIllegalChars = sizeof(gskIllegalNameChars) / sizeof(char);
|
||||||
|
|
||||||
|
if (Chr >= 0 && Chr <= 31)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (u32 BanIdx = 0; BanIdx < skNumIllegalChars; BanIdx++)
|
||||||
|
{
|
||||||
|
if (Chr == gskIllegalNameChars[BanIdx])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsValidName(const TString& rkName, bool Directory, bool RootDir /*= false*/)
|
bool IsValidName(const TString& rkName, bool Directory, bool RootDir /*= false*/)
|
||||||
{
|
{
|
||||||
// Only accounting for Windows limitations right now. However, this function should
|
// Only accounting for Windows limitations right now. However, this function should
|
||||||
@ -413,11 +420,9 @@ bool IsValidName(const TString& rkName, bool Directory, bool RootDir /*= false*/
|
|||||||
if (rkName.IsEmpty())
|
if (rkName.IsEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (rkName.Size() > 255)
|
if (rkName.Size() > MaxFileNameLength())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u32 NumIllegalChars = sizeof(gskIllegalNameChars) / sizeof(char);
|
|
||||||
|
|
||||||
if (Directory && (rkName == "." || rkName == ".."))
|
if (Directory && (rkName == "." || rkName == ".."))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -426,18 +431,11 @@ bool IsValidName(const TString& rkName, bool Directory, bool RootDir /*= false*/
|
|||||||
{
|
{
|
||||||
char Chr = rkName[iChr];
|
char Chr = rkName[iChr];
|
||||||
|
|
||||||
if (Chr >= 0 && Chr <= 31)
|
// Allow colon only as the last character of root
|
||||||
return false;
|
bool IsLegalColon = (Chr == ':' && RootDir && iChr == rkName.Size() - 1);
|
||||||
|
|
||||||
// Allow colon only on last character of root
|
if (!IsLegalColon && !IsValidFileNameCharacter(Chr))
|
||||||
if (Chr == ':' && (!RootDir || iChr != rkName.Size() - 1))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (u32 iBan = 0; iBan < NumIllegalChars; iBan++)
|
|
||||||
{
|
|
||||||
if (Chr == gskIllegalNameChars[iBan])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory && (rkName.Back() == ' ' || rkName.Back() == '.'))
|
if (Directory && (rkName.Back() == ' ' || rkName.Back() == '.'))
|
||||||
|
@ -28,8 +28,10 @@ TString WorkingDirectory();
|
|||||||
TString MakeAbsolute(TString Path);
|
TString MakeAbsolute(TString Path);
|
||||||
TString MakeRelative(const TString& rkPath, const TString& rkRelativeTo = WorkingDirectory());
|
TString MakeRelative(const TString& rkPath, const TString& rkRelativeTo = WorkingDirectory());
|
||||||
TString SimplifyRelativePath(const TString& rkPath);
|
TString SimplifyRelativePath(const TString& rkPath);
|
||||||
|
u32 MaxFileNameLength();
|
||||||
TString SanitizeName(TString Name, bool Directory, bool RootDir = false);
|
TString SanitizeName(TString Name, bool Directory, bool RootDir = false);
|
||||||
TString SanitizePath(TString Path, bool Directory);
|
TString SanitizePath(TString Path, bool Directory);
|
||||||
|
bool IsValidFileNameCharacter(char Chr);
|
||||||
bool IsValidName(const TString& rkName, bool Directory, bool RootDir = false);
|
bool IsValidName(const TString& rkName, bool Directory, bool RootDir = false);
|
||||||
bool IsValidPath(const TString& rkPath, bool Directory);
|
bool IsValidPath(const TString& rkPath, bool Directory);
|
||||||
void GetDirectoryContents(TString DirPath, TStringList& rOut, bool Recursive = true, bool IncludeFiles = true, bool IncludeDirs = true);
|
void GetDirectoryContents(TString DirPath, TStringList& rOut, bool Recursive = true, bool IncludeFiles = true, bool IncludeDirs = true);
|
||||||
|
@ -106,7 +106,13 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
|||||||
if (rArc.IsReader())
|
if (rArc.IsReader())
|
||||||
{
|
{
|
||||||
for (auto Iter = EmptyDirectories.begin(); Iter != EmptyDirectories.end(); Iter++)
|
for (auto Iter = EmptyDirectories.begin(); Iter != EmptyDirectories.end(); Iter++)
|
||||||
CreateVirtualDirectory(*Iter);
|
{
|
||||||
|
// Don't create empty virtual directories that don't actually exist in the filesystem
|
||||||
|
TString AbsPath = ResourcesDir() + *Iter;
|
||||||
|
|
||||||
|
if (FileUtil::Exists(AbsPath))
|
||||||
|
CreateVirtualDirectory(*Iter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -247,6 +247,30 @@ bool CVirtualDirectory::RemoveChildResource(CResourceEntry *pEntry)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CVirtualDirectory::Rename(const TString& rkNewName)
|
||||||
|
{
|
||||||
|
Log::Write("MOVING DIRECTORY: " + FullPath() + " -> " + mpParent->FullPath() + rkNewName + '/');
|
||||||
|
|
||||||
|
if (!IsRoot())
|
||||||
|
{
|
||||||
|
if (!mpParent->FindChildDirectory(rkNewName, false))
|
||||||
|
{
|
||||||
|
TString AbsPath = AbsolutePath();
|
||||||
|
TString NewPath = mpParent->AbsolutePath() + rkNewName + "/";
|
||||||
|
|
||||||
|
if (FileUtil::MoveDirectory(AbsPath, NewPath))
|
||||||
|
{
|
||||||
|
mName = rkNewName;
|
||||||
|
mpStore->SetCacheDirty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::Error("DIRECTORY MOVE FAILED");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CVirtualDirectory::Delete()
|
bool CVirtualDirectory::Delete()
|
||||||
{
|
{
|
||||||
ASSERT(IsEmpty(true) && !IsRoot());
|
ASSERT(IsEmpty(true) && !IsRoot());
|
||||||
@ -257,6 +281,7 @@ bool CVirtualDirectory::Delete()
|
|||||||
{
|
{
|
||||||
if (!mpParent || mpParent->RemoveChildDirectory(this))
|
if (!mpParent || mpParent->RemoveChildDirectory(this))
|
||||||
{
|
{
|
||||||
|
mpStore->SetCacheDirty();
|
||||||
delete this;
|
delete this;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ public:
|
|||||||
bool AddChild(CVirtualDirectory *pDir);
|
bool AddChild(CVirtualDirectory *pDir);
|
||||||
bool RemoveChildDirectory(CVirtualDirectory *pSubdir);
|
bool RemoveChildDirectory(CVirtualDirectory *pSubdir);
|
||||||
bool RemoveChildResource(CResourceEntry *pEntry);
|
bool RemoveChildResource(CResourceEntry *pEntry);
|
||||||
|
bool Rename(const TString& rkNewName);
|
||||||
bool Delete();
|
bool Delete();
|
||||||
void DeleteEmptySubdirectories();
|
void DeleteEmptySubdirectories();
|
||||||
bool SetParent(CVirtualDirectory *pParent);
|
bool SetParent(CVirtualDirectory *pParent);
|
||||||
|
@ -240,7 +240,10 @@ void CEditorApplication::TickEditors()
|
|||||||
mLastUpdate = CTimer::GlobalTime();
|
mLastUpdate = CTimer::GlobalTime();
|
||||||
double DeltaTime = mLastUpdate - LastUpdate;
|
double DeltaTime = mLastUpdate - LastUpdate;
|
||||||
|
|
||||||
// Make sure the resource store cache is up-to-date
|
// Make sure the resource store caches are up-to-date
|
||||||
|
if (gpEditorStore)
|
||||||
|
gpEditorStore->ConditionalSaveStore();
|
||||||
|
|
||||||
if (gpResourceStore)
|
if (gpResourceStore)
|
||||||
gpResourceStore->ConditionalSaveStore();
|
gpResourceStore->ConditionalSaveStore();
|
||||||
|
|
||||||
|
51
src/Editor/CFileNameValidator.h
Normal file
51
src/Editor/CFileNameValidator.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef CFILENAMEVALIDATOR_H
|
||||||
|
#define CFILENAMEVALIDATOR_H
|
||||||
|
|
||||||
|
#include <QValidator>
|
||||||
|
|
||||||
|
#include "UICommon.h"
|
||||||
|
#include <Common/FileUtil.h>
|
||||||
|
|
||||||
|
class CFileNameValidator : public QValidator
|
||||||
|
{
|
||||||
|
bool mIsDirectory;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CFileNameValidator(bool IsDirectory, QObject *pParent = 0)
|
||||||
|
: QValidator(pParent)
|
||||||
|
, mIsDirectory(IsDirectory)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QValidator::State validate(QString& rInput, int&) const
|
||||||
|
{
|
||||||
|
QValidator::State Out = QValidator::Acceptable;
|
||||||
|
|
||||||
|
if (!FileUtil::IsValidName( TO_TSTRING(rInput), mIsDirectory ))
|
||||||
|
{
|
||||||
|
// Uh oh, the input is invalid. Only invalid characters will be considered entirely
|
||||||
|
// invalid; other errors will be considered intermediate.
|
||||||
|
Out = QValidator::Intermediate;
|
||||||
|
|
||||||
|
for (int ChrIdx = 0; ChrIdx < rInput.size(); ChrIdx++)
|
||||||
|
{
|
||||||
|
char Chr = rInput.at(ChrIdx).toLatin1();
|
||||||
|
|
||||||
|
if (!FileUtil::IsValidFileNameCharacter(Chr))
|
||||||
|
{
|
||||||
|
Out = QValidator::Invalid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixup(QString& rInput) const
|
||||||
|
{
|
||||||
|
TString Sanitized = FileUtil::SanitizeName( TO_TSTRING(rInput), mIsDirectory );
|
||||||
|
rInput = TO_QSTRING(Sanitized);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CFILENAMEVALIDATOR_H
|
@ -191,7 +191,10 @@ HEADERS += \
|
|||||||
ResourceBrowser/CResourceMimeData.h \
|
ResourceBrowser/CResourceMimeData.h \
|
||||||
ResourceBrowser/CResourceTableView.h \
|
ResourceBrowser/CResourceTableView.h \
|
||||||
Undo/CMoveResourceCommand.h \
|
Undo/CMoveResourceCommand.h \
|
||||||
Undo/CMoveDirectoryCommand.h
|
Undo/CMoveDirectoryCommand.h \
|
||||||
|
Undo/CRenameResourceCommand.h \
|
||||||
|
Undo/CRenameDirectoryCommand.h \
|
||||||
|
CFileNameValidator.h
|
||||||
|
|
||||||
# Source Files
|
# Source Files
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include "Editor/CEditorApplication.h"
|
#include "Editor/CEditorApplication.h"
|
||||||
#include "Editor/Undo/CMoveDirectoryCommand.h"
|
#include "Editor/Undo/CMoveDirectoryCommand.h"
|
||||||
#include "Editor/Undo/CMoveResourceCommand.h"
|
#include "Editor/Undo/CMoveResourceCommand.h"
|
||||||
|
#include "Editor/Undo/CRenameDirectoryCommand.h"
|
||||||
|
#include "Editor/Undo/CRenameResourceCommand.h"
|
||||||
#include <Core/GameProject/AssetNameGeneration.h>
|
#include <Core/GameProject/AssetNameGeneration.h>
|
||||||
#include <Core/GameProject/CAssetNameMap.h>
|
#include <Core/GameProject/CAssetNameMap.h>
|
||||||
|
|
||||||
@ -220,6 +222,54 @@ void CResourceBrowser::CreateFilterCheckboxes()
|
|||||||
mpFilterBoxesLayout->addSpacerItem(pSpacer);
|
mpFilterBoxesLayout->addSpacerItem(pSpacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CResourceBrowser::RenameResource(CResourceEntry *pEntry, const TString& rkNewName)
|
||||||
|
{
|
||||||
|
if (pEntry->Name() == rkNewName)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check if the move is valid
|
||||||
|
if (!pEntry->CanMoveTo(pEntry->DirectoryPath(), rkNewName))
|
||||||
|
{
|
||||||
|
if (pEntry->Directory()->FindChildResource(rkNewName, pEntry->ResourceType()) != nullptr)
|
||||||
|
{
|
||||||
|
UICommon::ErrorMsg(this, "Failed to rename; the destination directory has conflicting files!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UICommon::ErrorMsg(this, "Failed to rename; filename is invalid!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything seems to be valid; proceed with the rename
|
||||||
|
mUndoStack.push( new CRenameResourceCommand(pEntry, rkNewName) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CResourceBrowser::RenameDirectory(CVirtualDirectory *pDir, const TString& rkNewName)
|
||||||
|
{
|
||||||
|
if (pDir->Name() == rkNewName)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!CVirtualDirectory::IsValidDirectoryName(rkNewName))
|
||||||
|
{
|
||||||
|
UICommon::ErrorMsg(this, "Failed to rename; directory name is invalid!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for conflicts
|
||||||
|
if (pDir->Parent()->FindChildDirectory(rkNewName, false) != nullptr)
|
||||||
|
{
|
||||||
|
UICommon::ErrorMsg(this, "Failed to rename; the destination directory has a conflicting directory!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No conflicts, proceed with the rename
|
||||||
|
mUndoStack.push( new CRenameDirectoryCommand(pDir, rkNewName) );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CResourceBrowser::MoveResources(const QList<CResourceEntry*>& rkResources, const QList<CVirtualDirectory*>& rkDirectories, CVirtualDirectory *pNewDir)
|
bool CResourceBrowser::MoveResources(const QList<CResourceEntry*>& rkResources, const QList<CVirtualDirectory*>& rkDirectories, CVirtualDirectory *pNewDir)
|
||||||
{
|
{
|
||||||
// Check for any conflicts
|
// Check for any conflicts
|
||||||
@ -242,7 +292,7 @@ bool CResourceBrowser::MoveResources(const QList<CResourceEntry*>& rkResources,
|
|||||||
// If there were conflicts, notify the user of them
|
// If there were conflicts, notify the user of them
|
||||||
if (!ConflictingResources.isEmpty() || !ConflictingDirs.isEmpty())
|
if (!ConflictingResources.isEmpty() || !ConflictingDirs.isEmpty())
|
||||||
{
|
{
|
||||||
QString ErrorMsg = "Unable to move; the destination directory has conflicting files.\n\n";
|
QString ErrorMsg = "Failed to move; the destination directory has conflicting files.\n\n";
|
||||||
|
|
||||||
foreach (CVirtualDirectory *pDir, ConflictingDirs)
|
foreach (CVirtualDirectory *pDir, ConflictingDirs)
|
||||||
{
|
{
|
||||||
|
@ -56,6 +56,8 @@ public:
|
|||||||
void SelectDirectory(CVirtualDirectory *pDir);
|
void SelectDirectory(CVirtualDirectory *pDir);
|
||||||
void CreateFilterCheckboxes();
|
void CreateFilterCheckboxes();
|
||||||
|
|
||||||
|
bool RenameResource(CResourceEntry *pEntry, 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);
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
#include "CResourceDelegate.h"
|
#include "CResourceDelegate.h"
|
||||||
|
#include "CResourceBrowser.h"
|
||||||
#include "CResourceProxyModel.h"
|
#include "CResourceProxyModel.h"
|
||||||
#include "CResourceTableModel.h"
|
#include "CResourceTableModel.h"
|
||||||
|
#include "Editor/CFileNameValidator.h"
|
||||||
|
#include "Editor/UICommon.h"
|
||||||
#include <Common/Common.h>
|
#include <Common/Common.h>
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
struct SResDelegateInfo
|
// Font Info
|
||||||
|
struct SResDelegateFontInfo
|
||||||
{
|
{
|
||||||
QFont NameFont;
|
QFont NameFont;
|
||||||
QFont InfoFont;
|
QFont InfoFont;
|
||||||
@ -16,12 +21,12 @@ struct SResDelegateInfo
|
|||||||
int Margin;
|
int Margin;
|
||||||
int Spacing;
|
int Spacing;
|
||||||
|
|
||||||
SResDelegateInfo()
|
SResDelegateFontInfo()
|
||||||
: NameFontMetrics(NameFont), InfoFontMetrics(InfoFont) {}
|
: NameFontMetrics(NameFont), InfoFontMetrics(InfoFont) {}
|
||||||
};
|
};
|
||||||
SResDelegateInfo GetDelegateInfo(const QStyleOptionViewItem& rkOption)
|
SResDelegateFontInfo GetFontInfo(const QStyleOptionViewItem& rkOption)
|
||||||
{
|
{
|
||||||
SResDelegateInfo Info;
|
SResDelegateFontInfo Info;
|
||||||
|
|
||||||
Info.NameFont = rkOption.font;
|
Info.NameFont = rkOption.font;
|
||||||
Info.NameFont.setPointSize( rkOption.font.pointSize() + 1 );
|
Info.NameFont.setPointSize( rkOption.font.pointSize() + 1 );
|
||||||
@ -42,10 +47,61 @@ SResDelegateInfo GetDelegateInfo(const QStyleOptionViewItem& rkOption)
|
|||||||
return Info;
|
return Info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Geometry Info
|
||||||
|
struct SResDelegateGeometryInfo
|
||||||
|
{
|
||||||
|
QRect InnerRect;
|
||||||
|
QRect IconRect;
|
||||||
|
QRect NameStringRect;
|
||||||
|
QRect InfoStringRect;
|
||||||
|
};
|
||||||
|
SResDelegateGeometryInfo GetGeometryInfo(const SResDelegateFontInfo& rkFontInfo, const QStyleOptionViewItem& rkOption, bool IsDirectory)
|
||||||
|
{
|
||||||
|
SResDelegateGeometryInfo Info;
|
||||||
|
|
||||||
|
// Calculate inner rect
|
||||||
|
int Margin = rkFontInfo.Margin;
|
||||||
|
Info.InnerRect = rkOption.rect.adjusted(Margin, Margin, -Margin, -Margin);
|
||||||
|
|
||||||
|
// Calculate icon
|
||||||
|
int IdealIconSize = CResourceBrowserDelegate::skIconSize;
|
||||||
|
int IconSize = Math::Min(IdealIconSize, Info.InnerRect.height());
|
||||||
|
int IconX = Info.InnerRect.left() + ((IdealIconSize - IconSize) / 2);
|
||||||
|
int IconY = Info.InnerRect.top() + ((Info.InnerRect.height() - IconSize) / 2);
|
||||||
|
Info.IconRect = QRect(IconX, IconY, IconSize, IconSize);
|
||||||
|
|
||||||
|
// Calculate name string
|
||||||
|
int NameX = Info.InnerRect.left() + IdealIconSize + (rkFontInfo.Spacing * 2);
|
||||||
|
int NameY = Info.InnerRect.top();
|
||||||
|
int NameSizeX = Info.InnerRect.right() - NameX;
|
||||||
|
int NameSizeY = rkFontInfo.NameFontMetrics.height();
|
||||||
|
|
||||||
|
// Adjust Y for directories to center it in the rect
|
||||||
|
if (IsDirectory)
|
||||||
|
{
|
||||||
|
NameY += (Info.InnerRect.height() - NameSizeY) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info.NameStringRect = QRect(NameX, NameY, NameSizeX, NameSizeY);
|
||||||
|
|
||||||
|
// Calculate info string
|
||||||
|
if (!IsDirectory)
|
||||||
|
{
|
||||||
|
int InfoX = NameX;
|
||||||
|
int InfoY = NameY + NameSizeY + rkFontInfo.Spacing;
|
||||||
|
int InfoSizeX = NameSizeX;
|
||||||
|
int InfoSizeY = rkFontInfo.InfoFontMetrics.height();
|
||||||
|
Info.InfoStringRect = QRect(InfoX, InfoY, InfoSizeX, InfoSizeY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delegate implementation
|
||||||
QSize CResourceBrowserDelegate::sizeHint(const QStyleOptionViewItem& rkOption, const QModelIndex&) const
|
QSize CResourceBrowserDelegate::sizeHint(const QStyleOptionViewItem& rkOption, const QModelIndex&) const
|
||||||
{
|
{
|
||||||
// Get string info
|
// Get string info
|
||||||
SResDelegateInfo Info = GetDelegateInfo(rkOption);
|
SResDelegateFontInfo Info = GetFontInfo(rkOption);
|
||||||
|
|
||||||
// Calculate height
|
// Calculate height
|
||||||
int Height = (Info.Margin * 2) + Info.NameFontMetrics.height() + Info.Spacing + Info.InfoFontMetrics.height();
|
int Height = (Info.Margin * 2) + Info.NameFontMetrics.height() + Info.Spacing + Info.InfoFontMetrics.height();
|
||||||
@ -54,20 +110,12 @@ QSize CResourceBrowserDelegate::sizeHint(const QStyleOptionViewItem& rkOption, c
|
|||||||
|
|
||||||
void CResourceBrowserDelegate::paint(QPainter *pPainter, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const
|
void CResourceBrowserDelegate::paint(QPainter *pPainter, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const
|
||||||
{
|
{
|
||||||
const CResourceProxyModel *pkProxy = qobject_cast<const CResourceProxyModel*>(rkIndex.model());
|
|
||||||
ASSERT(pkProxy != nullptr);
|
|
||||||
|
|
||||||
const CResourceTableModel *pkModel = qobject_cast<const CResourceTableModel*>(pkProxy->sourceModel());
|
|
||||||
ASSERT(pkModel != nullptr);
|
|
||||||
|
|
||||||
// Get resource entry
|
// Get resource entry
|
||||||
QModelIndex SourceIndex = pkProxy->mapToSource(rkIndex);
|
CResourceEntry *pEntry = GetIndexEntry(rkIndex);
|
||||||
CResourceEntry *pEntry = pkModel->IndexEntry(SourceIndex);
|
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
SResDelegateInfo Info = GetDelegateInfo(rkOption);
|
SResDelegateFontInfo FontInfo = GetFontInfo(rkOption);
|
||||||
QRect InnerRect = rkOption.rect.adjusted(Info.Margin, Info.Margin, -Info.Margin, -Info.Margin);
|
SResDelegateGeometryInfo GeomInfo = GetGeometryInfo(FontInfo, rkOption, pEntry == nullptr);
|
||||||
QPoint PainterPos = InnerRect.topLeft();
|
|
||||||
|
|
||||||
// Draw icon
|
// Draw icon
|
||||||
QVariant IconVariant = rkIndex.model()->data(rkIndex, Qt::DecorationRole);
|
QVariant IconVariant = rkIndex.model()->data(rkIndex, Qt::DecorationRole);
|
||||||
@ -75,43 +123,16 @@ void CResourceBrowserDelegate::paint(QPainter *pPainter, const QStyleOptionViewI
|
|||||||
if (IconVariant != QVariant::Invalid)
|
if (IconVariant != QVariant::Invalid)
|
||||||
{
|
{
|
||||||
QIcon Icon = IconVariant.value<QIcon>();
|
QIcon Icon = IconVariant.value<QIcon>();
|
||||||
|
Icon.paint(pPainter, GeomInfo.IconRect);
|
||||||
// Determine icon size. Ideally 24x24 if we have space, but downscale if we don't
|
|
||||||
int IdealIconSize = 24;
|
|
||||||
int IconSize = Math::Min(InnerRect.height(), IdealIconSize);
|
|
||||||
|
|
||||||
// Adjust icon position so it's centered in the ideal rect
|
|
||||||
QPoint IconPos = PainterPos;
|
|
||||||
IconPos.rx() += (IdealIconSize - IconSize) / 2;
|
|
||||||
IconPos.ry() += (InnerRect.height() - IconSize) / 2;
|
|
||||||
|
|
||||||
// Paint the icon
|
|
||||||
QRect IconRect(IconPos, QSize(IconSize, IconSize));
|
|
||||||
Icon.paint(pPainter, IconRect);
|
|
||||||
|
|
||||||
PainterPos.rx() += IdealIconSize + Info.Spacing + Info.Spacing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate rects
|
|
||||||
if (!pEntry)
|
|
||||||
PainterPos.ry() += (InnerRect.height() - Info.NameFontMetrics.height()) / 2;
|
|
||||||
|
|
||||||
int ResNameWidth = InnerRect.width() - (PainterPos.x() - InnerRect.left());
|
|
||||||
QSize ResNameSize(ResNameWidth, Info.NameFontMetrics.height());
|
|
||||||
QRect ResNameRect = QRect(PainterPos, ResNameSize);
|
|
||||||
PainterPos.ry() += ResNameRect.height() + Info.Spacing;
|
|
||||||
|
|
||||||
int ResInfoWidth = ResNameWidth;
|
|
||||||
QSize ResInfoSize(ResInfoWidth, Info.InfoFontMetrics.height());
|
|
||||||
QRect ResInfoRect = QRect(PainterPos, ResInfoSize);
|
|
||||||
|
|
||||||
// Draw resource name
|
// Draw resource name
|
||||||
QString ResName = pkModel->data(SourceIndex, Qt::DisplayRole).toString();
|
QString ResName = rkIndex.model()->data(rkIndex, Qt::DisplayRole).toString();
|
||||||
QString ElidedName = Info.NameFontMetrics.elidedText(ResName, Qt::ElideRight, ResNameWidth);
|
QString ElidedName = FontInfo.NameFontMetrics.elidedText(ResName, Qt::ElideRight, GeomInfo.NameStringRect.width());
|
||||||
|
|
||||||
pPainter->setFont(Info.NameFont);
|
pPainter->setFont(FontInfo.NameFont);
|
||||||
pPainter->setPen(Info.NamePen);
|
pPainter->setPen(FontInfo.NamePen);
|
||||||
pPainter->drawText(ResNameRect, ElidedName);
|
pPainter->drawText(GeomInfo.NameStringRect, ElidedName);
|
||||||
|
|
||||||
// Draw resource info string
|
// Draw resource info string
|
||||||
if (pEntry)
|
if (pEntry)
|
||||||
@ -121,10 +142,92 @@ void CResourceBrowserDelegate::paint(QPainter *pPainter, const QStyleOptionViewI
|
|||||||
if (mDisplayAssetIDs)
|
if (mDisplayAssetIDs)
|
||||||
ResInfo.prepend( TO_QSTRING(pEntry->ID().ToString()) + " | " );
|
ResInfo.prepend( TO_QSTRING(pEntry->ID().ToString()) + " | " );
|
||||||
|
|
||||||
QString ElidedResInfo = Info.InfoFontMetrics.elidedText(ResInfo, Qt::ElideRight, ResInfoWidth);
|
QString ElidedResInfo = FontInfo.InfoFontMetrics.elidedText(ResInfo, Qt::ElideRight, GeomInfo.InfoStringRect.width());
|
||||||
|
|
||||||
pPainter->setFont(Info.InfoFont);
|
pPainter->setFont(FontInfo.InfoFont);
|
||||||
pPainter->setPen(Info.InfoPen);
|
pPainter->setPen(FontInfo.InfoPen);
|
||||||
pPainter->drawText(ResInfoRect, ElidedResInfo);
|
pPainter->drawText(GeomInfo.InfoStringRect, ElidedResInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Editor
|
||||||
|
QWidget* CResourceBrowserDelegate::createEditor(QWidget *pParent, const QStyleOptionViewItem&, const QModelIndex& rkIndex) const
|
||||||
|
{
|
||||||
|
bool IsDirectory = (GetIndexDirectory(rkIndex) != nullptr);
|
||||||
|
|
||||||
|
QLineEdit *pLineEdit = new QLineEdit(pParent);
|
||||||
|
pLineEdit->setValidator( new CFileNameValidator(IsDirectory, pLineEdit) );
|
||||||
|
|
||||||
|
// Set the max length to 150. Limit should be 255 but FileUtil::MoveFile doesn't
|
||||||
|
// seem to want to work with filenames that long. Not sure why.
|
||||||
|
u32 MaxLength = 150;
|
||||||
|
pLineEdit->setMaxLength(MaxLength);
|
||||||
|
|
||||||
|
return pLineEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceBrowserDelegate::setEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const
|
||||||
|
{
|
||||||
|
QLineEdit *pLineEdit = static_cast<QLineEdit*>(pEditor);
|
||||||
|
CResourceEntry *pEntry = GetIndexEntry(rkIndex);
|
||||||
|
|
||||||
|
if (pEntry)
|
||||||
|
pLineEdit->setText( TO_QSTRING(pEntry->Name()) );
|
||||||
|
else
|
||||||
|
pLineEdit->setText( TO_QSTRING(GetIndexDirectory(rkIndex)->Name()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceBrowserDelegate::setModelData(QWidget *pEditor, QAbstractItemModel *, const QModelIndex& rkIndex) const
|
||||||
|
{
|
||||||
|
QLineEdit *pLineEdit = static_cast<QLineEdit*>(pEditor);
|
||||||
|
QString NewName = pLineEdit->text();
|
||||||
|
pLineEdit->validator()->fixup(NewName);
|
||||||
|
|
||||||
|
if (!NewName.isEmpty())
|
||||||
|
{
|
||||||
|
CResourceEntry *pEntry = GetIndexEntry(rkIndex);
|
||||||
|
|
||||||
|
if (pEntry)
|
||||||
|
gpEdApp->ResourceBrowser()->RenameResource(pEntry, TO_TSTRING(NewName));
|
||||||
|
else
|
||||||
|
gpEdApp->ResourceBrowser()->RenameDirectory( GetIndexDirectory(rkIndex), TO_TSTRING(NewName) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceBrowserDelegate::updateEditorGeometry(QWidget *pEditor, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const
|
||||||
|
{
|
||||||
|
// Check if this is a directory
|
||||||
|
bool IsDir = GetIndexEntry(rkIndex) == nullptr;
|
||||||
|
|
||||||
|
// Get rect
|
||||||
|
SResDelegateFontInfo FontInfo = GetFontInfo(rkOption);
|
||||||
|
SResDelegateGeometryInfo GeomInfo = GetGeometryInfo(FontInfo, rkOption, IsDir);
|
||||||
|
|
||||||
|
// Set geometry; make it a little bit better than the name string rect to give the user more space
|
||||||
|
QRect WidgetRect = GeomInfo.NameStringRect.adjusted(-3, -3, 3, 3);
|
||||||
|
pEditor->setGeometry(WidgetRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
CResourceEntry* CResourceBrowserDelegate::GetIndexEntry(const QModelIndex& rkIndex) const
|
||||||
|
{
|
||||||
|
const CResourceProxyModel *pkProxy = qobject_cast<const CResourceProxyModel*>(rkIndex.model());
|
||||||
|
ASSERT(pkProxy != nullptr);
|
||||||
|
|
||||||
|
const CResourceTableModel *pkModel = qobject_cast<const CResourceTableModel*>(pkProxy->sourceModel());
|
||||||
|
ASSERT(pkModel != nullptr);
|
||||||
|
|
||||||
|
QModelIndex SourceIndex = pkProxy->mapToSource(rkIndex);
|
||||||
|
return pkModel->IndexEntry(SourceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
CVirtualDirectory* CResourceBrowserDelegate::GetIndexDirectory(const QModelIndex& rkIndex) const
|
||||||
|
{
|
||||||
|
const CResourceProxyModel *pkProxy = qobject_cast<const CResourceProxyModel*>(rkIndex.model());
|
||||||
|
ASSERT(pkProxy != nullptr);
|
||||||
|
|
||||||
|
const CResourceTableModel *pkModel = qobject_cast<const CResourceTableModel*>(pkProxy->sourceModel());
|
||||||
|
ASSERT(pkModel != nullptr);
|
||||||
|
|
||||||
|
QModelIndex SourceIndex = pkProxy->mapToSource(rkIndex);
|
||||||
|
return pkModel->IndexDirectory(SourceIndex);
|
||||||
|
}
|
||||||
|
@ -3,8 +3,13 @@
|
|||||||
|
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
|
|
||||||
class CResourceBrowserDelegate : public QStyledItemDelegate
|
class CResourceBrowserDelegate : public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
static const int skIconSize = 32;
|
||||||
|
|
||||||
|
private:
|
||||||
bool mDisplayAssetIDs;
|
bool mDisplayAssetIDs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -16,7 +21,16 @@ public:
|
|||||||
QSize sizeHint(const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const;
|
QSize sizeHint(const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const;
|
||||||
void paint(QPainter *pPainter, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const;
|
void paint(QPainter *pPainter, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const;
|
||||||
|
|
||||||
|
QWidget* createEditor(QWidget *pParent, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const;
|
||||||
|
void setEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const;
|
||||||
|
void setModelData(QWidget *pEditor, QAbstractItemModel *pModel, const QModelIndex& rkIndex) const;
|
||||||
|
void updateEditorGeometry(QWidget *pEditor, const QStyleOptionViewItem& rkOption, const QModelIndex& rkIndex) const;
|
||||||
|
|
||||||
inline void SetDisplayAssetIDs(bool Display) { mDisplayAssetIDs = Display; }
|
inline void SetDisplayAssetIDs(bool Display) { mDisplayAssetIDs = Display; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
class CResourceEntry* GetIndexEntry(const QModelIndex& rkIndex) const;
|
||||||
|
class CVirtualDirectory* GetIndexDirectory(const QModelIndex& rkIndex) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CRESOURCEBROWSERDELEGATE_H
|
#endif // CRESOURCEBROWSERDELEGATE_H
|
||||||
|
@ -51,7 +51,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
else if (pLeftDir && pRightDir)
|
else if (pLeftDir && pRightDir)
|
||||||
return rkLeft.row() < rkRight.row(); // leave original directory order intact
|
return pLeftDir->Name().ToUpper() < pRightDir->Name().ToUpper();
|
||||||
|
|
||||||
else if (mSortMode == eSortByName)
|
else if (mSortMode == eSortByName)
|
||||||
return pLeftRes->UppercaseName() < pRightRes->UppercaseName();
|
return pLeftRes->UppercaseName() < pRightRes->UppercaseName();
|
||||||
|
@ -20,6 +20,8 @@ CResourceTableContextMenu::CResourceTableContextMenu(CResourceBrowser *pBrowser,
|
|||||||
mpOpenInExternalAppAction = addAction("Open in external application", this, SLOT(OpenInExternalApp()));
|
mpOpenInExternalAppAction = addAction("Open in external application", this, SLOT(OpenInExternalApp()));
|
||||||
mpOpenContainingFolderAction = addAction("Open containing folder", this, SLOT(OpenContainingFolder()));
|
mpOpenContainingFolderAction = addAction("Open containing folder", this, SLOT(OpenContainingFolder()));
|
||||||
addSeparator();
|
addSeparator();
|
||||||
|
mpRenameAction = addAction("Rename", this, SLOT(Rename()));
|
||||||
|
addSeparator();
|
||||||
mpCopyNameAction = addAction("Copy name", this, SLOT(CopyName()));
|
mpCopyNameAction = addAction("Copy name", this, SLOT(CopyName()));
|
||||||
mpCopyPathAction = addAction("Copy path", this, SLOT(CopyPath()));
|
mpCopyPathAction = addAction("Copy path", this, SLOT(CopyPath()));
|
||||||
mpCopyIDAction = addAction("Copy asset ID", this, SLOT(CopyID()));
|
mpCopyIDAction = addAction("Copy asset ID", this, SLOT(CopyID()));
|
||||||
@ -28,11 +30,11 @@ CResourceTableContextMenu::CResourceTableContextMenu(CResourceBrowser *pBrowser,
|
|||||||
void CResourceTableContextMenu::ShowMenu(const QPoint& rkPos)
|
void CResourceTableContextMenu::ShowMenu(const QPoint& rkPos)
|
||||||
{
|
{
|
||||||
// Fetch the entry/directory
|
// Fetch the entry/directory
|
||||||
QModelIndex ProxyIndex = mpTable->indexAt(rkPos);
|
mProxyIndex = mpTable->indexAt(rkPos);
|
||||||
|
|
||||||
if (ProxyIndex.isValid())
|
if (mProxyIndex.isValid())
|
||||||
{
|
{
|
||||||
mIndex = mpProxy->mapToSource(ProxyIndex);
|
mIndex = mpProxy->mapToSource(mProxyIndex);
|
||||||
mpEntry = mpModel->IndexEntry(mIndex);
|
mpEntry = mpModel->IndexEntry(mIndex);
|
||||||
mpDirectory = mpModel->IndexDirectory(mIndex);
|
mpDirectory = mpModel->IndexDirectory(mIndex);
|
||||||
|
|
||||||
@ -77,6 +79,11 @@ void CResourceTableContextMenu::OpenContainingFolder()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CResourceTableContextMenu::Rename()
|
||||||
|
{
|
||||||
|
mpTable->edit(mProxyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
void CResourceTableContextMenu::CopyName()
|
void CResourceTableContextMenu::CopyName()
|
||||||
{
|
{
|
||||||
if (mpEntry)
|
if (mpEntry)
|
||||||
|
@ -16,6 +16,7 @@ class CResourceTableContextMenu : public QMenu
|
|||||||
CResourceTableModel *mpModel;
|
CResourceTableModel *mpModel;
|
||||||
CResourceProxyModel *mpProxy;
|
CResourceProxyModel *mpProxy;
|
||||||
|
|
||||||
|
QModelIndex mProxyIndex;
|
||||||
QModelIndex mIndex;
|
QModelIndex mIndex;
|
||||||
CResourceEntry *mpEntry;
|
CResourceEntry *mpEntry;
|
||||||
CVirtualDirectory *mpDirectory;
|
CVirtualDirectory *mpDirectory;
|
||||||
@ -25,6 +26,8 @@ class CResourceTableContextMenu : public QMenu
|
|||||||
QAction *mpOpenInExternalAppAction;
|
QAction *mpOpenInExternalAppAction;
|
||||||
QAction *mpOpenContainingFolderAction;
|
QAction *mpOpenContainingFolderAction;
|
||||||
|
|
||||||
|
QAction *mpRenameAction;
|
||||||
|
|
||||||
QAction *mpCopyNameAction;
|
QAction *mpCopyNameAction;
|
||||||
QAction *mpCopyPathAction;
|
QAction *mpCopyPathAction;
|
||||||
QAction *mpCopyIDAction;
|
QAction *mpCopyIDAction;
|
||||||
@ -39,6 +42,7 @@ public slots:
|
|||||||
void Open();
|
void Open();
|
||||||
void OpenInExternalApp();
|
void OpenInExternalApp();
|
||||||
void OpenContainingFolder();
|
void OpenContainingFolder();
|
||||||
|
void Rename();
|
||||||
void CopyName();
|
void CopyName();
|
||||||
void CopyPath();
|
void CopyPath();
|
||||||
void CopyID();
|
void CopyID();
|
||||||
|
@ -59,7 +59,7 @@ QVariant CResourceTableModel::data(const QModelIndex& rkIndex, int Role) const
|
|||||||
|
|
||||||
Qt::ItemFlags CResourceTableModel::flags(const QModelIndex& rkIndex) const
|
Qt::ItemFlags CResourceTableModel::flags(const QModelIndex& rkIndex) const
|
||||||
{
|
{
|
||||||
Qt::ItemFlags Out = Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled;
|
Qt::ItemFlags Out = Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsEditable;
|
||||||
|
|
||||||
if (IsIndexDirectory(rkIndex))
|
if (IsIndexDirectory(rkIndex))
|
||||||
Out |= Qt::ItemIsDropEnabled;
|
Out |= Qt::ItemIsDropEnabled;
|
||||||
@ -99,16 +99,20 @@ bool CResourceTableModel::canDropMimeData(const QMimeData *pkData, Qt::DropActio
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CResourceTableModel::dropMimeData(const QMimeData *pkData, Qt::DropAction, int Row, int Column, const QModelIndex& rkParent)
|
bool CResourceTableModel::dropMimeData(const QMimeData *pkData, Qt::DropAction Action, int Row, int Column, const QModelIndex& rkParent)
|
||||||
{
|
{
|
||||||
const CResourceMimeData *pkMimeData = qobject_cast<const CResourceMimeData*>(pkData);
|
const CResourceMimeData *pkMimeData = qobject_cast<const CResourceMimeData*>(pkData);
|
||||||
|
|
||||||
QModelIndex Index = (rkParent.isValid() ? rkParent : index(Row, Column, rkParent));
|
if (canDropMimeData(pkData, Action, Row, Column, rkParent))
|
||||||
CVirtualDirectory *pDir = IndexDirectory(Index);
|
{
|
||||||
ASSERT(pDir);
|
QModelIndex Index = (rkParent.isValid() ? rkParent : index(Row, Column, rkParent));
|
||||||
|
CVirtualDirectory *pDir = IndexDirectory(Index);
|
||||||
|
ASSERT(pDir);
|
||||||
|
|
||||||
gpEdApp->ResourceBrowser()->MoveResources( pkMimeData->Resources(), pkMimeData->Directories(), pDir );
|
gpEdApp->ResourceBrowser()->MoveResources( pkMimeData->Resources(), pkMimeData->Directories(), pDir );
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMimeData* CResourceTableModel::mimeData(const QModelIndexList& rkIndexes) const
|
QMimeData* CResourceTableModel::mimeData(const QModelIndexList& rkIndexes) const
|
||||||
@ -292,6 +296,13 @@ void CResourceTableModel::OnDirectoryMoved(CVirtualDirectory *pDir, CVirtualDire
|
|||||||
bool WasInModel = !mIsAssetListMode && pOldDir == mpCurrentDir;
|
bool WasInModel = !mIsAssetListMode && pOldDir == mpCurrentDir;
|
||||||
bool IsInModel = !mIsAssetListMode && pNewDir == mpCurrentDir;
|
bool IsInModel = !mIsAssetListMode && pNewDir == mpCurrentDir;
|
||||||
|
|
||||||
|
// Handle parent link
|
||||||
|
if (pDir == mpCurrentDir)
|
||||||
|
{
|
||||||
|
ASSERT(mDirectories.front() == pOldDir);
|
||||||
|
mDirectories[0] = pNewDir;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle rename
|
// Handle rename
|
||||||
if (WasInModel && IsInModel && pDir->Name() != OldName)
|
if (WasInModel && IsInModel && pDir->Name() != OldName)
|
||||||
{
|
{
|
||||||
@ -312,7 +323,7 @@ void CResourceTableModel::OnDirectoryMoved(CVirtualDirectory *pDir, CVirtualDire
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add
|
// Add
|
||||||
else if (!WasInModel && !IsInModel)
|
else if (!WasInModel && IsInModel)
|
||||||
{
|
{
|
||||||
// Just append to the end, let the proxy handle sorting
|
// Just append to the end, let the proxy handle sorting
|
||||||
beginInsertRows(QModelIndex(), mDirectories.size(), mDirectories.size());
|
beginInsertRows(QModelIndex(), mDirectories.size(), mDirectories.size());
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
#include "CResourceTableView.h"
|
#include "CResourceTableView.h"
|
||||||
|
#include <QAction>
|
||||||
#include <QDragEnterEvent>
|
#include <QDragEnterEvent>
|
||||||
|
|
||||||
CResourceTableView::CResourceTableView(QWidget *pParent /*= 0*/)
|
CResourceTableView::CResourceTableView(QWidget *pParent /*= 0*/)
|
||||||
: QTableView(pParent)
|
: QTableView(pParent)
|
||||||
{}
|
{
|
||||||
|
// Create "rename" key shortcut
|
||||||
|
// todo - there's no QKeySequence::Rename. Is there another standard "rename" shortcut on other platforms?
|
||||||
|
mpRenameAction = new QAction(this);
|
||||||
|
mpRenameAction->setShortcut( QKeySequence(Qt::Key_F2) );
|
||||||
|
connect(mpRenameAction, SIGNAL(triggered(bool)), this, SLOT(RenameSelected()));
|
||||||
|
addAction(mpRenameAction);
|
||||||
|
}
|
||||||
|
|
||||||
void CResourceTableView::dragEnterEvent(QDragEnterEvent *pEvent)
|
void CResourceTableView::dragEnterEvent(QDragEnterEvent *pEvent)
|
||||||
{
|
{
|
||||||
@ -18,3 +26,24 @@ void CResourceTableView::dragEnterEvent(QDragEnterEvent *pEvent)
|
|||||||
setState(QAbstractItemView::DraggingState);
|
setState(QAbstractItemView::DraggingState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CResourceTableView::focusInEvent(QFocusEvent*)
|
||||||
|
{
|
||||||
|
mpRenameAction->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CResourceTableView::focusOutEvent(QFocusEvent*)
|
||||||
|
{
|
||||||
|
mpRenameAction->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************ SLOTS ************
|
||||||
|
void CResourceTableView::RenameSelected()
|
||||||
|
{
|
||||||
|
QModelIndexList List = selectionModel()->selectedIndexes();
|
||||||
|
|
||||||
|
if (List.size() == 1)
|
||||||
|
{
|
||||||
|
edit(List.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,10 +6,16 @@
|
|||||||
class CResourceTableView : public QTableView
|
class CResourceTableView : public QTableView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
QAction *mpRenameAction;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CResourceTableView(QWidget *pParent = 0);
|
explicit CResourceTableView(QWidget *pParent = 0);
|
||||||
void dragEnterEvent(QDragEnterEvent *pEvent);
|
void dragEnterEvent(QDragEnterEvent *pEvent);
|
||||||
|
void focusInEvent(QFocusEvent*);
|
||||||
|
void focusOutEvent(QFocusEvent*);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void RenameSelected();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CRESOURCETABLEVIEW_H
|
#endif // CRESOURCETABLEVIEW_H
|
||||||
|
@ -34,11 +34,10 @@ protected:
|
|||||||
void DoMove(const TString& rkPath, bool IsAutoDir)
|
void DoMove(const TString& rkPath, bool IsAutoDir)
|
||||||
{
|
{
|
||||||
CVirtualDirectory *pOldDir = mpEntry->Directory();
|
CVirtualDirectory *pOldDir = mpEntry->Directory();
|
||||||
TString OldName = mpEntry->Name();
|
|
||||||
bool Success = mpEntry->Move(rkPath, IsAutoDir);
|
bool Success = mpEntry->Move(rkPath, IsAutoDir);
|
||||||
ASSERT(Success); // todo better error handling
|
ASSERT(Success); // todo better error handling
|
||||||
|
|
||||||
gpEdApp->ResourceBrowser()->ResourceMoved(mpEntry, pOldDir, OldName);
|
gpEdApp->ResourceBrowser()->ResourceMoved(mpEntry, pOldDir, mpEntry->Name());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
38
src/Editor/Undo/CRenameDirectoryCommand.h
Normal file
38
src/Editor/Undo/CRenameDirectoryCommand.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef CRENAMEDIRECTORYCOMMAND_H
|
||||||
|
#define CRENAMEDIRECTORYCOMMAND_H
|
||||||
|
|
||||||
|
#include "IUndoCommand.h"
|
||||||
|
#include "Editor/CEditorApplication.h"
|
||||||
|
#include "Editor/ResourceBrowser/CResourceBrowser.h"
|
||||||
|
#include <Core/GameProject/CVirtualDirectory.h>
|
||||||
|
|
||||||
|
class CRenameDirectoryCommand : public IUndoCommand
|
||||||
|
{
|
||||||
|
CVirtualDirectory *mpDir;
|
||||||
|
TString mOldName;
|
||||||
|
TString mNewName;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRenameDirectoryCommand(CVirtualDirectory *pDir, const TString& rkNewName)
|
||||||
|
: IUndoCommand("Rename Directory")
|
||||||
|
, mpDir(pDir)
|
||||||
|
, mOldName(pDir->Name())
|
||||||
|
, mNewName(rkNewName)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void undo() { DoMove(mOldName); }
|
||||||
|
void redo() { DoMove(mNewName); }
|
||||||
|
bool AffectsCleanState() const { return false; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void DoMove(const TString& rkName)
|
||||||
|
{
|
||||||
|
TString OldName = mpDir->Name();
|
||||||
|
bool Success = mpDir->Rename(rkName);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
gpEdApp->ResourceBrowser()->DirectoryMoved(mpDir, mpDir->Parent(), OldName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CRENAMEDIRECTORYCOMMAND_H
|
40
src/Editor/Undo/CRenameResourceCommand.h
Normal file
40
src/Editor/Undo/CRenameResourceCommand.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef CRENAMERESOURCECOMMAND_H
|
||||||
|
#define CRENAMERESOURCECOMMAND_H
|
||||||
|
|
||||||
|
#include "IUndoCommand.h"
|
||||||
|
#include "Editor/CEditorApplication.h"
|
||||||
|
#include "Editor/ResourceBrowser/CResourceBrowser.h"
|
||||||
|
#include <Core/GameProject/CResourceEntry.h>
|
||||||
|
|
||||||
|
class CRenameResourceCommand : public IUndoCommand
|
||||||
|
{
|
||||||
|
CResourceEntry *mpEntry;
|
||||||
|
TString mOldName;
|
||||||
|
TString mNewName;
|
||||||
|
bool mOldNameAutoGenerated;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRenameResourceCommand(CResourceEntry *pEntry, const TString& rkNewName)
|
||||||
|
: IUndoCommand("Rename Resource")
|
||||||
|
, mpEntry(pEntry)
|
||||||
|
, mOldName(pEntry->Name())
|
||||||
|
, mNewName(rkNewName)
|
||||||
|
, mOldNameAutoGenerated(pEntry->HasFlag(eREF_AutoResName))
|
||||||
|
{}
|
||||||
|
|
||||||
|
void undo() { DoMove(mOldName, mOldNameAutoGenerated); }
|
||||||
|
void redo() { DoMove(mNewName, false); }
|
||||||
|
bool AffectsCleanState() const { return false; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void DoMove(const TString& rkName, bool IsAutoName)
|
||||||
|
{
|
||||||
|
TString OldName = mpEntry->Name();
|
||||||
|
bool Success = mpEntry->Rename(rkName, IsAutoName);
|
||||||
|
ASSERT(Success);
|
||||||
|
|
||||||
|
gpEdApp->ResourceBrowser()->ResourceMoved(mpEntry, mpEntry->Directory(), OldName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CRENAMERESOURCECOMMAND_H
|
@ -3,7 +3,7 @@
|
|||||||
<name>Midi</name>
|
<name>Midi</name>
|
||||||
<properties>
|
<properties>
|
||||||
<struct ID="0x255A4580" template="Structs/EditorProperties.xml"/>
|
<struct ID="0x255A4580" template="Structs/EditorProperties.xml"/>
|
||||||
<property ID="0x9D1A67A8" type="asset" extensions="STRM"/>
|
<property ID="0x9D1A67A8" type="asset" extensions="CSNG"/>
|
||||||
<property ID="0x90AA341F" type="float">
|
<property ID="0x90AA341F" type="float">
|
||||||
<default>0.0</default>
|
<default>0.0</default>
|
||||||
</property>
|
</property>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user