Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
#5108: Refactor PrefabSelector, start extracting a base FileSystemVie…
…w class and use that instead.
  • Loading branch information
codereader committed Nov 16, 2020
1 parent 83042ae commit 749028c
Show file tree
Hide file tree
Showing 11 changed files with 546 additions and 158 deletions.
2 changes: 2 additions & 0 deletions libs/wxutil/Makefile.am
Expand Up @@ -23,6 +23,8 @@ libwxutil_la_LIBADD = $(top_builddir)/libs/xmlutil/libxmlutil.la \
libwxutil_la_SOURCES = ConsoleView.cpp \
EntityClassChooser.cpp \
FreezePointer.cpp \
fsview/FileSystemView.cpp \
fsview/Populator.cpp \
GLWidget.cpp \
KeyValueTable.cpp \
PanedPosition.cpp \
Expand Down
4 changes: 2 additions & 2 deletions libs/wxutil/TreeView.cpp
Expand Up @@ -49,7 +49,7 @@ class TreeView::Search :
void _onTreeViewCharHook(wxKeyEvent& keyEvent);
};

TreeView::TreeView(wxWindow* parent, TreeModel::Ptr model, long style) :
TreeView::TreeView(wxWindow* parent, const TreeModel::Ptr& model, long style) :
wxDataViewCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style),
_collapseRecursively(true)
{
Expand All @@ -72,7 +72,7 @@ TreeView* TreeView::Create(wxWindow* parent, long style)

// Construct a TreeView using the given TreeModel, which will be associated
// with this view (refcount is automatically decreased by one).
TreeView* TreeView::CreateWithModel(wxWindow* parent, TreeModel::Ptr model, long style)
TreeView* TreeView::CreateWithModel(wxWindow* parent, const TreeModel::Ptr& model, long style)
{
return new TreeView(parent, model, style);
}
Expand Down
4 changes: 2 additions & 2 deletions libs/wxutil/TreeView.h
Expand Up @@ -30,7 +30,7 @@ class TreeView :

bool _collapseRecursively;

TreeView(wxWindow* parent, TreeModel::Ptr model, long style);
TreeView(wxWindow* parent, const TreeModel::Ptr& model, long style);

public:
typedef wxWindowPtr<TreeView> Ptr;
Expand All @@ -40,7 +40,7 @@ class TreeView :

// Construct a TreeView using the given TreeModel, which will be associated
// with this view (refcount is automatically decreased by one).
static TreeView* CreateWithModel(wxWindow* parent, TreeModel::Ptr model, long style = wxDV_SINGLE);
static TreeView* CreateWithModel(wxWindow* parent, const TreeModel::Ptr& model, long style = wxDV_SINGLE);

virtual ~TreeView();

Expand Down
195 changes: 195 additions & 0 deletions libs/wxutil/fsview/FileSystemView.cpp
@@ -0,0 +1,195 @@
#include "FileSystemView.h"

#include "i18n.h"
#include "iuimanager.h"
#include <wx/artprov.h>

namespace wxutil
{

wxDEFINE_EVENT(EV_FSVIEW_SELECTION_CHANGED, FileSystemView::SelectionChangedEvent);

FileSystemView::SelectionChangedEvent::SelectionChangedEvent(int id) :
wxEvent(id, EV_FSVIEW_SELECTION_CHANGED)
{}

FileSystemView::SelectionChangedEvent::SelectionChangedEvent(const std::string& selectedPath, bool isFolder, int id) :
wxEvent(id, EV_FSVIEW_SELECTION_CHANGED),
_selectedPath(selectedPath),
_isFolder(isFolder)
{}

wxEvent* FileSystemView::SelectionChangedEvent::Clone() const
{
return new FileSystemView::SelectionChangedEvent(*this);
}

const std::string& FileSystemView::SelectionChangedEvent::GetSelectedPath() const
{
return _selectedPath;
}

bool FileSystemView::SelectionChangedEvent::SelectionIsFolder()
{
return _isFolder;
}

FileSystemView::FileSystemView(wxWindow* parent, const TreeModel::Ptr& model, long style) :
TreeView(parent, model, style),
_treeStore(model)
{
// Single visible column, containing the directory/shader name and the icon
AppendIconTextColumn(_("File"), Columns().filename.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);

// Get selection and connect the changed callback
Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, &FileSystemView::OnSelectionChanged, this);
Bind(EV_TREEMODEL_POPULATION_FINISHED, &FileSystemView::OnTreeStorePopulationFinished, this);

// Use the TreeModel's full string search function
AddSearchColumn(Columns().filename);
}

const fsview::TreeColumns& FileSystemView::Columns()
{
static fsview::TreeColumns _columns;
return _columns;
}

FileSystemView* FileSystemView::Create(wxWindow* parent, long style)
{
TreeModel::Ptr model(new TreeModel(Columns()));
return new FileSystemView(parent, model, style);
}

const std::string& FileSystemView::GetBasePath() const
{
return _basePath;
}

void FileSystemView::SetBasePath(const std::string& basePath)
{
_basePath = basePath;
}

void FileSystemView::Populate(const std::string& preselectPath)
{
_populated = true;

if (_populator && _populator->GetBasePath() == GetBasePath())
{
// Population already running for this path
return;
}

// Clear the existing run first (this waits for it to finish)
_populator.reset();

// Clear the treestore
_treeStore->Clear();

wxutil::TreeModel::Row row = _treeStore->AddItem();

wxIcon prefabIcon;
prefabIcon.CopyFromBitmap(
wxArtProvider::GetBitmap(GlobalUIManager().ArtIdPrefix() + "cmenu_add_prefab.png"));

row[Columns().filename] = wxVariant(wxDataViewIconText(_("Loading..."), prefabIcon));
row[Columns().isFolder] = false;
row[Columns().vfspath] = "__loadingnode__"; // to prevent that item from being found
row.SendItemAdded();

_populator.reset(new fsview::Populator(Columns(), this, GetBasePath()));

// Start the thread, will send an event when finished
_populator->Populate();
}

void FileSystemView::SelectPath(const std::string& path)
{
// #4490: Only preselect if path is not empty, wxGTK will buffer that
// and call ExpandAncestors() on a stale wxDataViewItem in its internal idle routine
if (path.empty()) return;

// Find and select the item
SelectItem(_treeStore->FindString(path, Columns().vfspath));
}

std::string FileSystemView::GetSelectedPath()
{
wxDataViewItem item = GetSelection();

if (!item.IsOk()) return "";

wxutil::TreeModel::Row row(item, *GetModel());

return row[Columns().vfspath];
}

bool FileSystemView::GetIsFolderSelected()
{
wxDataViewItem item = GetSelection();

if (!item.IsOk()) return false;

wxutil::TreeModel::Row row(item, *GetModel());

return row[Columns().isFolder].getBool();
}

void FileSystemView::SelectItem(const wxDataViewItem& item)
{
if (!item.IsOk()) return;

Select(item);
EnsureVisible(item);
HandleSelectionChange();
}

TreeModel::Ptr FileSystemView::CreateDefaultModel()
{
_treeStore.reset(new TreeModel(Columns()));
return _treeStore;
}

void FileSystemView::HandleSelectionChange()
{
auto selectedPath = GetSelectedPath();

SelectionChangedEvent event(GetSelectedPath(), GetIsFolderSelected(), this->GetId());
event.SetEventObject(this);

HandleWindowEvent(event);
}

void FileSystemView::OnSelectionChanged(wxDataViewEvent& ev)
{
HandleSelectionChange();
}

void FileSystemView::OnTreeStorePopulationFinished(TreeModel::PopulationFinishedEvent& ev)
{
_treeStore = ev.GetTreeModel();

wxDataViewItem preselectItem;

if (!_preselectPath.empty())
{
// Find and select the classname
preselectItem = _treeStore->FindString(_preselectPath, Columns().vfspath);
}

AssociateModel(_treeStore.get());

if (preselectItem.IsOk())
{
SelectItem(preselectItem);
}

_populator.reset();

// Auto-size the first level
TriggerColumnSizeEvent();
}

}
76 changes: 76 additions & 0 deletions libs/wxutil/fsview/FileSystemView.h
@@ -0,0 +1,76 @@
#pragma once

