Modified resource browser to use a filesystem browser view

This commit is contained in:
Aruki 2017-02-01 20:23:51 -07:00
parent c51d79cc42
commit 548fcb2f8e
8 changed files with 309 additions and 80 deletions

View File

@ -34,7 +34,7 @@ void CEditorApplication::InitEditor()
mpWorldEditor = new CWorldEditor();
mpResourceBrowser = new CResourceBrowser(mpWorldEditor);
mpProjectDialog = new CProjectOverviewDialog();
connect(mpProjectDialog, SIGNAL(ActiveProjectChanged(CGameProject*)), mpResourceBrowser, SLOT(RefreshResources()));
connect(mpProjectDialog, SIGNAL(ActiveProjectChanged(CGameProject*)), mpResourceBrowser, SLOT(UpdateStore()));
}
void CEditorApplication::EditResource(CResourceEntry *pEntry)

View File

@ -666,7 +666,8 @@ void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelInde
if (Type == eAssetProperty)
{
Params.SetResource( static_cast<CResourceSelector*>(pEditor)->Entry()->ID() );
CResourceEntry *pEntry = static_cast<CResourceSelector*>(pEditor)->Entry();
Params.SetResource( pEntry ? pEntry->ID() : CAssetID::InvalidID(mpEditor->CurrentGame()) );
}
else if (Type == eEnumProperty)

View File

@ -12,6 +12,8 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
, mpUI(new Ui::CResourceBrowser)
, mpSelectedEntry(nullptr)
, mpStore(gpResourceStore)
, mpSelectedDir(nullptr)
, mSearching(false)
{
mpUI->setupUi(this);
setWindowFlags(windowFlags() | Qt::WindowMinimizeButtonHint);
@ -49,11 +51,11 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
pImportNamesMenu->addAction(pImportFromAssetNameMapAction);
// Set up connections
connect(mpUI->StoreComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(RefreshResources()));
connect(mpUI->StoreComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateStore()));
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)));
connect(mpUI->ResourceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnDoubleClickResource(QModelIndex)));
connect(mpUI->ResourceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnDoubleClickTable(QModelIndex)));
connect(mpUI->ResourceTableView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnResourceSelectionChanged(QModelIndex, QModelIndex)));
connect(pImportFromContentsTxtAction, SIGNAL(triggered()), this, SLOT(OnImportPakContentsTxt()));
connect(pImportFromAssetNameMapAction, SIGNAL(triggered()), this, SLOT(OnImportNamesFromAssetNameMap()));
@ -73,16 +75,56 @@ CResourceBrowser::~CResourceBrowser()
void CResourceBrowser::RefreshResources()
{
// Fill resource table
mpStore = (mpUI->StoreComboBox->currentIndex() == 0 ? gpResourceStore : gpEditorStore);
mpModel->FillEntryList(mpStore);
mpModel->FillEntryList(mpSelectedDir, mSearching);
// Fill directory tree
// Mark directories to span all three columns
mpUI->ResourceTableView->clearSpans();
for (u32 iDir = 0; iDir < mpModel->NumDirectories(); iDir++)
mpUI->ResourceTableView->setSpan(iDir, 0, 1, 3);
}
void CResourceBrowser::UpdateDescriptionLabel()
{
QString Desc;
bool ValidDir = mpSelectedDir && !mpSelectedDir->IsRoot();
QString Path = (ValidDir ? '\\' + TO_QSTRING(mpSelectedDir->FullPath()) : "");
if (mSearching)
{
QString SearchText = mpUI->SearchBar->text();
Desc = QString("Searching \"%1\"").arg(SearchText);
if (ValidDir)
Desc += QString(" in %1").arg(Path);
}
else
{
if (ValidDir)
Desc = Path;
}
mpUI->TableDescriptionLabel->setText(Desc);
}
void CResourceBrowser::UpdateStore()
{
int StoreIndex = mpUI->StoreComboBox->currentIndex();
CResourceStore *pNewStore = (StoreIndex == 0 ? gpResourceStore : gpEditorStore);
if (mpStore != pNewStore)
{
mpStore = pNewStore;
// Refresh directory tree
mpDirectoryModel->SetRoot(mpStore ? mpStore->RootDirectory() : nullptr);
QModelIndex RootIndex = mpDirectoryModel->index(0, 0, QModelIndex());
mpUI->DirectoryTreeView->expand(RootIndex);
mpUI->DirectoryTreeView->clearSelection();
OnDirectorySelectionChanged(QModelIndex(), QModelIndex());
}
}
void CResourceBrowser::OnSortModeChanged(int Index)
{
@ -98,20 +140,34 @@ void CResourceBrowser::OnSearchStringChanged()
void CResourceBrowser::OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& /*rkPrevIndex*/)
{
CVirtualDirectory *pDir = nullptr;
if (rkNewIndex.isValid())
pDir = mpDirectoryModel->IndexDirectory(rkNewIndex);
mpSelectedDir = mpDirectoryModel->IndexDirectory(rkNewIndex);
else
mpSelectedDir = mpStore ? mpStore->RootDirectory() : nullptr;
mpProxyModel->SetDirectory(pDir);
UpdateDescriptionLabel();
RefreshResources();
}
void CResourceBrowser::OnDoubleClickResource(QModelIndex Index)
void CResourceBrowser::OnDoubleClickTable(QModelIndex Index)
{
QModelIndex SourceIndex = mpProxyModel->mapToSource(Index);
// Directory - switch to the selected directory
if (mpModel->IsIndexDirectory(SourceIndex))
{
CVirtualDirectory *pDir = mpModel->IndexDirectory(SourceIndex);
QModelIndex Index = mpDirectoryModel->GetIndexForDirectory(pDir);
mpUI->DirectoryTreeView->selectionModel()->setCurrentIndex(Index, QItemSelectionModel::ClearAndSelect);
}
// Resource - open resource for editing
else
{
CResourceEntry *pEntry = mpModel->IndexEntry(SourceIndex);
gpEdApp->EditResource(pEntry);
}
}
void CResourceBrowser::OnResourceSelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& /*rkPrevIndex*/)
{
@ -167,5 +223,15 @@ void CResourceBrowser::ExportAssetNames()
void CResourceBrowser::UpdateFilter()
{
QString SearchText = mpUI->SearchBar->text();
bool NewSearching = !SearchText.isEmpty();
if (mSearching != NewSearching)
{
mSearching = NewSearching;
RefreshResources();
}
UpdateDescriptionLabel();
mpProxyModel->SetSearchString( TO_TWIDESTRING(mpUI->SearchBar->text()) );
}

View File

@ -19,8 +19,10 @@ class CResourceBrowser : public QDialog
CResourceStore *mpStore;
CResourceTableModel *mpModel;
CResourceProxyModel *mpProxyModel;
CVirtualDirectory *mpSelectedDir;
CVirtualDirectoryModel *mpDirectoryModel;
QTimer mUpdateFilterTimer;
bool mSearching;
public:
explicit CResourceBrowser(QWidget *pParent = 0);
@ -31,10 +33,12 @@ public:
public slots:
void RefreshResources();
void UpdateDescriptionLabel();
void UpdateStore();
void OnSortModeChanged(int Index);
void OnSearchStringChanged();
void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex);
void OnDoubleClickResource(QModelIndex Index);
void OnDoubleClickTable(QModelIndex Index);
void OnResourceSelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex);
void OnImportPakContentsTxt();
void OnGenerateAssetNames();

