Implemented initial version of resource browser

This commit is contained in:
parax0 2016-07-10 06:58:23 -06:00
parent 08dcfe5e5a
commit 6f98ae5bb8
17 changed files with 716 additions and 7 deletions

View File

@ -30,7 +30,7 @@
*/ */
// Helper macros for creating string literals of the correct char type. Internal use only! Invalid outside of this header! // Helper macros for creating string literals of the correct char type. Internal use only! Invalid outside of this header!
#define LITERAL(Text) (typeid(CharType) == typeid(char)) ? (const CharType*) ##Text : (const CharType*) L##Text #define LITERAL(Text) (typeid(CharType) == typeid(char) ? (const CharType*) ##Text : (const CharType*) L##Text)
#define CHAR_LITERAL(Text) (CharType) Text #define CHAR_LITERAL(Text) (CharType) Text
// ************ TBasicString ************ // ************ TBasicString ************
@ -846,7 +846,7 @@ public:
static TBasicString<CharType> FromFloat(float Value, int MinDecimals = 1) static TBasicString<CharType> FromFloat(float Value, int MinDecimals = 1)
{ {
TString Out = std::to_string(Value); _TString Out = std::to_string(Value);
int NumZeroes = Out.Size() - (Out.IndexOf(LITERAL(".")) + 1); int NumZeroes = Out.Size() - (Out.IndexOf(LITERAL(".")) + 1);
while (Out.Back() == CHAR_LITERAL('0') && NumZeroes > MinDecimals) while (Out.Back() == CHAR_LITERAL('0') && NumZeroes > MinDecimals)
@ -858,6 +858,39 @@ public:
return Out; return Out;
} }
static TBasicString<CharType> FileSizeString(u64 Size, u32 NumDecimals = 2)
{
_TString Out;
_TString Type;
if (Size < 100)
{
return FromInt64(Size, 0, 10) + LITERAL(" bytes");
}
else if (Size < 1000000)
{
Out = FromFloat(Size / 1000.f, NumDecimals);
Type = LITERAL("KB");
}
else if (Size < 1000000000)
{
Out = FromFloat(Size / 1000000.f, NumDecimals);
Type = LITERAL("MB");
}
else
{
Out = FromFloat(Size / 1000000000.f, NumDecimals);
Type = LITERAL("GB");
}
u32 DecCount = Out.Size() - (Out.IndexOf(CHAR_LITERAL('.')) + 1);
if (DecCount > NumDecimals) Out = Out.ChopBack(DecCount - NumDecimals);
return Out + Type;
}
static TBasicString<CharType> HexString(unsigned char Num, int Width = 8, bool AddPrefix = true, bool Uppercase = true) static TBasicString<CharType> HexString(unsigned char Num, int Width = 8, bool AddPrefix = true, bool Uppercase = true)
{ {
return HexString((unsigned long) Num, Width, AddPrefix, Uppercase); return HexString((unsigned long) Num, Width, AddPrefix, Uppercase);

View File

@ -195,7 +195,8 @@ HEADERS += \
GameProject/CGameExporter.h \ GameProject/CGameExporter.h \
GameProject/CResourceStore.h \ GameProject/CResourceStore.h \
GameProject/CVirtualDirectory.h \ GameProject/CVirtualDirectory.h \
GameProject/CResourceEntry.h GameProject/CResourceEntry.h \
GameProject/CResourceIterator.h
# Source Files # Source Files
SOURCES += \ SOURCES += \

View File

@ -171,6 +171,7 @@ void CGameExporter::LoadPaks()
for (auto It = mPaks.begin(); It != mPaks.end(); It++) for (auto It = mPaks.begin(); It != mPaks.end(); It++)
{ {
TWideString PakPath = *It; TWideString PakPath = *It;
TWideString PakName = PakPath.GetFileName(false);
TString CharPak = PakPath.ToUTF8(); TString CharPak = PakPath.ToUTF8();
CFileInStream Pak(CharPak.ToStdString(), IOUtil::eBigEndian); CFileInStream Pak(CharPak.ToStdString(), IOUtil::eBigEndian);
@ -203,6 +204,7 @@ void CGameExporter::LoadPaks()
u32 NameLen = Pak.ReadLong(); u32 NameLen = Pak.ReadLong();
TString Name = Pak.ReadString(NameLen); TString Name = Pak.ReadString(NameLen);
pCollection->AddResource(Name, ResID, ResType); pCollection->AddResource(Name, ResID, ResType);
SetResourcePath(ResID.ToLongLong(), PakName + L"\\", Name.ToUTF16());
} }
u32 NumResources = Pak.ReadLong(); u32 NumResources = Pak.ReadLong();
@ -261,6 +263,7 @@ void CGameExporter::LoadPaks()
CFourCC ResType = Pak.ReadLong(); CFourCC ResType = Pak.ReadLong();
CUniqueID ResID(Pak, IDLength); CUniqueID ResID(Pak, IDLength);
pCollection->AddResource(Name, ResID, ResType); pCollection->AddResource(Name, ResID, ResType);
SetResourcePath(ResID.ToLongLong(), PakName + L"\\", Name.ToUTF16());
} }
} }

