Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
#5127: More streamlining with regards to TreeModel::PopulationFinishe…
…dEvent handling - let this always point to the ResourceTreeView since, move the event handler argument from the Populator constructors to a setter.

Handle item selection after population right in ResourceTreeView.
  • Loading branch information
codereader committed Jan 2, 2021
1 parent 70c696b commit dbb8f97
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 64 deletions.
55 changes: 7 additions & 48 deletions libs/wxutil/EntityClassChooser.cpp
Expand Up @@ -119,8 +119,8 @@ class ThreadedEntityClassLoader final :
const ResourceTreeView::Columns& _columns;

public:
ThreadedEntityClassLoader(const ResourceTreeView::Columns& cols, wxEvtHandler* finishedHandler) :
ThreadedResourceTreePopulator(cols, finishedHandler),
ThreadedEntityClassLoader(const ResourceTreeView::Columns& cols) :
ThreadedResourceTreePopulator(cols),
_columns(cols)
{}

Expand Down Expand Up @@ -149,9 +149,6 @@ EntityClassChooser::EntityClassChooser()
_treeView(nullptr),
_selectedName("")
{
// Connect the finish callback to load the treestore
Bind(EV_TREEMODEL_POPULATION_FINISHED, &EntityClassChooser::onTreeStorePopulationFinished, this);

loadNamedPanel(this, "EntityClassChooserMainPanel");

// Connect button signals
Expand Down Expand Up @@ -225,7 +222,7 @@ EntityClassChooser& EntityClassChooser::Instance()
{
EntityClassChooserPtr& instancePtr = InstancePtr();

if (instancePtr == NULL)
if (!instancePtr)
{
// Not yet instantiated, do it now
instancePtr.reset(new EntityClassChooser);
Expand Down Expand Up @@ -259,28 +256,12 @@ void EntityClassChooser::onMainFrameShuttingDown()

void EntityClassChooser::loadEntityClasses()
{
_eclassLoader.reset(new ThreadedEntityClassLoader(_columns, this));
_eclassLoader->Populate();
_treeView->populate(std::make_shared<ThreadedEntityClassLoader>(_columns));
}

void EntityClassChooser::setSelectedEntityClass(const std::string& eclass)
{
// Select immediately if possible, otherwise remember class name for later
// selection
if (_treeStore != nullptr)
{
wxDataViewItem item = _treeStore->FindString(eclass, _columns.leafName);

if (item.IsOk())
{
_treeView->Select(item);
_classToHighlight.clear();

return;
}
}

_classToHighlight = eclass;
_treeView->setSelection(eclass);
}

const std::string& EntityClassChooser::getSelectedEntityClass() const
Expand Down Expand Up @@ -313,21 +294,6 @@ int EntityClassChooser::ShowModal()
return returnCode;
}

void EntityClassChooser::setTreeViewModel()
{
_treeView->setTreeModel(_treeStore);

// Expand the first layer
_treeView->ExpandTopLevelItems();

// Pre-select the given class if requested by setSelectedEntityClass()
if (!_classToHighlight.empty())
{
assert(_treeStore);
setSelectedEntityClass(_classToHighlight);
}
}

void EntityClassChooser::setupTreeView()
{
_treeStore = new TreeModel(_columns);
Expand All @@ -339,6 +305,7 @@ void EntityClassChooser::setupTreeView()

_treeView = new ResourceTreeView(parent, _treeStore, _columns);
_treeView->AddSearchColumn(_columns.iconAndName);
_treeView->setExpandTopLevelItemsAfterPopulation(true);

_treeView->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, &EntityClassChooser::onSelectionChanged, this);

Expand All @@ -357,7 +324,7 @@ void EntityClassChooser::updateUsageInfo(const std::string& eclass)

// Set the usage panel to the IEntityClass' usage information string
auto* usageText = findNamedObject<wxTextCtrl>(this, "EntityClassChooserUsageText");
usageText->SetValue(eclass::getUsage(*e));
usageText->SetValue(e ? eclass::getUsage(*e) : "");
}

void EntityClassChooser::updateSelection()
Expand Down Expand Up @@ -422,12 +389,4 @@ void EntityClassChooser::onSelectionChanged(wxDataViewEvent& ev)
updateSelection();
}

