Fixed table view updating to properly show changes after moving resources/directories

This commit is contained in:
Aruki 2017-07-15 22:24:59 -06:00
parent dbe8b7922c
commit a813c4c61c
10 changed files with 152 additions and 91 deletions

View File

@ -159,7 +159,7 @@ bool CResourceStore::SaveDatabaseCache()
void CResourceStore::ConditionalSaveStore() void CResourceStore::ConditionalSaveStore()
{ {
if (mDatabaseCacheDirty) SaveDatabaseCache(); if (mDatabaseCacheDirty) SaveDatabaseCache();
} }
void CResourceStore::SetProject(CGameProject *pProj) void CResourceStore::SetProject(CGameProject *pProj)

View File

@ -43,7 +43,7 @@ bool CVirtualDirectory::IsEmpty(bool CheckFilesystem) const
bool CVirtualDirectory::IsDescendantOf(CVirtualDirectory *pDir) const bool CVirtualDirectory::IsDescendantOf(CVirtualDirectory *pDir) const
{ {
return mpParent && (mpParent == pDir || mpParent->IsDescendantOf(pDir)); return (this == pDir) || (mpParent && pDir && (mpParent == pDir || mpParent->IsDescendantOf(pDir)));
} }
TString CVirtualDirectory::FullPath() const TString CVirtualDirectory::FullPath() const

View File

@ -240,13 +240,9 @@ void CEditorApplication::TickEditors()
mLastUpdate = CTimer::GlobalTime(); mLastUpdate = CTimer::GlobalTime();
double DeltaTime = mLastUpdate - LastUpdate; double DeltaTime = mLastUpdate - LastUpdate;
// The resource store should NOT be dirty at the beginning of a tick - this indicates we forgot to save it after updating somewhere // Make sure the resource store cache is up-to-date
if (gpResourceStore && gpResourceStore->IsCacheDirty()) if (gpResourceStore)
{
Log::Error("Resource store is dirty at the beginning of a tick! Call ConditionalSaveStore() after making any significant changes to assets!");
DEBUG_BREAK;
gpResourceStore->ConditionalSaveStore(); gpResourceStore->ConditionalSaveStore();
}
// Tick each editor window and redraw their viewports // Tick each editor window and redraw their viewports
foreach(IEditor *pEditor, mEditorWindows) foreach(IEditor *pEditor, mEditorWindows)

View File

@ -64,8 +64,6 @@ signals:
void ActiveProjectChanged(CGameProject *pNewProj); void ActiveProjectChanged(CGameProject *pNewProj);
void AssetsModified(); void AssetsModified();
void PackagesCooked(); void PackagesCooked();
void ResourceRenamed(CResourceEntry *pEntry);
void DirectoryRenamed(CVirtualDirectory *pDir);
}; };
#define gpEdApp static_cast<CEditorApplication*>(qApp) #define gpEdApp static_cast<CEditorApplication*>(qApp)

View File

@ -50,7 +50,7 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
pModeGroup->setExclusive(true); pModeGroup->setExclusive(true);
// Set up table models // Set up table models
mpModel = new CResourceTableModel(this); mpModel = new CResourceTableModel(this, this);
mpProxyModel = new CResourceProxyModel(this); mpProxyModel = new CResourceProxyModel(this);
mpProxyModel->setSourceModel(mpModel); mpProxyModel->setSourceModel(mpModel);
mpUI->ResourceTableView->setModel(mpProxyModel); mpUI->ResourceTableView->setModel(mpProxyModel);
@ -138,6 +138,7 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent)
connect(mpUI->DirectoryTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex,QModelIndex))); connect(mpUI->DirectoryTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnDirectorySelectionChanged(QModelIndex,QModelIndex)));
connect(mpUI->ResourceTableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnDoubleClickTable(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, QModelIndex)));
connect(mpProxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), mpUI->ResourceTableView, SLOT(resizeRowsToContents()));
connect(mpProxyModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), mpUI->ResourceTableView, SLOT(resizeRowsToContents())); connect(mpProxyModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), mpUI->ResourceTableView, SLOT(resizeRowsToContents()));
connect(mpFilterAllBox, SIGNAL(toggled(bool)), this, SLOT(OnFilterTypeBoxTicked(bool))); connect(mpFilterAllBox, SIGNAL(toggled(bool)), this, SLOT(OnFilterTypeBoxTicked(bool)));
connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(UpdateStore())); connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(UpdateStore()));