View File

@ -33,6 +33,8 @@ CResourceEntry::CResourceEntry(CResourceStore *pStore, const CUniqueID& rkID,
, mType(Type) , mType(Type)
, mNeedsRecook(false) , mNeedsRecook(false)
, mTransient(Transient) , mTransient(Transient)
, mCachedSize(-1)
, mCachedUppercaseName(rkFilename.ToUpper())
{ {
mpDirectory = mpStore->GetVirtualDirectory(rkDir, Transient, true); mpDirectory = mpStore->GetVirtualDirectory(rkDir, Transient, true);
if (mpDirectory) mpDirectory->AddChild(L"", this); if (mpDirectory) mpDirectory->AddChild(L"", this);
@ -70,6 +72,32 @@ TString CResourceEntry::CookedAssetPath(bool Relative) const
return ((mTransient || Relative) ? Path + Name : mpStore->ActiveProject()->CookedDir(false) + Path + Name); return ((mTransient || Relative) ? Path + Name : mpStore->ActiveProject()->CookedDir(false) + Path + Name);
} }
bool CResourceEntry::IsInDirectory(CVirtualDirectory *pDir) const
{
CVirtualDirectory *pParentDir = mpDirectory;
while (pParentDir)
{
if (pParentDir == pDir) return true;
pParentDir = pParentDir->Parent();
}
return false;
}
u64 CResourceEntry::Size() const
{
if (mCachedSize == -1)
{
if (HasCookedVersion())
mCachedSize = FileUtil::FileSize(CookedAssetPath());
else
return 0;
}
return mCachedSize;
}
bool CResourceEntry::NeedsRecook() const bool CResourceEntry::NeedsRecook() const
{ {
// Assets that do not have a raw version can't be recooked since they will always just be saved cooked to begin with. // Assets that do not have a raw version can't be recooked since they will always just be saved cooked to begin with.
@ -170,6 +198,7 @@ void CResourceEntry::Move(const TWideString& rkDir, const TWideString& rkName)
ASSERT(mpDirectory->FindChildResource(rkName) == nullptr); ASSERT(mpDirectory->FindChildResource(rkName) == nullptr);
mName = rkName; mName = rkName;
mCachedUppercaseName = rkName.ToUpper();
// Move files // Move files
if (HasDirectory) if (HasDirectory)

View File

@ -21,6 +21,9 @@ class CResourceEntry
bool mNeedsRecook; bool mNeedsRecook;
bool mTransient; bool mTransient;
mutable u64 mCachedSize;
mutable TWideString mCachedUppercaseName; // This is used to speed up case-insensitive sorting.
public: public:
CResourceEntry(CResourceStore *pStore, const CUniqueID& rkID, CResourceEntry(CResourceStore *pStore, const CUniqueID& rkID,
const TWideString& rkDir, const TWideString& rkFilename, const TWideString& rkDir, const TWideString& rkFilename,
@ -30,6 +33,8 @@ public:
bool HasCookedVersion() const; bool HasCookedVersion() const;
TString RawAssetPath(bool Relative = false) const; TString RawAssetPath(bool Relative = false) const;
TString CookedAssetPath(bool Relative = false) const; TString CookedAssetPath(bool Relative = false) const;
bool IsInDirectory(CVirtualDirectory *pDir) const;
u64 Size() const;
bool NeedsRecook() const; bool NeedsRecook() const;
void SetGame(EGame NewGame); void SetGame(EGame NewGame);
CResource* Load(); CResource* Load();
@ -48,6 +53,7 @@ public:
inline EGame Game() const { return mGame; } inline EGame Game() const { return mGame; }
inline CVirtualDirectory* Directory() const { return mpDirectory; } inline CVirtualDirectory* Directory() const { return mpDirectory; }
inline TWideString Name() const { return mName; } inline TWideString Name() const { return mName; }
inline TWideString UppercaseName() const { return mCachedUppercaseName; }
inline EResType ResourceType() const { return mType; } inline EResType ResourceType() const { return mType; }
inline bool IsTransient() const { return mTransient; } inline bool IsTransient() const { return mTransient; }

View File

@ -0,0 +1,69 @@
#ifndef CRESOURCEITERATOR
#define CRESOURCEITERATOR
#include <Core/GameProject/CResourceEntry.h>
#include <Core/GameProject/CResourceStore.h>
class CResourceIterator
{
CResourceStore *mpStore;
std::map<CUniqueID, CResourceEntry*>::iterator mIter;
CResourceEntry *mpCurEntry;
public:
CResourceIterator(CResourceStore *pStore)
: mpStore(pStore)
, mpCurEntry(nullptr)
{
mIter = mpStore->mResourceEntries.begin();
Next();
}
inline CResourceEntry* Next()
{
if (mIter != mpStore->mResourceEntries.end())
{
mpCurEntry = mIter->second;
mIter++;
}
else mpCurEntry = nullptr;
return mpCurEntry;
}
inline bool DoneIterating() const
{
return mpCurEntry == nullptr;
}
inline operator bool() const
{
return !DoneIterating();
}
inline CResourceEntry* operator*() const
{
return mpCurEntry;
}
inline CResourceEntry* operator->() const
{
return mpCurEntry;
}
inline CResourceIterator& operator++()
{
Next();
return *this;
}
inline CResourceIterator operator++(int)
{
CResourceIterator Copy = *this;
Next();
return Copy;
}
};
#endif // CRESOURCEITERATOR

View File

@ -16,6 +16,8 @@ class CResource;
class CResourceStore class CResourceStore
{ {
friend class CResourceIterator;
CGameProject *mpProj; CGameProject *mpProj;
CVirtualDirectory *mpProjectRoot; CVirtualDirectory *mpProjectRoot;
std::vector<CVirtualDirectory*> mTransientRoots; std::vector<CVirtualDirectory*> mTransientRoots;
@ -62,6 +64,7 @@ public:
// Accessors // Accessors
inline CGameProject* ActiveProject() const { return mpProj; } inline CGameProject* ActiveProject() const { return mpProj; }
inline CVirtualDirectory* RootDirectory() const { return mpProjectRoot; }
}; };
extern CResourceStore *gpResourceStore; extern CResourceStore *gpResourceStore;

View File

@ -1,6 +1,7 @@
#include "CProjectOverviewDialog.h" #include "CProjectOverviewDialog.h"
#include "ui_CProjectOverviewDialog.h" #include "ui_CProjectOverviewDialog.h"
#include "UICommon.h" #include "UICommon.h"
#include "Editor/ResourceBrowser/CResourceBrowser.h"
#include <Common/AssertMacro.h> #include <Common/AssertMacro.h>
#include <Core/GameProject/CGameExporter.h> #include <Core/GameProject/CGameExporter.h>
#include <QFileDialog> #include <QFileDialog>
@ -18,6 +19,7 @@ CProjectOverviewDialog::CProjectOverviewDialog(QWidget *pParent)
connect(mpUI->ExportGameButton, SIGNAL(clicked()), this, SLOT(ExportGame())); connect(mpUI->ExportGameButton, SIGNAL(clicked()), this, SLOT(ExportGame()));
connect(mpUI->LoadWorldButton, SIGNAL(clicked()), this, SLOT(LoadWorld())); connect(mpUI->LoadWorldButton, SIGNAL(clicked()), this, SLOT(LoadWorld()));
connect(mpUI->LaunchEditorButton, SIGNAL(clicked()), this, SLOT(LaunchEditor())); connect(mpUI->LaunchEditorButton, SIGNAL(clicked()), this, SLOT(LaunchEditor()));
connect(mpUI->ViewResourcesButton, SIGNAL(clicked()), this, SLOT(LaunchResourceBrowser()));
} }
CProjectOverviewDialog::~CProjectOverviewDialog() CProjectOverviewDialog::~CProjectOverviewDialog()
@ -164,3 +166,9 @@ void CProjectOverviewDialog::LaunchEditor()
gpResourceStore->DestroyUnreferencedResources(); gpResourceStore->DestroyUnreferencedResources();
} }
void CProjectOverviewDialog::LaunchResourceBrowser()
{
CResourceBrowser Browser(this);
Browser.exec();
}

View File

@ -30,6 +30,7 @@ public slots:
void ExportGame(); void ExportGame();
void LoadWorld(); void LoadWorld();
void LaunchEditor(); void LaunchEditor();
void LaunchResourceBrowser();
void SetupWorldsList(); void SetupWorldsList();
}; };