View File

@ -149,6 +149,42 @@
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="TableContainerWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>3</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<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="QLabel" name="TableDescriptionLabel">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QTableView" name="ResourceTableView">
<property name="sizePolicy">
@ -199,6 +235,9 @@
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -39,25 +39,40 @@ public:
bool lessThan(const QModelIndex& rkLeft, const QModelIndex& rkRight) const
{
CResourceEntry *pLeft = mpModel->IndexEntry(rkLeft);
CResourceEntry *pRight = mpModel->IndexEntry(rkRight);
CVirtualDirectory *pLeftDir = mpModel->IndexDirectory(rkLeft);
CVirtualDirectory *pRightDir = mpModel->IndexDirectory(rkRight);
CResourceEntry *pLeftRes = mpModel->IndexEntry(rkLeft);
CResourceEntry *pRightRes = mpModel->IndexEntry(rkRight);
if (pLeftDir && !pRightDir)
return true;
else if (pRightDir && !pLeftDir)
return false;
else if (pLeftDir && pRightDir)
return rkLeft.row() < rkRight.row(); // leave original directory order intact
else if (mSortMode == eSortByName)
return pLeftRes->UppercaseName() < pRightRes->UppercaseName();
if (mSortMode == eSortByName)
return pLeft->UppercaseName() < pRight->UppercaseName();
else
return pLeft->Size() < pRight->Size();
return pLeftRes->Size() < pRightRes->Size();
}
bool filterAcceptsRow(int SourceRow, const QModelIndex& rkSourceParent) const
{
QModelIndex Index = mpModel->index(SourceRow, 0, rkSourceParent);
CVirtualDirectory *pDir = mpModel->IndexDirectory(Index);
CResourceEntry *pEntry = mpModel->IndexEntry(Index);
if (mpDirectory && !pEntry->IsInDirectory(mpDirectory))
return false;
if (!mSearchString.IsEmpty() && !pEntry->UppercaseName().Contains(mSearchString))
if (!mSearchString.IsEmpty())
{
if (pDir)
return false;
else
return pEntry->UppercaseName().Contains(mSearchString);
}
return true;
}

View File