#include <sigc++/signal.h>
#include "../TreeModel.h"
#include "../TreeView.h"
#include "Populator.h"

namespace wxutil
{

class FileSystemView :
public TreeView
{
private:
TreeModel::Ptr _treeStore;

std::string _basePath;

// TRUE if the treeview has been populated
bool _populated;
std::unique_ptr<fsview::Populator> _populator;
std::string _preselectPath;

public:
class SelectionChangedEvent :
public wxEvent
{
private:
std::string _selectedPath;
bool _isFolder;

public:
SelectionChangedEvent(int id = 0);
SelectionChangedEvent(const std::string& selectedPath, bool isFolder, int id = 0);
SelectionChangedEvent(const SelectionChangedEvent& other) = default;

wxEvent* Clone() const override;

const std::string& GetSelectedPath() const;
bool SelectionIsFolder();
};

FileSystemView(wxWindow* parent, const TreeModel::Ptr& model, long style = wxDV_SINGLE);

static const fsview::TreeColumns& Columns();

public:
static FileSystemView* Create(wxWindow* parent, long style = wxDV_SINGLE);

const std::string& GetBasePath() const;

// Sets the base path of this view. This can be either an absolute filesystem path or a VFS path
void SetBasePath(const std::string& basePath);

// (Re-)populates the tree view, looking for files in the defined paths
// If the preselectPath argument is not empty, the item will be selected after population
void Populate(const std::string& preselectPath = std::string());

// Selects and scrolls to the item defined by the given path
void SelectPath(const std::string& path);

std::string GetSelectedPath();
bool GetIsFolderSelected();

private:
TreeModel::Ptr CreateDefaultModel();

void SelectItem(const wxDataViewItem& item);
void HandleSelectionChange();
void OnSelectionChanged(wxDataViewEvent& ev);
void OnTreeStorePopulationFinished(TreeModel::PopulationFinishedEvent& ev);
};

wxDECLARE_EVENT(EV_FSVIEW_SELECTION_CHANGED, FileSystemView::SelectionChangedEvent);

}

0 comments on commit 749028c

Please sign in to comment.