View File

@ -32,6 +32,13 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QPushButton" name="ViewResourcesButton">
<property name="text">
<string>View Resources</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="WorldsGroupBox"> <widget class="QGroupBox" name="WorldsGroupBox">
<property name="sizePolicy"> <property name="sizePolicy">

View File

@ -164,7 +164,11 @@ HEADERS += \
CGridRenderable.h \ CGridRenderable.h \
CharacterEditor/CSkeletonHierarchyModel.h \ CharacterEditor/CSkeletonHierarchyModel.h \
CLineRenderable.h \ CLineRenderable.h \
CProjectOverviewDialog.h CProjectOverviewDialog.h \
ResourceBrowser/CResourceBrowser.h \
ResourceBrowser/CResourceTableModel.h \
ResourceBrowser/CResourceProxyModel.h \
ResourceBrowser/CVirtualDirectoryModel.h
# Source Files # Source Files
SOURCES += \ SOURCES += \
@ -225,7 +229,8 @@ SOURCES += \
CharacterEditor/CCharacterEditor.cpp \ CharacterEditor/CCharacterEditor.cpp \
CharacterEditor/CCharacterEditorViewport.cpp \ CharacterEditor/CCharacterEditorViewport.cpp \
CharacterEditor/CSkeletonHierarchyModel.cpp \ CharacterEditor/CSkeletonHierarchyModel.cpp \
CProjectOverviewDialog.cpp CProjectOverviewDialog.cpp \
ResourceBrowser/CResourceBrowser.cpp
# UI Files # UI Files
FORMS += \ FORMS += \
@ -247,4 +252,5 @@ FORMS += \
WorldEditor/CRepackInfoDialog.ui \ WorldEditor/CRepackInfoDialog.ui \
CAboutDialog.ui \ CAboutDialog.ui \
CharacterEditor/CCharacterEditor.ui \ CharacterEditor/CCharacterEditor.ui \
CProjectOverviewDialog.ui CProjectOverviewDialog.ui \
ResourceBrowser/CResourceBrowser.ui