View File

@ -98,6 +98,8 @@ public slots:
signals: signals:
void SelectedResourceChanged(CResourceEntry *pNewRes); void SelectedResourceChanged(CResourceEntry *pNewRes);
void ResourceMoved(CResourceEntry *pRes, CVirtualDirectory *pOldDir, TString OldName);
void DirectoryMoved(CVirtualDirectory *pDir, CVirtualDirectory *pOldDir, TString OldName);
}; };
#endif // CRESOURCEBROWSER_H #endif // CRESOURCEBROWSER_H

View File

@ -2,12 +2,12 @@
#include "CResourceBrowser.h" #include "CResourceBrowser.h"
#include "CResourceMimeData.h" #include "CResourceMimeData.h"
CResourceTableModel::CResourceTableModel(QObject *pParent /*= 0*/) CResourceTableModel::CResourceTableModel(CResourceBrowser *pBrowser, QObject *pParent /*= 0*/)
: QAbstractTableModel(pParent) : QAbstractTableModel(pParent)
, mpCurrentDir(nullptr) , mpCurrentDir(nullptr)
{ {
connect(gpEdApp, SIGNAL(ResourceRenamed(CResourceEntry*)), this, SLOT(OnResourceRenamed(CResourceEntry*))); connect(pBrowser, SIGNAL(ResourceMoved(CResourceEntry*,CVirtualDirectory*,TString)), this, SLOT(OnResourceMoved(CResourceEntry*,CVirtualDirectory*,TString)));
connect(gpEdApp, SIGNAL(DirectoryRenamed(CVirtualDirectory*)), this, SLOT(OnDirectoryRenamed(CVirtualDirectory*))); connect(pBrowser, SIGNAL(DirectoryMoved(CVirtualDirectory*,CVirtualDirectory*,TString)), this, SLOT(OnDirectoryMoved(CVirtualDirectory*,CVirtualDirectory*,TString)));
} }
// ************ INTERFACE ************ // ************ INTERFACE ************
@ -32,7 +32,8 @@ QVariant CResourceTableModel::data(const QModelIndex& rkIndex, int Role) const
CVirtualDirectory *pDir = IndexDirectory(rkIndex); CVirtualDirectory *pDir = IndexDirectory(rkIndex);
if (Role == Qt::DisplayRole || Role == Qt::ToolTipRole) if (Role == Qt::DisplayRole || Role == Qt::ToolTipRole)
return (mHasParent && rkIndex.row() == 0 ? ".." : TO_QSTRING(pDir->Name())); return ( (mpCurrentDir && !mpCurrentDir->IsRoot() && rkIndex.row() == 0)
? ".." : TO_QSTRING(pDir->Name()));
else if (Role == Qt::DecorationRole) else if (Role == Qt::DecorationRole)
return QIcon(":/icons/Open_24px.png"); return QIcon(":/icons/Open_24px.png");
@ -143,10 +144,27 @@ Qt::DropActions CResourceTableModel::supportedDropActions() const
// ************ FUNCTIONALITY ************ // ************ FUNCTIONALITY ************
QModelIndex CResourceTableModel::GetIndexForEntry(CResourceEntry *pEntry) const QModelIndex CResourceTableModel::GetIndexForEntry(CResourceEntry *pEntry) const
{ {
if (mEntryIndexMap.contains(pEntry)) auto Iter = qBinaryFind(mEntries, pEntry);
return index(mEntryIndexMap[pEntry] + mDirectories.size(), 0, QModelIndex());
else if (Iter == mEntries.end())
return QModelIndex(); return QModelIndex();
else
{
int Index = Iter - mEntries.begin();
return index(mDirectories.size() + Index, 0, QModelIndex());
}
}
QModelIndex CResourceTableModel::GetIndexForDirectory(CVirtualDirectory *pDir) const
{
for (int DirIdx = 0; DirIdx < mDirectories.size(); DirIdx++)
{
if (mDirectories[DirIdx] == pDir)
return index(DirIdx, 0, QModelIndex());
}
return QModelIndex();
} }
CResourceEntry* CResourceTableModel::IndexEntry(const QModelIndex& rkIndex) const CResourceEntry* CResourceTableModel::IndexEntry(const QModelIndex& rkIndex) const
@ -169,21 +187,18 @@ void CResourceTableModel::FillEntryList(CVirtualDirectory *pDir, bool AssetListM
{ {
beginResetModel(); beginResetModel();
mpCurrentDir = pDir;
mEntries.clear(); mEntries.clear();
mDirectories.clear(); mDirectories.clear();
mEntryIndexMap.clear(); mIsAssetListMode = AssetListMode;
mHasParent = false;
if (pDir) if (pDir)
{ {
// In filesystem mode, show only subdirectories and assets in the current directory. // In filesystem mode, show only subdirectories and assets in the current directory.
if (!AssetListMode) if (!mIsAssetListMode)
{ {
if (!pDir->IsRoot()) if (!pDir->IsRoot())
{
mDirectories << pDir->Parent(); mDirectories << pDir->Parent();
mHasParent = true;
}
for (u32 iDir = 0; iDir < pDir->NumSubdirectories(); iDir++) for (u32 iDir = 0; iDir < pDir->NumSubdirectories(); iDir++)
mDirectories << pDir->SubdirectoryByIndex(iDir); mDirectories << pDir->SubdirectoryByIndex(iDir);
@ -194,8 +209,8 @@ void CResourceTableModel::FillEntryList(CVirtualDirectory *pDir, bool AssetListM
if (pEntry->TypeInfo()->IsVisibleInBrowser() && !pEntry->IsHidden()) if (pEntry->TypeInfo()->IsVisibleInBrowser() && !pEntry->IsHidden())
{ {
mEntryIndexMap[pEntry] = mEntries.size(); int Index = EntryListIndex(pEntry);
mEntries << pEntry; mEntries.insert(Index, pEntry);
} }
} }
} }
@ -216,8 +231,8 @@ void CResourceTableModel::RecursiveAddDirectoryContents(CVirtualDirectory *pDir)
if (pEntry->TypeInfo()->IsVisibleInBrowser() && !pEntry->IsHidden()) if (pEntry->TypeInfo()->IsVisibleInBrowser() && !pEntry->IsHidden())
{ {
mEntryIndexMap[pEntry] = mEntries.size(); int Index = EntryListIndex(pEntry);
mEntries << pEntry; mEntries.insert(Index, pEntry);
} }
} }
@ -225,29 +240,84 @@ void CResourceTableModel::RecursiveAddDirectoryContents(CVirtualDirectory *pDir)
RecursiveAddDirectoryContents(pDir->SubdirectoryByIndex(iDir)); RecursiveAddDirectoryContents(pDir->SubdirectoryByIndex(iDir));
} }
void CResourceTableModel::OnResourceRenamed(CResourceEntry *pEntry) int CResourceTableModel::EntryListIndex(CResourceEntry *pEntry)
{ {
if (mEntryIndexMap.contains(pEntry)) return qLowerBound(mEntries, pEntry) - mEntries.constBegin();
{
int Index = mEntries.indexOf(pEntry);
int Row = Index + mDirectories.size();
beginRemoveRows(QModelIndex(), Row, Row);
mEntries.removeAt(Index);
mEntryIndexMap.remove(pEntry);
endRemoveRows();
}
} }
void CResourceTableModel::OnDirectoryRenamed(CVirtualDirectory *pDir) void CResourceTableModel::OnResourceMoved(CResourceEntry *pEntry, CVirtualDirectory *pOldDir, TString OldName)
{ {
for (int DirIdx = 0; DirIdx < mDirectories.size(); DirIdx++) CVirtualDirectory *pNewDir = pEntry->Directory();
bool WasInModel = (pOldDir == mpCurrentDir || (mIsAssetListMode && pOldDir->IsDescendantOf(mpCurrentDir)));
bool IsInModel = (pNewDir == mpCurrentDir || (mIsAssetListMode && pNewDir->IsDescendantOf(mpCurrentDir)));
// Handle rename
if (WasInModel && IsInModel && pEntry->Name() != OldName)
{ {
if (mDirectories[DirIdx] == pDir) int ResIdx = EntryListIndex(pEntry);
int Row = ResIdx + mDirectories.size();
QModelIndex Index = index(Row, 0, QModelIndex());
emit dataChanged(Index, Index);
}
else if (pNewDir != pOldDir)
{
// Remove
if (WasInModel && !IsInModel)
{ {
beginRemoveRows(QModelIndex(), DirIdx, DirIdx); int Pos = EntryListIndex(pEntry);
mDirectories.removeAt(DirIdx); int Row = mDirectories.size() + Pos;
beginRemoveRows(QModelIndex(), Row, Row);
mEntries.removeAt(Pos);
endRemoveRows(); endRemoveRows();
} }
// Add
else if (!WasInModel && IsInModel)
{
int Index = EntryListIndex(pEntry);
int Row = mDirectories.size() + Index;
beginInsertRows(QModelIndex(), Row, Row);
mEntries.insert(Index, pEntry);
endInsertRows();
}
}
}
void CResourceTableModel::OnDirectoryMoved(CVirtualDirectory *pDir, CVirtualDirectory *pOldDir, TString OldName)
{
CVirtualDirectory *pNewDir = pDir->Parent();
bool WasInModel = !mIsAssetListMode && pOldDir == mpCurrentDir;
bool IsInModel = !mIsAssetListMode && pNewDir == mpCurrentDir;
// Handle rename
if (WasInModel && IsInModel && pDir->Name() != OldName)
{
QModelIndex Index = GetIndexForDirectory(pDir);
emit dataChanged(Index, Index);
}
else if (pNewDir != pOldDir)
{
// Remove
if (WasInModel && !IsInModel)
{
QModelIndex Index = GetIndexForDirectory(pDir);
beginRemoveRows(QModelIndex(), Index.row(), Index.row());
mDirectories.removeOne(pDir);
endRemoveRows();
}
// Add
else if (!WasInModel && !IsInModel)
{
// Just append to the end, let the proxy handle sorting
beginInsertRows(QModelIndex(), mDirectories.size(), mDirectories.size());
mDirectories << pDir;
endInsertRows();
}
} }
} }

