From 89d668a8103bfb27d4e46dc92131c38ab8484960 Mon Sep 17 00:00:00 2001 From: Aruki Date: Thu, 20 Jul 2017 20:56:29 -0600 Subject: [PATCH] Added ability to display referencers/dependencies of assets --- src/Core/GameProject/CDependencyTree.cpp | 11 ++ src/Core/GameProject/CDependencyTree.h | 2 + src/Core/Resource/CWorld.cpp | 11 ++ src/Core/Resource/CWorld.h | 1 + src/Editor/CEditorApplication.cpp | 20 +- .../ResourceBrowser/CResourceBrowser.cpp | 187 +++++++++++++----- src/Editor/ResourceBrowser/CResourceBrowser.h | 17 +- .../ResourceBrowser/CResourceBrowser.ui | 55 ++++-- .../ResourceBrowser/CResourceProxyModel.h | 11 ++ .../CResourceTableContextMenu.cpp | 76 ++++++- .../CResourceTableContextMenu.h | 10 +- .../ResourceBrowser/CResourceTableModel.cpp | 23 +++ .../ResourceBrowser/CResourceTableModel.h | 12 +- .../ResourceBrowser/CResourceTableView.h | 6 + 14 files changed, 363 insertions(+), 79 deletions(-) diff --git a/src/Core/GameProject/CDependencyTree.cpp b/src/Core/GameProject/CDependencyTree.cpp index 82da94f8..43774dd9 100644 --- a/src/Core/GameProject/CDependencyTree.cpp +++ b/src/Core/GameProject/CDependencyTree.cpp @@ -25,6 +25,12 @@ bool IDependencyNode::HasDependency(const CAssetID& rkID) const return false; } +void IDependencyNode::GetAllResourceReferences(std::set& rOutSet) const +{ + for (u32 iChild = 0; iChild < mChildren.size(); iChild++) + mChildren[iChild]->GetAllResourceReferences(rOutSet); +} + // ************ CDependencyTree ************ EDependencyNodeType CDependencyTree::Type() const { @@ -75,6 +81,11 @@ void CResourceDependency::Serialize(IArchive& rArc) rArc << SERIAL("ID", mID); } +void CResourceDependency::GetAllResourceReferences(std::set& rOutSet) const +{ + rOutSet.insert(mID); +} + bool CResourceDependency::HasDependency(const CAssetID& rkID) const { return (mID == rkID); diff --git a/src/Core/GameProject/CDependencyTree.h b/src/Core/GameProject/CDependencyTree.h index faa6c5c5..987f92b3 100644 --- a/src/Core/GameProject/CDependencyTree.h +++ b/src/Core/GameProject/CDependencyTree.h @@ -37,6 +37,7 @@ public: virtual ~IDependencyNode(); virtual EDependencyNodeType Type() const = 0; virtual void Serialize(IArchive& rArc) = 0; + virtual void GetAllResourceReferences(std::set& rOutSet) const; virtual bool HasDependency(const CAssetID& rkID) const; // Accessors @@ -71,6 +72,7 @@ public: virtual EDependencyNodeType Type() const; virtual void Serialize(IArchive& rArc); + virtual void GetAllResourceReferences(std::set& rOutSet) const; virtual bool HasDependency(const CAssetID& rkID) const; // Accessors diff --git a/src/Core/Resource/CWorld.cpp b/src/Core/Resource/CWorld.cpp index 0a1f59d5..ac411549 100644 --- a/src/Core/Resource/CWorld.cpp +++ b/src/Core/Resource/CWorld.cpp @@ -78,6 +78,17 @@ TString CWorld::AreaInGameName(u32 AreaIndex) const return "!!" + rkArea.InternalName; } +u32 CWorld::AreaIndex(CAssetID AreaID) const +{ + for (u32 AreaIdx = 0; AreaIdx < mAreas.size(); AreaIdx++) + { + if (mAreas[AreaIdx].AreaResID == AreaID) + return AreaIdx; + } + + return -1; +} + // ************ SERIALIZATION ************ void CWorld::Serialize(IArchive& rArc) { diff --git a/src/Core/Resource/CWorld.h b/src/Core/Resource/CWorld.h index 8680f64b..01cffd72 100644 --- a/src/Core/Resource/CWorld.h +++ b/src/Core/Resource/CWorld.h @@ -94,6 +94,7 @@ public: void SetAreaLayerInfo(CGameArea *pArea); TString InGameName() const; TString AreaInGameName(u32 AreaIndex) const; + u32 AreaIndex(CAssetID AreaID) const; // Serialization virtual void Serialize(IArchive& rArc); diff --git a/src/Editor/CEditorApplication.cpp b/src/Editor/CEditorApplication.cpp index 4bfc70fc..6db6c666 100644 --- a/src/Editor/CEditorApplication.cpp +++ b/src/Editor/CEditorApplication.cpp @@ -127,6 +127,24 @@ void CEditorApplication::EditResource(CResourceEntry *pEntry) switch (pEntry->ResourceType()) { + case eArea: + // We can't open an area on its own. Find a world that contains this area. + for (TResourceIterator It; It; ++It) + { + if (It->Dependencies()->HasDependency(pEntry->ID())) + { + CWorld *pWorld = (CWorld*) It->Load(); + u32 AreaIdx = pWorld->AreaIndex(pEntry->ID()); + + if (AreaIdx != -1) + { + mpWorldEditor->SetArea(pWorld, AreaIdx); + break; + } + } + } + break; + case eModel: pEd = new CModelEditorWindow((CModel*) pRes, mpWorldEditor); break; @@ -141,7 +159,7 @@ void CEditorApplication::EditResource(CResourceEntry *pEntry) pEd->show(); mEditingMap[pEntry] = pEd; } - else + else if (pEntry->ResourceType() != eArea) UICommon::InfoMsg(mpWorldEditor, "Unsupported Resource", "This resource type is currently unsupported for editing."); } } diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.cpp b/src/Editor/ResourceBrowser/CResourceBrowser.cpp index 57fedd9f..74021df2 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.cpp +++ b/src/Editor/ResourceBrowser/CResourceBrowser.cpp @@ -27,6 +27,7 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) , mEditorStore(false) , mAssetListMode(false) , mSearching(false) + , mpInspectedEntry(nullptr) { mpUI->setupUi(this); @@ -70,6 +71,7 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) mpUI->DirectoryTreeView->setModel(mpDirectoryModel); RefreshResources(); + UpdateDescriptionLabel(); // Set up filter checkboxes mpFilterBoxesLayout = new QVBoxLayout(); @@ -142,9 +144,12 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) connect(mpUI->ResourceListButton, SIGNAL(pressed()), this, SLOT(SetResourceListView())); connect(mpUI->SortComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSortModeChanged(int))); connect(mpUI->NewFolderButton, SIGNAL(pressed()), this, SLOT(CreateDirectory())); - connect(mpUI->DirectoryTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex,QModelIndex))); + connect(mpUI->ClearButton, SIGNAL(pressed()), this, SLOT(OnClearButtonPressed())); + + connect(mpUI->DirectoryTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex))); + connect(mpUI->DirectoryTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnDirectorySelectionChanged(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(mpUI->ResourceTableView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnResourceSelectionChanged(QModelIndex))); connect(mpProxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), mpUI->ResourceTableView, SLOT(resizeRowsToContents())); connect(mpProxyModel, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), mpUI->ResourceTableView, SLOT(resizeRowsToContents())); connect(mpFilterAllBox, SIGNAL(toggled(bool)), this, SLOT(OnFilterTypeBoxTicked(bool))); @@ -156,12 +161,28 @@ CResourceBrowser::~CResourceBrowser() delete mpUI; } +void CResourceBrowser::SetActiveDirectory(CVirtualDirectory *pDir) +{ + if (mpSelectedDir != pDir || mpModel->IsDisplayingUserEntryList()) + { + mpSelectedDir = pDir; + RefreshResources(); + UpdateDescriptionLabel(); + + if (sender() != mpUI->DirectoryTreeView) + { + QModelIndex Index = mpDirectoryModel->GetIndexForDirectory(pDir); + mpUI->DirectoryTreeView->selectionModel()->setCurrentIndex(Index, QItemSelectionModel::ClearAndSelect); + } + } +} + void CResourceBrowser::SelectResource(CResourceEntry *pEntry) { ASSERT(pEntry); - // Select target directory - SelectDirectory(pEntry->Directory()); + // Set directory active + SetActiveDirectory(pEntry->Directory()); // Clear search if (!mpUI->SearchBar->text().isEmpty()) @@ -173,14 +194,37 @@ void CResourceBrowser::SelectResource(CResourceEntry *pEntry) // Select resource QModelIndex SourceIndex = mpModel->GetIndexForEntry(pEntry); QModelIndex ProxyIndex = mpProxyModel->mapFromSource(SourceIndex); - mpUI->ResourceTableView->selectionModel()->select(ProxyIndex, QItemSelectionModel::ClearAndSelect); - mpUI->ResourceTableView->scrollTo(ProxyIndex, QAbstractItemView::PositionAtCenter); + + if (ProxyIndex.isValid()) + { + // Note: We have to call scrollToBottom() first or else sometimes scrollTo() doesn't work at all + // in large folders (like Uncategorized). Dumb but the only solution I've been able to figure out. + mpUI->ResourceTableView->selectionModel()->select(ProxyIndex, QItemSelectionModel::ClearAndSelect); + mpUI->ResourceTableView->scrollToBottom(); + mpUI->ResourceTableView->scrollTo(ProxyIndex, QAbstractItemView::PositionAtCenter); + } } void CResourceBrowser::SelectDirectory(CVirtualDirectory *pDir) { - QModelIndex Index = mpDirectoryModel->GetIndexForDirectory(pDir); - mpUI->DirectoryTreeView->selectionModel()->setCurrentIndex(Index, QItemSelectionModel::ClearAndSelect); + ASSERT(pDir); + ASSERT(!pDir->IsRoot()); + + // Set parent directory active + SetActiveDirectory(pDir->Parent()); + + // Clear search + if (!mpUI->SearchBar->text().isEmpty()) + { + mpUI->SearchBar->clear(); + UpdateFilter(); + } + + // Select directory + QModelIndex SourceIndex = mpModel->GetIndexForDirectory(pDir); + QModelIndex ProxyIndex = mpProxyModel->mapFromSource(SourceIndex); + mpUI->ResourceTableView->selectionModel()->select(ProxyIndex, QItemSelectionModel::ClearAndSelect); + mpUI->ResourceTableView->scrollTo(ProxyIndex, QAbstractItemView::PositionAtCenter); } void CResourceBrowser::CreateFilterCheckboxes() @@ -353,30 +397,27 @@ void CResourceBrowser::RefreshDirectories() void CResourceBrowser::UpdateDescriptionLabel() { + // Update main description label QString Desc; - Desc += (mAssetListMode ? "[Assets]" : "[Filesystem]"); - Desc += " "; - bool ValidDir = mpSelectedDir && !mpSelectedDir->IsRoot(); - QString Path = (ValidDir ? '/' + TO_QSTRING(mpSelectedDir->FullPath()) : ""); - - if (mSearching) + if (mpStore) { - QString SearchText = mpUI->SearchBar->text(); - Desc += QString("Searching \"%1\"").arg(SearchText); + QString ModelDesc = mpModel->ModelDescription(); - if (ValidDir) - Desc += QString(" in %1").arg(Path); - } - else - { - if (ValidDir) - Desc += Path; + if (mSearching) + { + QString SearchText = mpUI->SearchBar->text(); + Desc = QString("Searching \"%1\" in: %2").arg(SearchText).arg(ModelDesc); + } else - Desc += "Root"; + Desc = QString("Displaying: %1").arg(ModelDesc); } mpUI->TableDescriptionLabel->setText(Desc); + + // Update clear button status + bool EnableClearButton = (!mpUI->SearchBar->text().isEmpty() || mpModel->IsDisplayingUserEntryList() || (mpSelectedDir && !mpSelectedDir->IsRoot())); + mpUI->ClearButton->setEnabled(EnableClearButton); } void CResourceBrowser::SetResourceTreeView() @@ -391,6 +432,30 @@ void CResourceBrowser::SetResourceListView() RefreshResources(); } +void CResourceBrowser::OnClearButtonPressed() +{ + if (!mpUI->SearchBar->text().isEmpty()) + { + ResetSearch(); + } + else if (mpModel->IsDisplayingUserEntryList()) + { + RefreshResources(); + + if (mpInspectedEntry) + { + SelectResource(mpInspectedEntry); + mpInspectedEntry = nullptr; + } + } + else + { + SelectDirectory(mpSelectedDir); + } + + UpdateDescriptionLabel(); +} + void CResourceBrowser::OnSortModeChanged(int Index) { CResourceProxyModel::ESortMode Mode = (Index == 0 ? CResourceProxyModel::eSortByName : CResourceProxyModel::eSortBySize); @@ -461,31 +526,29 @@ bool CResourceBrowser::DeleteDirectories(const QList& rkDirs void CResourceBrowser::OnSearchStringChanged(QString SearchString) { - bool WasSearching = mSearching; + bool WasAssetList = InAssetListMode(); mSearching = !SearchString.isEmpty(); + bool IsAssetList = InAssetListMode(); // Check if we need to change to/from asset list mode to display/stop displaying search results - if (!mAssetListMode) + if (WasAssetList != IsAssetList) { - if ( (mSearching && !WasSearching) || - (!mSearching && WasSearching) ) - { - RefreshResources(); - } + RefreshResources(); } UpdateFilter(); } -void CResourceBrowser::OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& /*rkPrevIndex*/) +void CResourceBrowser::OnDirectorySelectionChanged(const QModelIndex& rkNewIndex) { - if (rkNewIndex.isValid()) - mpSelectedDir = mpDirectoryModel->IndexDirectory(rkNewIndex); - else - mpSelectedDir = mpStore ? mpStore->RootDirectory() : nullptr; + CVirtualDirectory *pDir = nullptr; - UpdateDescriptionLabel(); - RefreshResources(); + if (rkNewIndex.isValid()) + pDir = mpDirectoryModel->IndexDirectory(rkNewIndex); + else + pDir = mpStore ? mpStore->RootDirectory() : nullptr; + + SetActiveDirectory(pDir); } void CResourceBrowser::OnDoubleClickTable(QModelIndex Index) @@ -496,7 +559,11 @@ void CResourceBrowser::OnDoubleClickTable(QModelIndex Index) if (mpModel->IsIndexDirectory(SourceIndex)) { CVirtualDirectory *pDir = mpModel->IndexDirectory(SourceIndex); - SelectDirectory(pDir); + CVirtualDirectory *pOldDir = mpSelectedDir; + SetActiveDirectory(pDir); + + if (pOldDir->Parent() == pDir) + SelectDirectory(pOldDir); } // Resource - open resource for editing @@ -507,7 +574,7 @@ void CResourceBrowser::OnDoubleClickTable(QModelIndex Index) } } -void CResourceBrowser::OnResourceSelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& /*rkPrevIndex*/) +void CResourceBrowser::OnResourceSelectionChanged(const QModelIndex& rkNewIndex) { QModelIndex SourceIndex = mpProxyModel->mapToSource(rkNewIndex); mpSelectedEntry = mpModel->IndexEntry(SourceIndex); @@ -542,7 +609,7 @@ void CResourceBrowser::UpdateStore() QModelIndex RootIndex = mpDirectoryModel->index(0, 0, QModelIndex()); mpUI->DirectoryTreeView->expand(RootIndex); mpUI->DirectoryTreeView->clearSelection(); - OnDirectorySelectionChanged(QModelIndex(), QModelIndex()); + OnDirectorySelectionChanged(QModelIndex()); } } @@ -562,7 +629,7 @@ void CResourceBrowser::ImportPackageContentsList() { QStringList PathList = UICommon::OpenFilesDialog(this, "Open package contents list", "*.pak.contents.txt"); if (PathList.isEmpty()) return; - SelectDirectory(nullptr); + SetActiveDirectory(nullptr); foreach(const QString& rkPath, PathList) mpStore->ImportNamesFromPakContentsTxt(TO_TSTRING(rkPath), false); @@ -573,7 +640,7 @@ void CResourceBrowser::ImportPackageContentsList() void CResourceBrowser::GenerateAssetNames() { - SelectDirectory(nullptr); + SetActiveDirectory(nullptr); CProgressDialog Dialog("Generating asset names", true, true, this); Dialog.DisallowCanceling(); @@ -607,7 +674,7 @@ void CResourceBrowser::ImportAssetNameMap() return; } - SelectDirectory(nullptr); + SetActiveDirectory(nullptr); for (CResourceIterator It(mpStore); It; ++It) { @@ -660,19 +727,29 @@ void CResourceBrowser::RebuildResourceDB() } } -void CResourceBrowser::UpdateFilter() +void CResourceBrowser::ClearFilters() { - QString SearchText = mpUI->SearchBar->text(); - mSearching = !SearchText.isEmpty(); + ResetSearch(); + ResetTypeFilter(); +} - UpdateDescriptionLabel(); - mpProxyModel->SetSearchString( TO_TSTRING(mpUI->SearchBar->text()) ); - mpProxyModel->invalidate(); +void CResourceBrowser::ResetSearch() +{ + bool WasAssetList = InAssetListMode(); + mpUI->SearchBar->clear(); + mSearching = false; + bool IsAssetList = InAssetListMode(); + + if (IsAssetList != WasAssetList) + RefreshResources(); + + UpdateFilter(); } void CResourceBrowser::ResetTypeFilter() { mpFilterAllBox->setChecked(true); + UpdateFilter(); } void CResourceBrowser::OnFilterTypeBoxTicked(bool Checked) @@ -715,6 +792,16 @@ void CResourceBrowser::OnFilterTypeBoxTicked(bool Checked) ReentrantGuard = false; } +void CResourceBrowser::UpdateFilter() +{ + QString SearchText = mpUI->SearchBar->text(); + mSearching = !SearchText.isEmpty(); + + UpdateDescriptionLabel(); + mpProxyModel->SetSearchString( TO_TSTRING(mpUI->SearchBar->text()) ); + mpProxyModel->invalidate(); +} + void CResourceBrowser::UpdateUndoActionStates() { // Make sure that the undo actions are only enabled when the table view has focus. diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.h b/src/Editor/ResourceBrowser/CResourceBrowser.h index cf846016..00130f2c 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.h +++ b/src/Editor/ResourceBrowser/CResourceBrowser.h @@ -48,10 +48,14 @@ class CResourceBrowser : public QWidget QAction *mpRedoAction; QWidget *mpActionContainerWidget; + // Misc + CResourceEntry *mpInspectedEntry; // Entry being "inspected" (viewing dependencies/referencers, etc) + public: explicit CResourceBrowser(QWidget *pParent = 0); ~CResourceBrowser(); + void SetActiveDirectory(CVirtualDirectory *pDir); void SelectResource(CResourceEntry *pEntry); void SelectDirectory(CVirtualDirectory *pDir); void CreateFilterCheckboxes(); @@ -66,7 +70,9 @@ public: // Accessors inline CResourceStore* CurrentStore() const { return mpStore; } inline CResourceEntry* SelectedEntry() const { return mpSelectedEntry; } - inline bool InAssetListMode() const { return mAssetListMode || mSearching; } + inline bool InAssetListMode() const { return mAssetListMode || mSearching || mpModel->IsDisplayingUserEntryList(); } + + inline void SetInspectedEntry(CResourceEntry *pEntry) { mpInspectedEntry = pEntry; } public slots: void RefreshResources(); @@ -74,13 +80,14 @@ public slots: void UpdateDescriptionLabel(); void SetResourceTreeView(); void SetResourceListView(); + void OnClearButtonPressed(); void OnSortModeChanged(int Index); bool CreateDirectory(); bool DeleteDirectories(const QList& rkDirs); void OnSearchStringChanged(QString SearchString); - void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex); + void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex); void OnDoubleClickTable(QModelIndex Index); - void OnResourceSelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex); + void OnResourceSelectionChanged(const QModelIndex& rkNewIndex); void SetAssetIdDisplayEnabled(bool Enable); void UpdateStore(); @@ -91,10 +98,12 @@ public slots: void ImportAssetNameMap(); void ExportAssetNames(); void RebuildResourceDB(); - void UpdateFilter(); + void ClearFilters(); + void ResetSearch(); void ResetTypeFilter(); void OnFilterTypeBoxTicked(bool Checked); + void UpdateFilter(); void UpdateUndoActionStates(); void Undo(); diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.ui b/src/Editor/ResourceBrowser/CResourceBrowser.ui index 2028f322..61d0cdc6 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.ui +++ b/src/Editor/ResourceBrowser/CResourceBrowser.ui @@ -180,22 +180,43 @@ - - - - 0 - 0 - - - - - 8 - - - - - - + + + + + + 0 + 0 + + + + + 8 + + + + + + + + + + + + 20 + 20 + + + + + + + + :/icons/X_16px.png:/icons/X_16px.png + + + + @@ -227,7 +248,7 @@ 0 0 209 - 190 + 187 diff --git a/src/Editor/ResourceBrowser/CResourceProxyModel.h b/src/Editor/ResourceBrowser/CResourceProxyModel.h index e5d4867a..55476c6c 100644 --- a/src/Editor/ResourceBrowser/CResourceProxyModel.h +++ b/src/Editor/ResourceBrowser/CResourceProxyModel.h @@ -39,6 +39,17 @@ public: bool lessThan(const QModelIndex& rkLeft, const QModelIndex& rkRight) const { + // Parent directory is always row 0 and should always be at the top + if (mpModel->HasParentDirectoryEntry()) + { + if (rkLeft.row() == 0) + return true; + + if (rkRight.row() == 0) + return false; + } + + // Fetch directories and compare them CVirtualDirectory *pLeftDir = mpModel->IndexDirectory(rkLeft); CVirtualDirectory *pRightDir = mpModel->IndexDirectory(rkRight); CResourceEntry *pLeftRes = mpModel->IndexEntry(rkLeft); diff --git a/src/Editor/ResourceBrowser/CResourceTableContextMenu.cpp b/src/Editor/ResourceBrowser/CResourceTableContextMenu.cpp index 31041c18..ae8c9ab1 100644 --- a/src/Editor/ResourceBrowser/CResourceTableContextMenu.cpp +++ b/src/Editor/ResourceBrowser/CResourceTableContextMenu.cpp @@ -16,11 +16,22 @@ CResourceTableContextMenu::CResourceTableContextMenu(CResourceBrowser *pBrowser, connect(pView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowMenu(QPoint))); // Create actions +#if WIN32 + QString OpenInExplorerString = "Show in Explorer"; +#elif __APPLE__ + QString OpenInExplorerString = "Show in Finder"; +#else + QString OpenInExplorerString = "Show in file manager"; +#endif + mpOpenAction = addAction("Open", this, SLOT(Open())); mpOpenInExternalAppAction = addAction("Open in external application", this, SLOT(OpenInExternalApp())); - mpOpenContainingFolderAction = addAction("Open containing folder", this, SLOT(OpenContainingFolder())); + mpOpenInExplorerAction = addAction(OpenInExplorerString, this, SLOT(OpenInExplorer())); + mpSelectFolderAction = addAction("Select folder", this, SLOT(SelectFolder())); addSeparator(); mpRenameAction = addAction("Rename", this, SLOT(Rename())); + mpShowReferencersAction = addAction("Show referencers", this, SLOT(ShowReferencers())); + mpShowDependenciesAction = addAction("Show dependencies", this, SLOT(ShowDependencies())); addSeparator(); mpCopyNameAction = addAction("Copy name", this, SLOT(CopyName())); mpCopyPathAction = addAction("Copy path", this, SLOT(CopyPath())); @@ -41,6 +52,9 @@ void CResourceTableContextMenu::ShowMenu(const QPoint& rkPos) // Show/hide menu options bool IsRes = (mpEntry != nullptr); mpOpenInExternalAppAction->setVisible(IsRes); + mpSelectFolderAction->setVisible(mpModel->IsDisplayingAssetList()); + mpShowDependenciesAction->setVisible(IsRes); + mpShowReferencersAction->setVisible(IsRes); mpCopyIDAction->setVisible(IsRes); // Exec menu @@ -55,7 +69,7 @@ void CResourceTableContextMenu::Open() if (mpEntry) gpEdApp->EditResource(mpEntry); else - mpBrowser->SelectDirectory(mpDirectory); + mpBrowser->SetActiveDirectory(mpDirectory); } void CResourceTableContextMenu::OpenInExternalApp() @@ -64,7 +78,7 @@ void CResourceTableContextMenu::OpenInExternalApp() UICommon::OpenInExternalApplication( TO_QSTRING(mpEntry->CookedAssetPath()) ); } -void CResourceTableContextMenu::OpenContainingFolder() +void CResourceTableContextMenu::OpenInExplorer() { if (mpEntry) { @@ -79,11 +93,67 @@ void CResourceTableContextMenu::OpenContainingFolder() } } +void CResourceTableContextMenu::SelectFolder() +{ + CVirtualDirectory *pDir = (mpEntry ? mpEntry->Directory() : mpDirectory->Parent()); + mpBrowser->SetActiveDirectory(pDir); + + if (mpEntry) + mpBrowser->SelectResource(mpEntry); + else + mpBrowser->SelectDirectory(mpDirectory); +} + void CResourceTableContextMenu::Rename() { mpTable->edit(mProxyIndex); } +void CResourceTableContextMenu::ShowReferencers() +{ + ASSERT(mpEntry); + + QList EntryList; + + for (CResourceIterator Iter(mpEntry->ResourceStore()); Iter; ++Iter) + { + if (Iter->Dependencies()->HasDependency(mpEntry->ID())) + EntryList << *Iter; + } + + if (!mpModel->IsDisplayingUserEntryList()) + mpBrowser->SetInspectedEntry(mpEntry); + + QString ListDesc = QString("Referencers of \"%1\"").arg( TO_QSTRING(mpEntry->CookedAssetPath().GetFileName()) ); + mpModel->DisplayEntryList(EntryList, ListDesc); + mpBrowser->ClearFilters(); +} + +void CResourceTableContextMenu::ShowDependencies() +{ + ASSERT(mpEntry); + + std::set Dependencies; + mpEntry->Dependencies()->GetAllResourceReferences(Dependencies); + + QList EntryList; + + for (auto Iter = Dependencies.begin(); Iter != Dependencies.end(); Iter++) + { + CResourceEntry *pEntry = mpEntry->ResourceStore()->FindEntry(*Iter); + + if (pEntry) + EntryList << pEntry; + } + + if (!mpModel->IsDisplayingUserEntryList()) + mpBrowser->SetInspectedEntry(mpEntry); + + QString ListDesc = QString("Dependencies of \"%1\"").arg( TO_QSTRING(mpEntry->CookedAssetPath().GetFileName()) ); + mpModel->DisplayEntryList(EntryList, ListDesc); + mpBrowser->ClearFilters(); +} + void CResourceTableContextMenu::CopyName() { if (mpEntry) diff --git a/src/Editor/ResourceBrowser/CResourceTableContextMenu.h b/src/Editor/ResourceBrowser/CResourceTableContextMenu.h index 5a13acc1..e0f35474 100644 --- a/src/Editor/ResourceBrowser/CResourceTableContextMenu.h +++ b/src/Editor/ResourceBrowser/CResourceTableContextMenu.h @@ -24,9 +24,12 @@ class CResourceTableContextMenu : public QMenu // Actions QAction *mpOpenAction; QAction *mpOpenInExternalAppAction; - QAction *mpOpenContainingFolderAction; + QAction *mpOpenInExplorerAction; + QAction *mpSelectFolderAction; QAction *mpRenameAction; + QAction *mpShowReferencersAction; + QAction *mpShowDependenciesAction; QAction *mpCopyNameAction; QAction *mpCopyPathAction; @@ -41,8 +44,11 @@ public slots: // Menu Options void Open(); void OpenInExternalApp(); - void OpenContainingFolder(); + void OpenInExplorer(); + void SelectFolder(); void Rename(); + void ShowReferencers(); + void ShowDependencies(); void CopyName(); void CopyPath(); void CopyID(); diff --git a/src/Editor/ResourceBrowser/CResourceTableModel.cpp b/src/Editor/ResourceBrowser/CResourceTableModel.cpp index 18df735e..df05c7b4 100644 --- a/src/Editor/ResourceBrowser/CResourceTableModel.cpp +++ b/src/Editor/ResourceBrowser/CResourceTableModel.cpp @@ -5,6 +5,7 @@ CResourceTableModel::CResourceTableModel(CResourceBrowser *pBrowser, QObject *pParent /*= 0*/) : QAbstractTableModel(pParent) , mpCurrentDir(nullptr) + , mIsDisplayingUserEntryList(false) { connect(pBrowser, SIGNAL(DirectoryCreated(CVirtualDirectory*)), this, SLOT(CheckAddDirectory(CVirtualDirectory*))); connect(pBrowser, SIGNAL(DirectoryAboutToBeDeleted(CVirtualDirectory*)), this, SLOT(CheckRemoveDirectory(CVirtualDirectory*))); @@ -189,6 +190,11 @@ bool CResourceTableModel::IsIndexDirectory(const QModelIndex& rkIndex) const return rkIndex.row() >= 0 && rkIndex.row() < mDirectories.size(); } +bool CResourceTableModel::HasParentDirectoryEntry() const +{ + return !mIsAssetListMode && mpCurrentDir && !mpCurrentDir->IsRoot(); +} + void CResourceTableModel::FillEntryList(CVirtualDirectory *pDir, bool AssetListMode) { beginResetModel(); @@ -197,6 +203,7 @@ void CResourceTableModel::FillEntryList(CVirtualDirectory *pDir, bool AssetListM mEntries.clear(); mDirectories.clear(); mIsAssetListMode = AssetListMode; + mIsDisplayingUserEntryList = false; if (pDir) { @@ -226,6 +233,22 @@ void CResourceTableModel::FillEntryList(CVirtualDirectory *pDir, bool AssetListM RecursiveAddDirectoryContents(pDir); } + if (pDir) + mModelDescription = pDir->IsRoot() ? "Root" : TO_QSTRING(pDir->FullPath()); + else + mModelDescription = "Nothing"; + + endResetModel(); +} + +void CResourceTableModel::DisplayEntryList(QList& rkEntries, const QString& rkListDescription) +{ + beginResetModel(); + mEntries = rkEntries; + mDirectories.clear(); + mModelDescription = rkListDescription; + mIsAssetListMode = true; + mIsDisplayingUserEntryList = true; endResetModel(); } diff --git a/src/Editor/ResourceBrowser/CResourceTableModel.h b/src/Editor/ResourceBrowser/CResourceTableModel.h index 7943efbe..ff5d2e3f 100644 --- a/src/Editor/ResourceBrowser/CResourceTableModel.h +++ b/src/Editor/ResourceBrowser/CResourceTableModel.h @@ -16,7 +16,9 @@ class CResourceTableModel : public QAbstractTableModel CVirtualDirectory *mpCurrentDir; QList mDirectories; QList mEntries; + QString mModelDescription; bool mIsAssetListMode; + bool mIsDisplayingUserEntryList; public: CResourceTableModel(CResourceBrowser *pBrowser, QObject *pParent = 0); @@ -39,15 +41,21 @@ public: CResourceEntry* IndexEntry(const QModelIndex& rkIndex) const; CVirtualDirectory* IndexDirectory(const QModelIndex& rkIndex) const; bool IsIndexDirectory(const QModelIndex& rkIndex) const; + bool HasParentDirectoryEntry() const; void FillEntryList(CVirtualDirectory *pDir, bool AssetListMode); + void DisplayEntryList(QList& rkEntries, const QString& rkListDescription); protected: void RecursiveAddDirectoryContents(CVirtualDirectory *pDir); int EntryListIndex(CResourceEntry *pEntry); public: // Accessors - inline u32 NumDirectories() const { return mDirectories.size(); } - inline u32 NumResources() const { return mEntries.size(); } + inline u32 NumDirectories() const { return mDirectories.size(); } + inline u32 NumResources() const { return mEntries.size(); } + inline CVirtualDirectory* CurrentDir() const { return mpCurrentDir; } + inline bool IsDisplayingAssetList() const { return mIsAssetListMode; } + inline bool IsDisplayingUserEntryList() const { return mIsDisplayingUserEntryList; } + inline QString ModelDescription() const { return mModelDescription; } public slots: void CheckAddDirectory(CVirtualDirectory *pDir); diff --git a/src/Editor/ResourceBrowser/CResourceTableView.h b/src/Editor/ResourceBrowser/CResourceTableView.h index 9caaa77b..1b5b2e98 100644 --- a/src/Editor/ResourceBrowser/CResourceTableView.h +++ b/src/Editor/ResourceBrowser/CResourceTableView.h @@ -2,10 +2,16 @@ #define CRESOURCETABLEVIEW_H #include +#include "CResourceTableModel.h" +#include "CResourceProxyModel.h" class CResourceTableView : public QTableView { Q_OBJECT + + CResourceTableModel *mpModel; + CResourceProxyModel *mpProxy; + QAction *mpRenameAction; QAction *mpDeleteAction;