View File

@ -0,0 +1,63 @@
#include "CResourceBrowser.h"
#include "ui_CResourceBrowser.h"
CResourceBrowser::CResourceBrowser(QWidget *pParent)
: QDialog(pParent)
, mpUI(new Ui::CResourceBrowser)
{
mpUI->setupUi(this);
// Set up table models
mpModel = new CResourceTableModel(this);
mpProxyModel = new CResourceProxyModel(this);
mpProxyModel->setSourceModel(mpModel);
mpUI->ResourceTableView->setModel(mpProxyModel);
RefreshResources();
QHeaderView *pHeader = mpUI->ResourceTableView->horizontalHeader();
pHeader->setSectionResizeMode(0, QHeaderView::Stretch);
pHeader->resizeSection(1, 215);
pHeader->resizeSection(2, 75);
// Set up directory tree model
mpDirectoryModel = new CVirtualDirectoryModel(this);
mpDirectoryModel->SetRoot(gpResourceStore->RootDirectory());
mpUI->DirectoryTreeView->setModel(mpDirectoryModel);
mpUI->DirectoryTreeView->expand(mpDirectoryModel->index(0, 0, QModelIndex()));
// Set up connections
connect(mpUI->SearchBar, SIGNAL(textChanged(QString)), this, SLOT(OnSearchStringChanged()));
connect(mpUI->SortComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSortModeChanged(int)));
connect(mpUI->DirectoryTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex,QModelIndex)));
}
CResourceBrowser::~CResourceBrowser()
{
delete mpUI;
}
void CResourceBrowser::RefreshResources()
{
mpModel->FillEntryList(gpResourceStore);
}
void CResourceBrowser::OnSortModeChanged(int Index)
{
CResourceProxyModel::ESortMode Mode = (Index == 0 ? CResourceProxyModel::eSortByName : CResourceProxyModel::eSortBySize);
mpProxyModel->SetSortMode(Mode);
}
void CResourceBrowser::OnSearchStringChanged()
{
mpProxyModel->SetSearchString( mpUI->SearchBar->text() );
}
void CResourceBrowser::OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& /*rkPrevIndex*/)
{
CVirtualDirectory *pDir = nullptr;
if (rkNewIndex.isValid())
pDir = mpDirectoryModel->IndexDirectory(rkNewIndex);
mpProxyModel->SetDirectory(pDir);
}