View File

@ -16,11 +16,10 @@ class CResourceTableModel : public QAbstractTableModel
CVirtualDirectory *mpCurrentDir; CVirtualDirectory *mpCurrentDir;
QList<CVirtualDirectory*> mDirectories; QList<CVirtualDirectory*> mDirectories;
QList<CResourceEntry*> mEntries; QList<CResourceEntry*> mEntries;
QMap<CResourceEntry*, int> mEntryIndexMap; bool mIsAssetListMode;
bool mHasParent;
public: public:
CResourceTableModel(QObject *pParent = 0); CResourceTableModel(CResourceBrowser *pBrowser, QObject *pParent = 0);
// Interface // Interface
int rowCount(const QModelIndex& /*rkParent*/) const; int rowCount(const QModelIndex& /*rkParent*/) const;
@ -43,6 +42,7 @@ public:
void FillEntryList(CVirtualDirectory *pDir, bool AssetListMode); void FillEntryList(CVirtualDirectory *pDir, bool AssetListMode);
protected: protected:
void RecursiveAddDirectoryContents(CVirtualDirectory *pDir); void RecursiveAddDirectoryContents(CVirtualDirectory *pDir);
int EntryListIndex(CResourceEntry *pEntry);
public: public:
// Accessors // Accessors
@ -50,8 +50,8 @@ public:
inline u32 NumResources() const { return mEntries.size(); } inline u32 NumResources() const { return mEntries.size(); }
public slots: public slots:
void OnResourceRenamed(CResourceEntry *pEntry); void OnResourceMoved(CResourceEntry *pEntry, CVirtualDirectory *pOldDir, TString OldName);
void OnDirectoryRenamed(CVirtualDirectory *pDir); void OnDirectoryMoved(CVirtualDirectory *pDir, CVirtualDirectory *pOldDir, TString OldName);
}; };
#endif // CRESOURCELISTMODEL #endif // CRESOURCELISTMODEL