@ -12,7 +12,10 @@
class CResourceTableModel : public QAbstractTableModel
{
Q_OBJECT
QList<CVirtualDirectory*> mDirectories;
QList<CResourceEntry*> mEntries;
bool mHasParent;
public:
CResourceTableModel(QObject *pParent = 0)
@ -21,7 +24,7 @@ public:
int rowCount(const QModelIndex& /*rkParent*/) const
{
return mEntries.size();
return mDirectories.size() + mEntries.size();
}
int columnCount(const QModelIndex& /*rkParent*/) const
@ -31,9 +34,29 @@ public:
QVariant data(const QModelIndex& rkIndex, int Role) const
{
CResourceEntry *pEntry = mEntries[rkIndex.row()];
u32 Col = rkIndex.column();
// Directory
if (IsIndexDirectory(rkIndex))
{
if (Col != 0)
return QVariant::Invalid;
CVirtualDirectory *pDir = IndexDirectory(rkIndex);
if (Role == Qt::DisplayRole || Role == Qt::ToolTipRole)
return (mHasParent && rkIndex.row() == 0 ? ".." : TO_QSTRING(pDir->Name()));
else if (Role == Qt::DecorationRole)
return QIcon(":/icons/Open_24px.png");
else
return QVariant::Invalid;
}
// Resource
CResourceEntry *pEntry = IndexEntry(rkIndex);
if (Role == Qt::DisplayRole)
{
if (Col == 0)
@ -64,28 +87,73 @@ public:
CResourceEntry* IndexEntry(const QModelIndex& rkIndex) const
{
return mEntries[rkIndex.row()];
int Index = rkIndex.row() - mDirectories.size();
return (Index >= 0 ? mEntries[Index] : nullptr);
}
void FillEntryList(CResourceStore *pStore)
CVirtualDirectory* IndexDirectory(const QModelIndex& rkIndex) const
{
return (rkIndex.row() < mDirectories.size() ? mDirectories[rkIndex.row()] : nullptr);
}
bool IsIndexDirectory(const QModelIndex& rkIndex) const
{
return rkIndex.row() < mDirectories.size();
}
void FillEntryList(CVirtualDirectory *pDir, bool IsSearching)
{
beginResetModel();
mEntries.clear();
mDirectories.clear();
mHasParent = false;
if (pStore)
if (pDir)
{
for (CResourceIterator It(pStore); It; ++It)
// When not searching, show only subdirectories and assets in the current directory.
if (!IsSearching)
{
if (It->IsTransient()) continue;
CResTypeInfo *pInfo = It->TypeInfo();
if (pInfo->IsVisibleInBrowser() && !It->IsHidden())
mEntries << *It;
if (!pDir->IsRoot())
{
mDirectories << pDir->Parent();
mHasParent = true;
}
for (u32 iDir = 0; iDir < pDir->NumSubdirectories(); iDir++)
mDirectories << pDir->SubdirectoryByIndex(iDir);
for (u32 iRes = 0; iRes < pDir->NumResources(); iRes++)
{
CResourceEntry *pEntry = pDir->ResourceByIndex(iRes);
if (pEntry->TypeInfo()->IsVisibleInBrowser() && !pEntry->IsHidden())
mEntries << pEntry;
}
}
// When searching, do not show subdirectories and show all assets in current directory + all subdirectories.
else
RecursiveAddDirectoryContents(pDir);
}
endResetModel();
}
protected:
void RecursiveAddDirectoryContents(CVirtualDirectory *pDir)
{
for (u32 iRes = 0; iRes < pDir->NumResources(); iRes++)
mEntries << pDir->ResourceByIndex(iRes);
for (u32 iDir = 0; iDir < pDir->NumSubdirectories(); iDir++)
RecursiveAddDirectoryContents(pDir->SubdirectoryByIndex(iDir));
}
public:
// Accessors
inline u32 NumDirectories() const { return mDirectories.size(); }
inline u32 NumResources() const { return mEntries.size(); }
};
#endif // CRESOURCELISTMODEL

View File

@ -85,6 +85,42 @@ public:
return QVariant::Invalid;
}
QModelIndex GetIndexForDirectory(CVirtualDirectory *pDir)
{
QVector<int> Indices;
CVirtualDirectory *pOriginal = pDir;
CVirtualDirectory *pParent = pDir->Parent();
// Get index list
while (pParent)
{
bool Found = false;
for (u32 iDir = 0; iDir < pParent->NumSubdirectories(); iDir++)
{
if (pParent->SubdirectoryByIndex(iDir) == pDir)
{
Indices.push_front(iDir);
pDir = pParent;
pParent = pParent->Parent();
Found = true;
break;
}
}
ASSERT(Found); // it should not be possible for this not to work
}
// Traverse hierarchy
QModelIndex Out = index(0, 0, QModelIndex());
foreach (int Idx, Indices)
Out = index(Idx, 0, Out);
ASSERT(IndexDirectory(Out) == pOriginal);
return Out;
}
inline CVirtualDirectory* IndexDirectory(const QModelIndex& rkIndex) const
{
if (!rkIndex.isValid()) return nullptr;