View File

@ -0,0 +1,32 @@
#ifndef CRESOURCEBROWSER_H
#define CRESOURCEBROWSER_H
#include "CResourceProxyModel.h"
#include "CResourceTableModel.h"
#include "CVirtualDirectoryModel.h"
#include <QDialog>
namespace Ui {
class CResourceBrowser;
}
class CResourceBrowser : public QDialog
{
Q_OBJECT
Ui::CResourceBrowser *mpUI;
CResourceTableModel *mpModel;
CResourceProxyModel *mpProxyModel;
CVirtualDirectoryModel *mpDirectoryModel;
public:
explicit CResourceBrowser(QWidget *pParent = 0);
~CResourceBrowser();
void RefreshResources();
public slots:
void OnSortModeChanged(int Index);
void OnSearchStringChanged();
void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex);
};
#endif // CRESOURCEBROWSER_H

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CResourceBrowser</class>
<widget class="QDialog" name="CResourceBrowser">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>789</width>
<height>577</height>
</rect>
</property>
<property name="windowTitle">
<string>Resource Browser</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QWidget" name="SidebarContainerWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="SearchBar">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>5</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="SortComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>5</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Sort by Name</string>
</property>
</item>
<item>
<property name="text">
<string>Sort by Size</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QTreeView" name="DirectoryTreeView">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="indentation">
<number>12</number>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTableView" name="ResourceTableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>3</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>21</number>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>21</number>
</attribute>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,89 @@
#ifndef CRESOURCEPROXYMODEL
#define CRESOURCEPROXYMODEL
#include "CResourceTableModel.h"
#include <QSortFilterProxyModel>
class CResourceProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
enum ESortMode
{
eSortByName, eSortBySize
};
private:
CResourceTableModel *mpModel;
CVirtualDirectory *mpDirectory;
QString mSearchString;
ESortMode mSortMode;
public:
explicit CResourceProxyModel(QObject *pParent = 0)
: QSortFilterProxyModel(pParent)
, mpModel(nullptr)
, mpDirectory(nullptr)
{
SetSortMode(eSortByName);
}
void setSourceModel(QAbstractItemModel *pSourceModel)
{
CResourceTableModel *pResModel = qobject_cast<CResourceTableModel*>(pSourceModel);
mpModel = pResModel;
QSortFilterProxyModel::setSourceModel(pResModel);
sort(0);
}
bool lessThan(const QModelIndex& rkLeft, const QModelIndex& rkRight) const
{
CResourceEntry *pLeft = mpModel->IndexEntry(rkLeft);
CResourceEntry *pRight = mpModel->IndexEntry(rkRight);
if (mSortMode == eSortByName)
return pLeft->UppercaseName() < pRight->UppercaseName();
else
return pLeft->Size() < pRight->Size();
}
bool filterAcceptsRow(int SourceRow, const QModelIndex& rkSourceParent) const
{
QModelIndex Index = mpModel->index(SourceRow, 0, rkSourceParent);
CResourceEntry *pEntry = mpModel->IndexEntry(Index);
if (mpDirectory && !pEntry->IsInDirectory(mpDirectory))
return false;
if (!mSearchString.isEmpty() && !pEntry->Name().Contains(TO_TWIDESTRING(mSearchString), false))
return false;
return true;
}
inline void SetSortMode(ESortMode Mode)
{
if (mSortMode != Mode)
{
mSortMode = Mode;
sort(0, (mSortMode == eSortByName ? Qt::AscendingOrder : Qt::DescendingOrder));
}
}
inline void SetDirectory(CVirtualDirectory *pDir)
{
mpDirectory = pDir;
invalidateFilter();
}
public slots:
void SetSearchString(const QString& rkString)
{
mSearchString = rkString;
invalidateFilter();
}
};
#endif // CRESOURCEPROXYMODEL