View File

@ -3,6 +3,7 @@
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "Editor/CEditorApplication.h" #include "Editor/CEditorApplication.h"
#include "Editor/ResourceBrowser/CResourceBrowser.h"
#include <Core/GameProject/CResourceStore.h> #include <Core/GameProject/CResourceStore.h>
#include <Core/GameProject/CVirtualDirectory.h> #include <Core/GameProject/CVirtualDirectory.h>
@ -22,31 +23,24 @@ public:
, mNewParent(pNewParent->FullPath()) , mNewParent(pNewParent->FullPath())
{} {}
void undo() void undo() { DoMove(mOldParent); }
{ void redo() { DoMove(mNewParent); }
CVirtualDirectory *pDir = mpStore->GetVirtualDirectory(mTargetDir, false);
CVirtualDirectory *pParent = mpStore->GetVirtualDirectory(mOldParent, false);
ASSERT(pDir && pParent);
pDir->SetParent(pParent);
mTargetDir = pDir->FullPath();
gpEdApp->DirectoryRenamed(pDir);
}
void redo()
{
CVirtualDirectory *pDir = mpStore->GetVirtualDirectory(mTargetDir, false);
CVirtualDirectory *pParent = mpStore->GetVirtualDirectory(mNewParent, false);
ASSERT(pDir && pParent);
pDir->SetParent(pParent);
mTargetDir = pDir->FullPath();
gpEdApp->DirectoryRenamed(pDir);
}
bool AffectsCleanState() const { return false; } bool AffectsCleanState() const { return false; }
protected:
void DoMove(const TString& rkPath)
{
CVirtualDirectory *pDir = mpStore->GetVirtualDirectory(mTargetDir, false);
CVirtualDirectory *pParent = mpStore->GetVirtualDirectory(rkPath, false);
ASSERT(pDir && pParent);
TString OldName = pDir->Name();
CVirtualDirectory *pOldParent = pDir->Parent();
pDir->SetParent(pParent);
mTargetDir = pDir->FullPath();
gpEdApp->ResourceBrowser()->DirectoryMoved(pDir, pOldParent, OldName);
}
}; };
#endif // CMOVEDIRECTORYCOMMAND_H #endif // CMOVEDIRECTORYCOMMAND_H