void EntityClassChooser::onTreeStorePopulationFinished(TreeModel::PopulationFinishedEvent& ev)
{
_treeView->UnselectAll();

_treeStore = ev.GetTreeModel();
setTreeViewModel();
}

} // namespace ui
5 changes: 0 additions & 5 deletions libs/wxutil/EntityClassChooser.h
Expand Up @@ -44,9 +44,6 @@ class EntityClassChooser :
// Last selected classname
std::string _selectedName;

// Class we should select when the treemodel is populated
std::string _classToHighlight;

// Model preview widget
ModelPreviewPtr _modelPreview;

Expand All @@ -67,7 +64,6 @@ class EntityClassChooser :
// Constructor. Creates the GTK widgets.
EntityClassChooser();

void setTreeViewModel();
void loadEntityClasses();

// Widget construction helpers
Expand All @@ -84,7 +80,6 @@ class EntityClassChooser :
void onOK(wxCommandEvent& ev);
void onSelectionChanged(wxDataViewEvent& ev);
void onDeleteEvent(wxCloseEvent& ev);
void onTreeStorePopulationFinished(TreeModel::PopulationFinishedEvent& ev);

void onMainFrameShuttingDown();

Expand Down
4 changes: 4 additions & 0 deletions libs/wxutil/dataview/IResourceTreePopulator.h
@@ -1,6 +1,7 @@
#pragma once

#include <memory>
#include <wx/event.h>

namespace wxutil
{
Expand All @@ -22,6 +23,9 @@ class IResourceTreePopulator

virtual ~IResourceTreePopulator() {}

// Define the event handler that is notified once population is done
virtual void SetFinishedHandler(wxEvtHandler* finishedHandler) = 0;

// Will start the population and block until population is done.
virtual void EnsurePopulated() = 0;

Expand Down
31 changes: 27 additions & 4 deletions libs/wxutil/dataview/ResourceTreeView.cpp
Expand Up @@ -23,7 +23,8 @@ ResourceTreeView::ResourceTreeView(wxWindow* parent, const TreeModel::Ptr& model
const ResourceTreeView::Columns& columns, long style) :
TreeView(parent, nullptr, style), // associate the model later
_columns(columns),
_mode(TreeMode::ShowAll)
_mode(TreeMode::ShowAll),
_expandTopLevelItemsAfterPopulation(false)
{
// Note that we need to avoid accessing the _columns reference in the constructor
// since it is likely owned by subclasses and might not be ready yet
Expand Down Expand Up @@ -169,10 +170,11 @@ std::string ResourceTreeView::getSelection()

void ResourceTreeView::setSelection(const std::string& fullName)
{
// Wait for any running populator
if (_populator)
{
_populator->EnsurePopulated();
// Postpone the selection, store the name
_itemToSelectAfterPopulation = fullName;
return;
}

// If the selection string is empty, collapse the treeview and return with
Expand All @@ -195,6 +197,8 @@ void ResourceTreeView::setSelection(const std::string& fullName)
wxDataViewEvent ev(wxEVT_DATAVIEW_SELECTION_CHANGED, this, item);
ProcessWindowEvent(ev);
}

_itemToSelectAfterPopulation.clear();
}

void ResourceTreeView::clear()
Expand All @@ -203,6 +207,7 @@ void ResourceTreeView::clear()
_populator.reset();
_treeStore->Clear();
_emptyFavouritesLabel = wxDataViewItem();
_itemToSelectAfterPopulation.clear();
}

void ResourceTreeView::populate(const IResourceTreePopulator::Ptr& populator)
Expand All @@ -219,17 +224,35 @@ void ResourceTreeView::populate(const IResourceTreePopulator::Ptr& populator)

row.SendItemAdded();

// It will fire the TreeModel::PopulationFinishedEvent when done, point it to ourselves
populator->SetFinishedHandler(this);

// Start population (this might be a thread or not)
// In any case this will fire the TreeModel::PopulationFinishedEvent when done
_populator = populator;
_populator->Populate();
}

void ResourceTreeView::setExpandTopLevelItemsAfterPopulation(bool expand)
{
_expandTopLevelItemsAfterPopulation = expand;
}

void ResourceTreeView::_onTreeStorePopulationFinished(TreeModel::PopulationFinishedEvent& ev)
{
UnselectAll();
setTreeModel(ev.GetTreeModel());
_populator.reset();

if (_expandTopLevelItemsAfterPopulation)
{
ExpandTopLevelItems();
}

// Populator is empty now, check if we need to pre-select anything
if (!_itemToSelectAfterPopulation.empty())
{
setSelection(_itemToSelectAfterPopulation);
}
}

