From fe9a074029030c4b94c608cefd35b27aef6e7539 Mon Sep 17 00:00:00 2001 From: Aruki Date: Thu, 13 Jul 2017 01:41:46 -0600 Subject: [PATCH] Added context menu to the resource browser; fixed search results not displaying correctly --- src/Editor/Editor.pro | 6 +- .../ResourceBrowser/CResourceBrowser.cpp | 32 +++++-- src/Editor/ResourceBrowser/CResourceBrowser.h | 4 +- .../ResourceBrowser/CResourceBrowser.ui | 14 ++- .../CResourceTableContextMenu.cpp | 96 +++++++++++++++++++ .../CResourceTableContextMenu.h | 47 +++++++++ src/Editor/UICommon.cpp | 65 +++---------- src/Editor/UICommon.h | 6 +- 8 files changed, 205 insertions(+), 65 deletions(-) create mode 100644 src/Editor/ResourceBrowser/CResourceTableContextMenu.cpp create mode 100644 src/Editor/ResourceBrowser/CResourceTableContextMenu.h diff --git a/src/Editor/Editor.pro b/src/Editor/Editor.pro index c5b621c9..be020060 100644 --- a/src/Editor/Editor.pro +++ b/src/Editor/Editor.pro @@ -186,7 +186,8 @@ HEADERS += \ CUIRelay.h \ Widgets/CSelectResourcePanel.h \ Widgets/CFilteredResourceModel.h \ - ResourceBrowser/CResourceDelegate.h + ResourceBrowser/CResourceDelegate.h \ + ResourceBrowser/CResourceTableContextMenu.h # Source Files SOURCES += \ @@ -255,7 +256,8 @@ SOURCES += \ WorldEditor/CWorldEditorSidebar.cpp \ CProgressDialog.cpp \ Widgets/CSelectResourcePanel.cpp \ - ResourceBrowser/CResourceDelegate.cpp + ResourceBrowser/CResourceDelegate.cpp \ + ResourceBrowser/CResourceTableContextMenu.cpp # UI Files FORMS += \ diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.cpp b/src/Editor/ResourceBrowser/CResourceBrowser.cpp index a2182208..8edb905e 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.cpp +++ b/src/Editor/ResourceBrowser/CResourceBrowser.cpp @@ -2,9 +2,11 @@ #include "ui_CResourceBrowser.h" #include "CProgressDialog.h" #include "CResourceDelegate.h" +#include "CResourceTableContextMenu.h" #include "Editor/CEditorApplication.h" #include #include + #include #include #include @@ -109,8 +111,11 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) pGroup->addAction(pEdStoreAction); #endif + // Create context menu for the resource table + new CResourceTableContextMenu(this, mpUI->ResourceTableView, mpModel, mpProxyModel); + // Set up connections - connect(mpUI->SearchBar, SIGNAL(textChanged(QString)), this, SLOT(OnSearchStringChanged())); + connect(mpUI->SearchBar, SIGNAL(StoppedTyping(QString)), this, SLOT(OnSearchStringChanged(QString))); connect(mpUI->ResourceTreeButton, SIGNAL(pressed()), this, SLOT(SetResourceTreeView())); connect(mpUI->ResourceListButton, SIGNAL(pressed()), this, SLOT(SetResourceListView())); connect(mpUI->SortComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSortModeChanged(int))); @@ -118,7 +123,6 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) connect(mpUI->ResourceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnDoubleClickTable(QModelIndex))); connect(mpUI->ResourceTableView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnResourceSelectionChanged(QModelIndex, QModelIndex))); connect(mpProxyModel, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), mpUI->ResourceTableView, SLOT(resizeRowsToContents())); - connect(&mUpdateFilterTimer, SIGNAL(timeout()), this, SLOT(UpdateFilter())); connect(mpFilterAllBox, SIGNAL(toggled(bool)), this, SLOT(OnFilterTypeBoxTicked(bool))); connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(UpdateStore())); } @@ -202,7 +206,7 @@ void CResourceBrowser::CreateFilterCheckboxes() void CResourceBrowser::RefreshResources() { // Fill resource table - mpModel->FillEntryList(mpSelectedDir, mAssetListMode); + mpModel->FillEntryList(mpSelectedDir, mAssetListMode || mSearching); } void CResourceBrowser::RefreshDirectories() @@ -261,10 +265,22 @@ void CResourceBrowser::OnSortModeChanged(int Index) mpProxyModel->SetSortMode(Mode); } -void CResourceBrowser::OnSearchStringChanged() +void CResourceBrowser::OnSearchStringChanged(QString SearchString) { - const int kUpdateWaitTime = 500; - mUpdateFilterTimer.start(kUpdateWaitTime); + bool WasSearching = mSearching; + mSearching = !SearchString.isEmpty(); + + // Check if we need to change to/from asset list mode to display/stop displaying search results + if (!mAssetListMode) + { + if ( (mSearching && !WasSearching) || + (!mSearching && WasSearching) ) + { + RefreshResources(); + } + } + + UpdateFilter(); } void CResourceBrowser::OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& /*rkPrevIndex*/) @@ -320,6 +336,10 @@ void CResourceBrowser::UpdateStore() { mpStore = pNewStore; + // Clear search + mpUI->SearchBar->clear(); + mSearching = false; + // Refresh type filter list CreateFilterCheckboxes(); diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.h b/src/Editor/ResourceBrowser/CResourceBrowser.h index 1fbb80a3..9ed8b457 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.h +++ b/src/Editor/ResourceBrowser/CResourceBrowser.h @@ -24,7 +24,6 @@ class CResourceBrowser : public QWidget CResourceBrowserDelegate *mpDelegate; CVirtualDirectory *mpSelectedDir; CVirtualDirectoryModel *mpDirectoryModel; - QTimer mUpdateFilterTimer; bool mEditorStore; bool mAssetListMode; bool mSearching; @@ -51,6 +50,7 @@ public: void CreateFilterCheckboxes(); // Accessors + inline CResourceStore* CurrentStore() const { return mpStore; } inline CResourceEntry* SelectedEntry() const { return mpSelectedEntry; } inline bool InAssetListMode() const { return mAssetListMode || mSearching; } @@ -61,7 +61,7 @@ public slots: void SetResourceTreeView(); void SetResourceListView(); void OnSortModeChanged(int Index); - void OnSearchStringChanged(); + void OnSearchStringChanged(QString SearchString); void OnDirectorySelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex); void OnDoubleClickTable(QModelIndex Index); void OnResourceSelectionChanged(const QModelIndex& rkNewIndex, const QModelIndex& rkPrevIndex); diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.ui b/src/Editor/ResourceBrowser/CResourceBrowser.ui index 00056209..061642c8 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.ui +++ b/src/Editor/ResourceBrowser/CResourceBrowser.ui @@ -70,7 +70,7 @@ - + 5 @@ -185,7 +185,7 @@ Qt::Horizontal - + @@ -269,6 +269,9 @@ 8 + + Qt::CustomContextMenu + QAbstractItemView::NoEditTriggers @@ -301,6 +304,13 @@ + + + CTimedLineEdit + QLineEdit +
Editor/Widgets/CTimedLineEdit.h
+
+
diff --git a/src/Editor/ResourceBrowser/CResourceTableContextMenu.cpp b/src/Editor/ResourceBrowser/CResourceTableContextMenu.cpp new file mode 100644 index 00000000..fc583889 --- /dev/null +++ b/src/Editor/ResourceBrowser/CResourceTableContextMenu.cpp @@ -0,0 +1,96 @@ +#include "CResourceTableContextMenu.h" +#include "CResourceBrowser.h" +#include "Editor/CEditorApplication.h" +#include + +CResourceTableContextMenu::CResourceTableContextMenu(CResourceBrowser *pBrowser, QTableView *pView, CResourceTableModel *pModel, CResourceProxyModel *pProxy) + : QMenu(pView) + , mpBrowser(pBrowser) + , mpTable(pView) + , mpModel(pModel) + , mpProxy(pProxy) + , mpEntry(nullptr) + , mpDirectory(nullptr) +{ + // Connect to the view + connect(pView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowMenu(QPoint))); + + // Create actions + mpOpenAction = addAction("Open", this, SLOT(Open())); + mpOpenInExternalAppAction = addAction("Open in external application", this, SLOT(OpenInExternalApp())); + mpOpenContainingFolderAction = addAction("Open containing folder", this, SLOT(OpenContainingFolder())); + addSeparator(); + mpCopyNameAction = addAction("Copy name", this, SLOT(CopyName())); + mpCopyPathAction = addAction("Copy path", this, SLOT(CopyPath())); + mpCopyIDAction = addAction("Copy asset ID", this, SLOT(CopyID())); +} + +void CResourceTableContextMenu::ShowMenu(const QPoint& rkPos) +{ + // Fetch the entry/directory + QModelIndex ProxyIndex = mpTable->indexAt(rkPos); + mIndex = mpProxy->mapToSource(ProxyIndex); + mpEntry = mpModel->IndexEntry(mIndex); + mpDirectory = mpModel->IndexDirectory(mIndex); + + // Show/hide menu options + bool IsRes = (mpEntry != nullptr); + mpOpenInExternalAppAction->setVisible(IsRes); + mpCopyIDAction->setVisible(IsRes); + + // Exec menu + QPoint GlobalPos = mpTable->viewport()->mapToGlobal(rkPos); + exec(GlobalPos); +} + +// Menu Options +void CResourceTableContextMenu::Open() +{ + if (mpEntry) + gpEdApp->EditResource(mpEntry); + else + mpBrowser->SelectDirectory(mpDirectory); +} + +void CResourceTableContextMenu::OpenInExternalApp() +{ + ASSERT(mpEntry); + UICommon::OpenInExternalApplication( TO_QSTRING(mpEntry->CookedAssetPath()) ); +} + +void CResourceTableContextMenu::OpenContainingFolder() +{ + if (mpEntry) + { + QString Path = TO_QSTRING( mpEntry->CookedAssetPath() ); + UICommon::OpenContainingFolder(Path); + } + else + { + TString BasePath = mpBrowser->CurrentStore()->ResourcesDir(); + QString Path = TO_QSTRING( BasePath + mpDirectory->FullPath() ); + UICommon::OpenContainingFolder(Path); + } +} + +void CResourceTableContextMenu::CopyName() +{ + if (mpEntry) + gpEdApp->clipboard()->setText( TO_QSTRING(mpEntry->Name()) ); + else + gpEdApp->clipboard()->setText( TO_QSTRING(mpDirectory->Name()) ); +} + +void CResourceTableContextMenu::CopyPath() +{ + if (mpEntry) + gpEdApp->clipboard()->setText( TO_QSTRING(mpEntry->CookedAssetPath(true)) ); + else + gpEdApp->clipboard()->setText( TO_QSTRING(mpDirectory->FullPath()) ); +} + +void CResourceTableContextMenu::CopyID() +{ + ASSERT(mpEntry); + gpEdApp->clipboard()->setText( TO_QSTRING(mpEntry->ID().ToString()) ); +} diff --git a/src/Editor/ResourceBrowser/CResourceTableContextMenu.h b/src/Editor/ResourceBrowser/CResourceTableContextMenu.h new file mode 100644 index 00000000..1b7b8738 --- /dev/null +++ b/src/Editor/ResourceBrowser/CResourceTableContextMenu.h @@ -0,0 +1,47 @@ +#ifndef CRESOURCETABLECONTEXTMENU_H +#define CRESOURCETABLECONTEXTMENU_H + +#include "CResourceTableModel.h" +#include "CResourceProxyModel.h" + +#include +#include + +class CResourceTableContextMenu : public QMenu +{ + Q_OBJECT + + CResourceBrowser *mpBrowser; + QTableView *mpTable; + CResourceTableModel *mpModel; + CResourceProxyModel *mpProxy; + + QModelIndex mIndex; + CResourceEntry *mpEntry; + CVirtualDirectory *mpDirectory; + + // Actions + QAction *mpOpenAction; + QAction *mpOpenInExternalAppAction; + QAction *mpOpenContainingFolderAction; + + QAction *mpCopyNameAction; + QAction *mpCopyPathAction; + QAction *mpCopyIDAction; + +public: + CResourceTableContextMenu(CResourceBrowser *pBrowser, QTableView *pView, CResourceTableModel *pModel, CResourceProxyModel *pProxy); + +public slots: + void ShowMenu(const QPoint& rkPos); + + // Menu Options + void Open(); + void OpenInExternalApp(); + void OpenContainingFolder(); + void CopyName(); + void CopyPath(); + void CopyID(); +}; + +#endif // CRESOURCETABLECONTEXTMENU_H diff --git a/src/Editor/UICommon.cpp b/src/Editor/UICommon.cpp index 8c6f8a03..e7208fc7 100644 --- a/src/Editor/UICommon.cpp +++ b/src/Editor/UICommon.cpp @@ -1,61 +1,24 @@ #include "UICommon.h" +#include +#include namespace UICommon { -QMap FilterMap = { - { "AFSM", "AI Finite State Machine (*.AFSM)" }, - { "ANIM", "Animation (*.ANIM)" }, - { "ANCS", "Animation Character Set (*.ANCS)" }, - { "AGSC", "Audio Group (*.AGSC)" }, - { "ATBL", "Audio Lookup Table (*.ATBL)" }, - { "CAUD", "Audio Metadata (*.CAUD)" }, - { "CHAR", "Character (*.CHAR)" }, - { "CINF", "Skeleton (*.CINF)" }, - { "CMDL", "Model (*.CMDL)" }, - { "CRSC", "Collision Response Data (*.CRSC)" }, - { "CSKR", "Skin Rules (*.CSKR)" }, - { "CSMP", "Audio Sample (*.CSMP)" }, - { "CSNG", "MIDI Data (*.CSNG)" }, - { "CTWK", "Tweaks (*.CTWK)" }, - { "DCLN", "Collision Mesh (*.DCLN)" }, - { "DGRP", "Dependency Group (*.DGRP)" }, - { "DPSC", "Decal (*.DPSC)" }, - { "DSP" , "Music Track (*.DSP)" }, - { "DUMB", "Binary Data Dump (*.DUMB)" }, - { "ELSC", "Electric Particle (*.ELSC)" }, - { "EVNT", "Animation Event Data (*.EVNT)" }, - { "FRME", "GUI Frame (*.FRME)" }, - { "FSM2", "AI Finite State Machine (*.FSM2)" }, - { "FONT", "Font (*.FONT)" }, - { "HINT", "Hint System Data (*.HINT)" }, - { "MAPA", "Area Map (*.MAPA)" }, - { "MAPW", "World Map (*.MAPW)" }, - { "MAPU", "Universe Map (*.MAPU)" }, - { "MLVL", "World (*.MLVL)" }, - { "MREA", "Area (*.MREA)" }, - { "NTWK", "Tweaks (*.NTWK)" }, - { "PATH", "AI Navigation Mesh (*.PATH)" }, - { "PAK" , "Package (*.pak)" }, - { "PART", "Particle (*.PART)" }, - { "SAVW", "World Save Data (*.SAVW)" }, - { "SCAN", "Scannable Object Info (*.SCAN)" }, - { "STRG", "String Table (*.STRG)" }, - { "STRM", "Audio Stream (*.STRM)" }, - { "SWHC", "Swoosh Particle (*.SWHC)" }, - { "THP" , "Video (*.thp)" }, - { "TXTR", "Texture (*.TXTR)" }, - { "WPSC", "Projectile (*.WPSC)" } -}; - -QString ExtensionFilterString(const QString& rkExtension) +void OpenContainingFolder(const QString& rkPath) { - QMap::const_iterator it = FilterMap.find(rkExtension.toUpper()); +#if WIN32 + QStringList Args; + Args << "/select," << QDir::toNativeSeparators(rkPath); + QProcess::startDetached("explorer", Args); +#else +#error OpenContainingFolder() not implemented! +#endif +} - if (it != FilterMap.end()) - return it.value(); - else - return "Unknown Extension (*." + rkExtension + ")"; +bool OpenInExternalApplication(const QString& rkPath) +{ + return QDesktopServices::openUrl( QString("file:///") + QDir::toNativeSeparators(rkPath) ); } } diff --git a/src/Editor/UICommon.h b/src/Editor/UICommon.h index 9f1a41df..20622637 100644 --- a/src/Editor/UICommon.h +++ b/src/Editor/UICommon.h @@ -38,8 +38,10 @@ namespace UICommon { -extern QMap FilterMap; -QString ExtensionFilterString(const QString& rkExtension); + +// Utility +void OpenContainingFolder(const QString& rkPath); +bool OpenInExternalApplication(const QString& rkPath); // TString/TWideString <-> QString inline QString ToQString(const TString& rkStr)