View File

@ -3,6 +3,7 @@
#include "IUndoCommand.h" #include "IUndoCommand.h"
#include "Editor/CEditorApplication.h" #include "Editor/CEditorApplication.h"
#include "Editor/ResourceBrowser/CResourceBrowser.h"
#include <Core/GameProject/CResourceEntry.h> #include <Core/GameProject/CResourceEntry.h>
class CMoveResourceCommand : public IUndoCommand class CMoveResourceCommand : public IUndoCommand
@ -21,25 +22,24 @@ public:
, mOldDirAutoGenerated(pEntry->HasFlag(eREF_AutoResDir)) , mOldDirAutoGenerated(pEntry->HasFlag(eREF_AutoResDir))
{} {}
void undo() // note: for redo, it doesn't matter if the new directory was auto-generated, since the
{ // purpose of tracking that flag is to detect which resources have been auto-categorized.
bool Success = mpEntry->Move(mOldDirPath, mOldDirAutoGenerated); // if this is being called, even if the new directory is auto-generated, it means the
ASSERT(Success); // todo better error handling // user is intentionally placing it here, so it should be treated as a custom directory
gpEdApp->ResourceRenamed(mpEntry); void undo() { DoMove(mOldDirPath, mOldDirAutoGenerated); }
} void redo() { DoMove(mNewDirPath, false); }
void redo()
{
// note: it doesn't matter if the new directory was auto-generated, since the
// purpose of tracking that flag is to detect which resources have been auto-categorized.
// if this is being called, even if the new directory is auto-generated, it means the
// user is intentionally placing it here, so it should be treated as a custom directory
bool Success = mpEntry->Move(mNewDirPath);
ASSERT(Success); // todo better error handling
gpEdApp->ResourceRenamed(mpEntry);
}
bool AffectsCleanState() const { return false; } bool AffectsCleanState() const { return false; }
protected:
void DoMove(const TString& rkPath, bool IsAutoDir)
{
CVirtualDirectory *pOldDir = mpEntry->Directory();
TString OldName = mpEntry->Name();
bool Success = mpEntry->Move(rkPath, IsAutoDir);
ASSERT(Success); // todo better error handling
gpEdApp->ResourceBrowser()->ResourceMoved(mpEntry, pOldDir, OldName);
}
}; };
#endif // CMOVERESOURCECOMMAND_H #endif // CMOVERESOURCECOMMAND_H