View File

@ -0,0 +1,99 @@
#ifndef CRESOURCETABLEMODEL
#define CRESOURCETABLEMODEL
#include "Editor/UICommon.h"
#include <Core/GameProject/CResourceEntry.h>
#include <Core/GameProject/CResourceIterator.h>
#include <Core/GameProject/CResourceStore.h>
#include <Core/Resource/CResource.h>
#include <QAbstractTableModel>
#include <QIcon>
class CResourceTableModel : public QAbstractTableModel
{
Q_OBJECT
QList<CResourceEntry*> mEntries;
public:
CResourceTableModel(QObject *pParent = 0)
: QAbstractTableModel(pParent)
{}
int rowCount(const QModelIndex& /*rkParent*/) const
{
return mEntries.size();
}
int columnCount(const QModelIndex& /*rkParent*/) const
{
return 3;
}
QVariant data(const QModelIndex& rkIndex, int Role) const
{
CResourceEntry *pEntry = mEntries[rkIndex.row()];
u32 Col = rkIndex.column();
if (Role == Qt::DisplayRole)
{
if (Col == 0) return TO_QSTRING(pEntry->Name());
if (Col == 1) return TO_QSTRING(GetResourceTypeName(pEntry->ResourceType()));
if (Col == 2)
{
u64 Size = pEntry->Size();
return Size ? TO_QSTRING( TString::FileSizeString(pEntry->Size()) ) : "";
}
}
else if (Role == Qt::ToolTipRole)
return TO_QSTRING(pEntry->Directory()->FullPath() + pEntry->Name());
return QVariant::Invalid;
}
CResourceEntry* IndexEntry(const QModelIndex& rkIndex) const
{
return mEntries[rkIndex.row()];
}
void FillEntryList(CResourceStore *pStore)
{
beginResetModel();
mEntries.clear();
for (CResourceIterator It(pStore); It; ++It)
{
if (It->IsTransient()) continue;
EResType Type = It->ResourceType();
switch (Type)
{
case eArea:
case eAreaCollision:
case eAreaLights:
case eAreaMaterials:
case eAreaSurfaceBounds:
case eAreaOctree:
case eAreaVisibilityTree:
case eMapArea:
case eMapWorld:
case ePathfinding:
case ePortalArea:
case eSaveArea:
case eSaveWorld:
case eStaticGeometryMap:
case eTweak:
case eWorld:
continue;
default:
mEntries << *It;
}
}
endResetModel();
}
};
#endif // CRESOURCELISTMODEL