void ResourceTreeView::_onContextMenu(wxDataViewEvent& ev)
Expand Down
5 changes: 5 additions & 0 deletions libs/wxutil/dataview/ResourceTreeView.h
Expand Up @@ -67,6 +67,9 @@ class ResourceTreeView :
// The currently active populator object
IResourceTreePopulator::Ptr _populator;

bool _expandTopLevelItemsAfterPopulation;
std::string _itemToSelectAfterPopulation;

public:
ResourceTreeView(wxWindow* parent, const Columns& columns, long style = wxDV_SINGLE);
ResourceTreeView(wxWindow* parent, const TreeModel::Ptr& model, const Columns& columns, long style = wxDV_SINGLE);
Expand All @@ -92,6 +95,8 @@ class ResourceTreeView :
// Populate this tree using the given populator object
virtual void populate(const IResourceTreePopulator::Ptr& populator);

void setExpandTopLevelItemsAfterPopulation(bool expand);

protected:
virtual void populateContextMenu(wxutil::PopupMenu& popupMenu);

Expand Down
15 changes: 12 additions & 3 deletions libs/wxutil/dataview/ThreadedResourceTreePopulator.cpp
Expand Up @@ -12,10 +12,9 @@ struct ThreadAbortedException : public std::runtime_error
};

// Construct and initialise variables
ThreadedResourceTreePopulator::ThreadedResourceTreePopulator(const TreeModel::ColumnRecord& columns,
wxEvtHandler* finishedHandler) :
ThreadedResourceTreePopulator::ThreadedResourceTreePopulator(const TreeModel::ColumnRecord& columns) :
wxThread(wxTHREAD_JOINABLE),
_finishedHandler(finishedHandler),
_finishedHandler(nullptr),
_columns(columns),
_started(false)
{}
Expand Down Expand Up @@ -64,6 +63,11 @@ wxThread::ExitCode ThreadedResourceTreePopulator::Entry()
return static_cast<ExitCode>(0);
}

void ThreadedResourceTreePopulator::SetFinishedHandler(wxEvtHandler* finishedHandler)
{
_finishedHandler = finishedHandler;
}

void ThreadedResourceTreePopulator::EnsurePopulated()
{
// Start the thread now if we have to
Expand All @@ -81,6 +85,11 @@ void ThreadedResourceTreePopulator::EnsurePopulated()

void ThreadedResourceTreePopulator::Populate()
{
if (_finishedHandler == nullptr)
{
throw std::runtime_error("Cannot start population without a finished handler");
}

if (IsRunning())
{
return;
Expand Down
4 changes: 3 additions & 1 deletion libs/wxutil/dataview/ThreadedResourceTreePopulator.h
Expand Up @@ -58,12 +58,14 @@ class ThreadedResourceTreePopulator :

public:
// Construct and initialise variables
ThreadedResourceTreePopulator(const TreeModel::ColumnRecord& columns, wxEvtHandler* finishedHandler);
ThreadedResourceTreePopulator(const TreeModel::ColumnRecord& columns);

virtual ~ThreadedResourceTreePopulator();

// IResourceTreePopulator implementation

virtual void SetFinishedHandler(wxEvtHandler* finishedHandler) override;

// Blocks until the worker thread is done.
virtual void EnsurePopulated() override;

Expand Down
6 changes: 3 additions & 3 deletions radiant/ui/mediabrowser/MediaBrowserTreeView.cpp
Expand Up @@ -172,8 +172,8 @@ class MediaPopulator final :

public:
// Construct and initialise variables
MediaPopulator(const MediaBrowserTreeView::TreeColumns& columns, wxEvtHandler* finishedHandler) :
ThreadedResourceTreePopulator(columns, finishedHandler),
MediaPopulator(const MediaBrowserTreeView::TreeColumns& columns) :
ThreadedResourceTreePopulator(columns),
_columns(columns)
{
_favourites = GlobalFavouritesManager().getFavourites(decl::Type::Material);
Expand Down Expand Up @@ -303,7 +303,7 @@ void MediaBrowserTreeView::setTreeMode(MediaBrowserTreeView::TreeMode mode)

void MediaBrowserTreeView::populate()
{
ResourceTreeView::populate(std::make_shared<MediaPopulator>(_columns, this));
ResourceTreeView::populate(std::make_shared<MediaPopulator>(_columns));
}

void MediaBrowserTreeView::populateContextMenu(wxutil::PopupMenu& popupMenu)
Expand Down

0 comments on commit dbb8f97

Please sign in to comment.