View File

@ -0,0 +1,103 @@
#ifndef CVIRTUALDIRECTORYMODEL
#define CVIRTUALDIRECTORYMODEL
#include "Editor/UICommon.h"
#include <Core/GameProject/CVirtualDirectory.h>
#include <QAbstractItemModel>
#include <QIcon>
class CVirtualDirectoryModel : public QAbstractItemModel
{
Q_OBJECT
CVirtualDirectory *mpRoot;
public:
CVirtualDirectoryModel(QObject *pParent = 0)
: QAbstractItemModel(pParent)
, mpRoot(nullptr)
{}
QModelIndex index(int Row, int Column, const QModelIndex& rkParent) const
{
if (!hasIndex(Row, Column, rkParent))
return QModelIndex();
CVirtualDirectory *pDir = IndexDirectory(rkParent);
if (pDir && pDir->NumSubdirectories() > (u32) Row)
return createIndex(Row, Column, pDir->SubdirectoryByIndex(Row));
else if (!pDir)
return createIndex(Row, Column, mpRoot);
return QModelIndex();
}
QModelIndex parent(const QModelIndex& rkChild) const
{
CVirtualDirectory *pDir = IndexDirectory(rkChild);
CVirtualDirectory *pParent = pDir->Parent();
if (pParent)
{
CVirtualDirectory *pGrandparent = pParent->Parent();
if (pGrandparent)
{
for (u32 iSub = 0; iSub < pGrandparent->NumSubdirectories(); iSub++)
{
if (pGrandparent->SubdirectoryByIndex(iSub) == pParent)
return createIndex(iSub, 0, pParent);
}
}
else return createIndex(0, 0, mpRoot);
}
return QModelIndex();
}
int rowCount(const QModelIndex& rkParent) const
{
CVirtualDirectory *pDir = IndexDirectory(rkParent);
if (pDir) return pDir->NumSubdirectories();
else return mpRoot ? 1 : 0;
}
int columnCount(const QModelIndex& /*rkParent*/) const
{
return 1;
}
QVariant data(const QModelIndex& rkIndex, int Role) const
{
if (Role == Qt::DisplayRole || Role == Qt::ToolTipRole)
{
CVirtualDirectory *pDir = IndexDirectory(rkIndex);
if (pDir) return TO_QSTRING(pDir->Name());
}
if (Role == Qt::DecorationRole)
{
return QIcon(":/icons/Open_24px.png");
}
return QVariant::Invalid;
}
inline CVirtualDirectory* IndexDirectory(const QModelIndex& rkIndex) const
{
if (!rkIndex.isValid()) return nullptr;
return static_cast<CVirtualDirectory*>(rkIndex.internalPointer());
}
inline void SetRoot(CVirtualDirectory *pDir)
{
beginResetModel();
mpRoot = pDir;
endResetModel();
}
};
#endif // CVIRTUALDIRECTORYMODEL