Extracted CMP_TREE_MODEL_ADAPTER_BASE class
This commit is contained in:
parent
3288a5f8b8
commit
0d190639f1
|
@ -124,6 +124,7 @@ set( EESCHEMA_SRCS
|
|||
getpart.cpp
|
||||
cmp_tree_model.cpp
|
||||
cmp_tree_model_adapter.cpp
|
||||
cmp_tree_model_adapter_base.cpp
|
||||
generate_alias_info.cpp
|
||||
hierarch.cpp
|
||||
highlight_connection.cpp
|
||||
|
|
|
@ -133,7 +133,6 @@ CMP_TREE_NODE_LIB_ID::CMP_TREE_NODE_LIB_ID( CMP_TREE_NODE* aParent, LIB_ALIAS* a
|
|||
|
||||
Type = LIBID;
|
||||
Parent = aParent;
|
||||
Type = ALIAS;
|
||||
Name = aAlias->GetName();
|
||||
Desc = aAlias->GetDescription();
|
||||
|
||||
|
|
|
@ -26,51 +26,7 @@
|
|||
#include <symbol_lib_table.h>
|
||||
#include <wx/progdlg.h>
|
||||
|
||||
CMP_TREE_MODEL_ADAPTER::WIDTH_CACHE CMP_TREE_MODEL_ADAPTER::m_width_cache;
|
||||
|
||||
|
||||
static const int kDataViewIndent = 20;
|
||||
|
||||
|
||||
/**
|
||||
* Convert CMP_TREE_NODE -> wxDataViewItem
|
||||
*/
|
||||
static wxDataViewItem ToItem( CMP_TREE_NODE const* aNode )
|
||||
{
|
||||
return wxDataViewItem( const_cast<void*>( static_cast<void const*>( aNode ) ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert wxDataViewItem -> CMP_TREE_NODE
|
||||
*/
|
||||
static CMP_TREE_NODE const* ToNode( wxDataViewItem aItem )
|
||||
{
|
||||
return static_cast<CMP_TREE_NODE const*>( aItem.GetID() );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert CMP_TREE_NODE's children to wxDataViewItemArray
|
||||
*/
|
||||
static unsigned int IntoArray( CMP_TREE_NODE const& aNode, wxDataViewItemArray& aChildren )
|
||||
{
|
||||
unsigned int n = 0;
|
||||
|
||||
for( auto const& child: aNode.Children )
|
||||
{
|
||||
if( child->Score > 0 )
|
||||
{
|
||||
aChildren.Add( ToItem( &*child ) );
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
CMP_TREE_MODEL_ADAPTER::PTR CMP_TREE_MODEL_ADAPTER::Create( SYMBOL_LIB_TABLE* aLibs )
|
||||
CMP_TREE_MODEL_ADAPTER_BASE::PTR CMP_TREE_MODEL_ADAPTER::Create( SYMBOL_LIB_TABLE* aLibs )
|
||||
{
|
||||
auto adapter = new CMP_TREE_MODEL_ADAPTER( aLibs );
|
||||
auto container = CMP_TREE_MODEL_ADAPTER::PTR( adapter );
|
||||
|
@ -79,13 +35,7 @@ CMP_TREE_MODEL_ADAPTER::PTR CMP_TREE_MODEL_ADAPTER::Create( SYMBOL_LIB_TABLE* aL
|
|||
|
||||
|
||||
CMP_TREE_MODEL_ADAPTER::CMP_TREE_MODEL_ADAPTER( SYMBOL_LIB_TABLE* aLibs )
|
||||
:m_filter( CMP_FILTER_NONE ),
|
||||
m_show_units( true ),
|
||||
m_libs( aLibs ),
|
||||
m_preselect_unit( 0 ),
|
||||
m_col_part( nullptr ),
|
||||
m_col_desc( nullptr ),
|
||||
m_widget( nullptr )
|
||||
: m_libs( aLibs )
|
||||
{}
|
||||
|
||||
|
||||
|
@ -93,28 +43,9 @@ CMP_TREE_MODEL_ADAPTER::~CMP_TREE_MODEL_ADAPTER()
|
|||
{}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::SetFilter( CMP_FILTER_TYPE aFilter )
|
||||
{
|
||||
m_filter = aFilter;
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::ShowUnits( bool aShow )
|
||||
{
|
||||
m_show_units = aShow;
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::SetPreselectNode( LIB_ID const& aLibId, int aUnit )
|
||||
{
|
||||
m_preselect_lib_id = aLibId;
|
||||
m_preselect_unit = aUnit;
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::AddLibrary( wxString const& aLibNickname )
|
||||
{
|
||||
bool onlyPowerSymbols = ( m_filter == CMP_FILTER_POWER );
|
||||
bool onlyPowerSymbols = ( GetFilter() == CMP_FILTER_POWER );
|
||||
|
||||
wxArrayString aliases;
|
||||
|
||||
|
@ -135,26 +66,6 @@ void CMP_TREE_MODEL_ADAPTER::AddLibrary( wxString const& aLibNickname )
|
|||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::AddLibrariesWithProgress( const std::vector<wxString>& aNicknames, EDA_DRAW_FRAME* aParent )
|
||||
{
|
||||
auto* prg = new wxProgressDialog(
|
||||
_( "Loading symbol libraries" ),
|
||||
wxEmptyString,
|
||||
aNicknames.size(),
|
||||
aParent );
|
||||
|
||||
unsigned int ii = 0;
|
||||
|
||||
for( auto nickname : aNicknames )
|
||||
{
|
||||
prg->Update( ii++, wxString::Format( _( "Loading library '%s'" ), nickname ) );
|
||||
AddLibrary( nickname );
|
||||
}
|
||||
|
||||
prg->Destroy();
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::AddAliasList(
|
||||
wxString const& aNodeName,
|
||||
wxArrayString const& aAliasNameList )
|
||||
|
@ -182,319 +93,3 @@ void CMP_TREE_MODEL_ADAPTER::AddAliasList(
|
|||
|
||||
AddAliasList( aNodeName, alias_list );
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::AddAliasList(
|
||||
wxString const& aNodeName,
|
||||
std::vector<LIB_ALIAS*> const& aAliasList )
|
||||
{
|
||||
auto& lib_node = m_tree.AddLib( aNodeName );
|
||||
|
||||
for( auto a: aAliasList )
|
||||
{
|
||||
lib_node.AddAlias( a );
|
||||
}
|
||||
|
||||
lib_node.AssignIntrinsicRanks();
|
||||
m_tree.AssignIntrinsicRanks();
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::UpdateSearchString( wxString const& aSearch )
|
||||
{
|
||||
m_tree.ResetScore();
|
||||
|
||||
wxStringTokenizer tokenizer( aSearch );
|
||||
|
||||
while( tokenizer.HasMoreTokens() )
|
||||
{
|
||||
const wxString term = tokenizer.GetNextToken().Lower();
|
||||
EDA_COMBINED_MATCHER matcher( term );
|
||||
|
||||
m_tree.UpdateScore( matcher );
|
||||
}
|
||||
|
||||
m_tree.SortNodes();
|
||||
Cleared();
|
||||
AttachTo( m_widget );
|
||||
|
||||
ShowResults() || ShowPreselect() || ShowSingleLibrary();
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::AttachTo( wxDataViewCtrl* aDataViewCtrl )
|
||||
{
|
||||
m_widget = aDataViewCtrl;
|
||||
aDataViewCtrl->Freeze();
|
||||
aDataViewCtrl->SetIndent( kDataViewIndent );
|
||||
aDataViewCtrl->AssociateModel( this );
|
||||
aDataViewCtrl->ClearColumns();
|
||||
|
||||
wxString part_head = _( "Part" );
|
||||
wxString desc_head = _( "Desc" );
|
||||
|
||||
m_col_part = aDataViewCtrl->AppendTextColumn( part_head, 0, wxDATAVIEW_CELL_INERT,
|
||||
ColWidth( m_tree, 0, part_head ) );
|
||||
m_col_desc = aDataViewCtrl->AppendTextColumn( desc_head, 1, wxDATAVIEW_CELL_INERT,
|
||||
ColWidth( m_tree, 1, desc_head ) );
|
||||
aDataViewCtrl->Thaw();
|
||||
}
|
||||
|
||||
|
||||
LIB_ID CMP_TREE_MODEL_ADAPTER::GetAliasFor( const wxDataViewItem& aSelection ) const
|
||||
{
|
||||
auto node = ToNode( aSelection );
|
||||
|
||||
LIB_ID emptyId;
|
||||
|
||||
if( !node )
|
||||
return emptyId;
|
||||
|
||||
return node->LibId;
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER::GetUnitFor( const wxDataViewItem& aSelection ) const
|
||||
{
|
||||
auto node = ToNode( aSelection );
|
||||
return node ? node->Unit : 0;
|
||||
}
|
||||
|
||||
|
||||
CMP_TREE_NODE::TYPE CMP_TREE_MODEL_ADAPTER::GetTypeFor( const wxDataViewItem& aSelection ) const
|
||||
{
|
||||
auto node = ToNode( aSelection );
|
||||
return node ? node->Type : CMP_TREE_NODE::INVALID;
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER::GetComponentsCount() const
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for( auto& lib: m_tree.Children )
|
||||
{
|
||||
for( auto& alias: lib->Children )
|
||||
{
|
||||
(void) alias;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER::HasContainerColumns( wxDataViewItem const& aItem ) const
|
||||
{
|
||||
return IsContainer( aItem );
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER::IsContainer( wxDataViewItem const& aItem ) const
|
||||
{
|
||||
auto node = ToNode( aItem );
|
||||
return node ? node->Children.size() : true;
|
||||
}
|
||||
|
||||
|
||||
wxDataViewItem CMP_TREE_MODEL_ADAPTER::GetParent( wxDataViewItem const& aItem ) const
|
||||
{
|
||||
auto node = ToNode( aItem );
|
||||
auto parent = node ? node->Parent : nullptr;
|
||||
|
||||
// wxDataViewModel has no root node, but rather top-level elements have
|
||||
// an invalid (null) parent.
|
||||
if( !node || !parent || parent->Type == CMP_TREE_NODE::TYPE::ROOT )
|
||||
{
|
||||
return ToItem( nullptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToItem( parent );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int CMP_TREE_MODEL_ADAPTER::GetChildren(
|
||||
wxDataViewItem const& aItem,
|
||||
wxDataViewItemArray& aChildren ) const
|
||||
{
|
||||
auto node = ( aItem.IsOk() ? ToNode( aItem ) : &m_tree );
|
||||
|
||||
if( node->Type != CMP_TREE_NODE::TYPE::LIBID || m_show_units )
|
||||
return IntoArray( *node, aChildren );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER::GetValue(
|
||||
wxVariant& aVariant,
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol ) const
|
||||
{
|
||||
auto node = ToNode( aItem );
|
||||
wxASSERT( node );
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
case 0:
|
||||
aVariant = node->Name;
|
||||
break;
|
||||
case 1:
|
||||
aVariant = node->Desc;
|
||||
break;
|
||||
default:
|
||||
wxFAIL_MSG( "Invalid column ID!" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER::GetAttr(
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol,
|
||||
wxDataViewItemAttr& aAttr ) const
|
||||
{
|
||||
auto node = ToNode( aItem );
|
||||
wxASSERT( node );
|
||||
|
||||
if( node->Type != CMP_TREE_NODE::LIBID )
|
||||
{
|
||||
// Currently only aliases are formatted at all
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !node->IsRoot && aCol == 0 )
|
||||
{
|
||||
// Names of non-root aliases are italicized
|
||||
aAttr.SetItalic( true );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER::ColWidth( CMP_TREE_NODE& aTree, int aCol, wxString const& aHeading )
|
||||
{
|
||||
const int indent = aCol ? 0 : kDataViewIndent;
|
||||
|
||||
int min_width = WidthFor( aHeading, aCol );
|
||||
int width = std::max( aTree.Score > 0 ? WidthFor( aTree, aCol ) : 0, min_width );
|
||||
|
||||
if( aTree.Score > 0 )
|
||||
{
|
||||
for( auto& node: aTree.Children )
|
||||
{
|
||||
width = std::max( width, ColWidth( *node, aCol, aHeading ) + indent );
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER::WidthFor( CMP_TREE_NODE& aNode, int aCol )
|
||||
{
|
||||
auto result = m_width_cache.find( aNode.Name );
|
||||
|
||||
if( result != m_width_cache.end() )
|
||||
{
|
||||
return result->second[aCol];
|
||||
}
|
||||
else
|
||||
{
|
||||
int wname = m_widget->GetTextExtent( aNode.Name ).x + kDataViewIndent;
|
||||
int wdesc = m_widget->GetTextExtent( aNode.Desc ).x;
|
||||
|
||||
auto& val = m_width_cache[aNode.Name];
|
||||
val.push_back( wname );
|
||||
val.push_back( wdesc );
|
||||
return val[aCol];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER::WidthFor( wxString const& aHeading, int aCol )
|
||||
{
|
||||
static std::vector<int> widths;
|
||||
|
||||
for( int i = (int) widths.size(); i <= aCol; ++i )
|
||||
{
|
||||
widths.push_back( 0 );
|
||||
}
|
||||
|
||||
if( widths[aCol] == 0 )
|
||||
{
|
||||
widths[aCol] = m_widget->GetTextExtent( aHeading ).x;
|
||||
}
|
||||
|
||||
return widths[aCol];
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER::FindAndExpand(
|
||||
CMP_TREE_NODE& aNode,
|
||||
std::function<bool( CMP_TREE_NODE const* )> aFunc )
|
||||
{
|
||||
for( auto& node: aNode.Children )
|
||||
{
|
||||
if( aFunc( &*node ) )
|
||||
{
|
||||
auto item = wxDataViewItem(
|
||||
const_cast<void*>( static_cast<void const*>( &*node ) ) );
|
||||
m_widget->ExpandAncestors( item );
|
||||
m_widget->EnsureVisible( item );
|
||||
m_widget->Select( item );
|
||||
return true;
|
||||
}
|
||||
else if( FindAndExpand( *node, aFunc ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER::ShowResults()
|
||||
{
|
||||
return FindAndExpand( m_tree,
|
||||
[]( CMP_TREE_NODE const* n )
|
||||
{
|
||||
return n->Type == CMP_TREE_NODE::TYPE::LIBID && n->Score > 1;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER::ShowPreselect()
|
||||
{
|
||||
if( !m_preselect_lib_id.IsValid() )
|
||||
return false;
|
||||
|
||||
return FindAndExpand( m_tree,
|
||||
[&]( CMP_TREE_NODE const* n )
|
||||
{
|
||||
if( n->Type == CMP_TREE_NODE::LIBID && ( n->Children.empty() || !m_preselect_unit ) )
|
||||
return m_preselect_lib_id == n->LibId;
|
||||
else if( n->Type == CMP_TREE_NODE::UNIT && m_preselect_unit )
|
||||
return m_preselect_lib_id == n->Parent->LibId && m_preselect_unit == n->Unit;
|
||||
else
|
||||
return false;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER::ShowSingleLibrary()
|
||||
{
|
||||
return FindAndExpand( m_tree,
|
||||
[]( CMP_TREE_NODE const* n )
|
||||
{
|
||||
return n->Type == CMP_TREE_NODE::TYPE::LIBID &&
|
||||
n->Parent->Parent->Children.size() == 1;
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -22,84 +22,18 @@
|
|||
#ifndef _CMP_TREE_MODEL_ADAPTER_H
|
||||
#define _CMP_TREE_MODEL_ADAPTER_H
|
||||
|
||||
#include <lib_id.h>
|
||||
|
||||
#include <draw_frame.h>
|
||||
#include <cmp_tree_model.h>
|
||||
|
||||
#include <wx/hashmap.h>
|
||||
#include <wx/dataview.h>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cmp_tree_model_adapter_base.h>
|
||||
|
||||
class SYMBOL_LIB_TABLE;
|
||||
|
||||
|
||||
/**
|
||||
* Adapter class in the component selector Model-View-Adapter (mediated MVC)
|
||||
* architecture. The other pieces are in:
|
||||
*
|
||||
* - Model: CMP_TREE_NODE and descendants in eeschema/cmp_tree_model.h
|
||||
* - View:
|
||||
* - DIALOG_CHOOSE_COMPONENT in eeschema/dialogs/dialog_choose_component.h
|
||||
* - wxDataViewCtrl
|
||||
*
|
||||
* This adapter presents the interface specified by wxDataViewModel to the
|
||||
* wxDataViewCtrl:
|
||||
*
|
||||
* +---+ +------------------+
|
||||
* +---+ Generates | A | | VIEW |
|
||||
* | M | from libs | D | wxDataViewModel |------------------|
|
||||
* | O | <---------- | A | <------------------> | wxDataViewCtrl |
|
||||
* | D | | P | |------------------|
|
||||
* | E | <---------> | T | <------------------- | wxTextCtrl |
|
||||
* | L | UpdateScore | E | UpdateSearchString() |------------------|
|
||||
* +---+ | R | | |
|
||||
* +---+ +------------------+
|
||||
*
|
||||
* Because this adapter is a wxDataViewModel, it is reference-counted by
|
||||
* wxObject. To ensure this interface is used correctly, the constructor
|
||||
* is private; CMP_TREE_MODEL_ADAPTER should be created by the static
|
||||
* factory method CMP_TREE_MODEL_ADAPTER::Create().
|
||||
*
|
||||
* Quick summary of methods used to drive this class:
|
||||
*
|
||||
* - `SetFilter()` - set whether the view is restricted to power parts
|
||||
* - `ShowUnits()` - set whether units are displayed
|
||||
* - `SetPreselectNode()` - set a node to highlight when not searching
|
||||
* - `AddLibrary()` - populate the model with all aliases in a library
|
||||
* - `AddAliasList()` - populate the model with a specific list of aliases
|
||||
*
|
||||
* Quick summary of methods used by the View:
|
||||
*
|
||||
* - `UpdateSearchString()` - pass in the user's search text
|
||||
* - `AttachTo()` - pass in the wxDataViewCtrl
|
||||
* - `GetAliasFor()` - get the LIB_ALIAS* for a selected item
|
||||
* - `GetUnitFor()` - get the unit for a selected item
|
||||
* - `GetComponentsCount()` - count the aliases loaded
|
||||
*
|
||||
* Methods implemented as part of wxDataViewModel:
|
||||
*
|
||||
* - `HasContainerColumns()` - whether a parent item has more than one column
|
||||
* - `IsContainer()` - whether an item is a parent
|
||||
* - `GetParent()` - return the parent of an item, or invalid if root
|
||||
* - `GetChildren()` - get the children of an item
|
||||
* - `GetColumnCount()` - get the number of columns in the view
|
||||
* - `GetColumnType()` - get the data type shown in each column
|
||||
* - `GetValue()` - get the data shown in a cell
|
||||
* - `SetValue()` - edit the data in a cell (does nothing)
|
||||
* - `GetAttr()` - get any per-item formatting
|
||||
* - `Compare()` - compare two rows, for sorting
|
||||
* - `HasDefaultCompare()` - whether sorted by default
|
||||
*/
|
||||
class CMP_TREE_MODEL_ADAPTER: public wxDataViewModel
|
||||
class CMP_TREE_MODEL_ADAPTER: public CMP_TREE_MODEL_ADAPTER_BASE
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Reference-counting container for a pointer to CMP_TREE_MODEL_ADAPTER.
|
||||
*/
|
||||
typedef wxObjectDataPtr<CMP_TREE_MODEL_ADAPTER> PTR;
|
||||
//typedef wxObjectDataPtr<CMP_TREE_MODEL_ADAPTER> PTR;
|
||||
|
||||
/**
|
||||
* Destructor. Do NOT delete this class manually; it is reference-counted
|
||||
|
@ -115,57 +49,13 @@ public:
|
|||
*/
|
||||
static PTR Create( SYMBOL_LIB_TABLE* aLibs );
|
||||
|
||||
/**
|
||||
* This enum allows a selective filtering of components to list
|
||||
*/
|
||||
enum CMP_FILTER_TYPE
|
||||
{
|
||||
CMP_FILTER_NONE, ///< no filtering
|
||||
CMP_FILTER_POWER, ///< list components flagged PWR
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the component filter type. Must be set before adding libraries
|
||||
*
|
||||
* @param aFilter if CMP_FILTER_POWER, only power parts are loaded
|
||||
*/
|
||||
void SetFilter( CMP_FILTER_TYPE aFilter );
|
||||
|
||||
/**
|
||||
* Whether or not to show units. May be set at any time; updates at the next
|
||||
* UpdateSearchString()
|
||||
*
|
||||
* @param aShow if true, units are displayed
|
||||
*/
|
||||
void ShowUnits( bool aShow );
|
||||
|
||||
/**
|
||||
* Set the component name to be selected if there are no search results.
|
||||
* May be set at any time; updates at the next UpdateSearchString().
|
||||
*
|
||||
* @param aLibId symbol #LIB_ID to be selected
|
||||
* @param aUnit unit to be selected, if > 0 (0 selects the alias itself)
|
||||
*/
|
||||
void SetPreselectNode( LIB_ID const& aLibId, int aUnit );
|
||||
|
||||
/**
|
||||
* Add all the components and their aliases in this library. To be called
|
||||
* in the setup phase.
|
||||
*
|
||||
* @param aLibNickname reference to a symbol library nickname
|
||||
*/
|
||||
void AddLibrary( wxString const& aLibNickname );
|
||||
|
||||
|
||||
/**
|
||||
* Add all the libraries in a SYMBOL_LIB_TABLE to the model,
|
||||
* displaying a progress dialog attached to the parent frame
|
||||
*
|
||||
* @param aNicknames is the list of library nicknames
|
||||
* @param aParent is the parent window to display the progress dialog
|
||||
*/
|
||||
void AddLibrariesWithProgress( const std::vector<wxString>& aNicknames, EDA_DRAW_FRAME* aParent );
|
||||
|
||||
void AddLibrary( wxString const& aLibNickname ) override;
|
||||
|
||||
/**
|
||||
* Add the given list of components, by name. To be called in the setup
|
||||
|
@ -176,70 +66,9 @@ public:
|
|||
*/
|
||||
void AddAliasList(
|
||||
wxString const& aNodeName,
|
||||
wxArrayString const& aAliasNameList );
|
||||
|
||||
/**
|
||||
* Add the given list of components by alias. To be called in the setup
|
||||
* phase.
|
||||
*
|
||||
* @param aNodeName the parent node the components will appear under
|
||||
* @param aAliasList list of aliases
|
||||
*/
|
||||
void AddAliasList(
|
||||
wxString const& aNodeName,
|
||||
std::vector<LIB_ALIAS*> const& aAliasList );
|
||||
|
||||
/**
|
||||
* Set the search string provided by the user.
|
||||
*
|
||||
* @param aSearch full, unprocessed search text
|
||||
*/
|
||||
void UpdateSearchString( wxString const& aSearch );
|
||||
|
||||
/**
|
||||
* Attach to a wxDataViewCtrl and initialize it. This will set up columns
|
||||
* and associate the model via the adapter.
|
||||
*
|
||||
* @param aDataViewCtrl the view component in the dialog
|
||||
*/
|
||||
void AttachTo( wxDataViewCtrl* aDataViewCtrl );
|
||||
|
||||
/**
|
||||
* Return the alias for the given item.
|
||||
*
|
||||
* @param aSelection item from the wxDataViewCtrl
|
||||
* (see wxDataViewCtrl::GetSelection())
|
||||
*
|
||||
* @return alias, or nullptr if none is selected
|
||||
*/
|
||||
LIB_ID GetAliasFor( const wxDataViewItem& aSelection ) const;
|
||||
|
||||
/**
|
||||
* Return the unit for the given item.
|
||||
*
|
||||
* @param aSelection item from the wxDataViewCtrl
|
||||
* (see wxDataViewCtrl::GetSelection())
|
||||
*
|
||||
* @return Unit, or zero if the alias itself is selected. Return valid is
|
||||
* invalid if GetAliasFor() returns nullptr.
|
||||
*/
|
||||
int GetUnitFor( const wxDataViewItem& aSelection ) const;
|
||||
|
||||
/**
|
||||
* Return node type for the given item.
|
||||
*
|
||||
* @param aSelection item from the wxDataViewCtrl
|
||||
* (see wxDataViewCtrl::GetSelection())
|
||||
*
|
||||
* @return Type of the selected node, might be INVALID.
|
||||
*/
|
||||
CMP_TREE_NODE::TYPE GetTypeFor( const wxDataViewItem& aSelection ) const;
|
||||
|
||||
/**
|
||||
* Return the number of components loaded in the tree.
|
||||
*/
|
||||
int GetComponentsCount() const;
|
||||
wxArrayString const& aAliasNameList ) override;
|
||||
|
||||
using CMP_TREE_MODEL_ADAPTER_BASE::AddAliasList;
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
@ -247,143 +76,8 @@ protected:
|
|||
*/
|
||||
CMP_TREE_MODEL_ADAPTER( SYMBOL_LIB_TABLE* aLibs );
|
||||
|
||||
/**
|
||||
* Check whether a container has columns too
|
||||
*/
|
||||
virtual bool HasContainerColumns( wxDataViewItem const& aItem ) const override;
|
||||
|
||||
/**
|
||||
* Check whether an item can have children.
|
||||
*/
|
||||
virtual bool IsContainer( wxDataViewItem const& aItem ) const override;
|
||||
|
||||
/**
|
||||
* Get the parent of an item.
|
||||
*
|
||||
* @param aItem item to get the parent of
|
||||
* @return parent of aItem, or an invalid wxDataViewItem if parent is root
|
||||
*/
|
||||
virtual wxDataViewItem GetParent( wxDataViewItem const& aItem ) const override;
|
||||
|
||||
/**
|
||||
* Populate a list of all the children of an item
|
||||
*
|
||||
* @return number of children
|
||||
*/
|
||||
virtual unsigned int GetChildren(
|
||||
wxDataViewItem const& aItem,
|
||||
wxDataViewItemArray& aChildren ) const override;
|
||||
|
||||
/**
|
||||
* Return the number of columns in the model
|
||||
*/
|
||||
virtual unsigned int GetColumnCount() const override { return 2; }
|
||||
|
||||
/**
|
||||
* Return the type of data stored in the column
|
||||
*
|
||||
* @return type of data as indicated by wxVariant::GetType()
|
||||
*/
|
||||
virtual wxString GetColumnType( unsigned int aCol ) const override { return "string"; }
|
||||
|
||||
/**
|
||||
* Get the value of an item.
|
||||
*
|
||||
* @param aVariant wxVariant to receive the data
|
||||
* @param aItem item whose data will be placed into aVariant
|
||||
* @param aCol column number of the data
|
||||
*/
|
||||
virtual void GetValue(
|
||||
wxVariant& aVariant,
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol ) const override;
|
||||
|
||||
/**
|
||||
* Set the value of an item. Does nothing - this model doesn't support
|
||||
* editing.
|
||||
*/
|
||||
virtual bool SetValue(
|
||||
wxVariant const& aVariant,
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol ) override { return false; }
|
||||
|
||||
/**
|
||||
* Get any formatting for an item.
|
||||
*
|
||||
* @param aItem item to get formatting for
|
||||
* @param aCol column number of interest
|
||||
* @param aAttr receiver for attributes
|
||||
* @return true iff the item has non-default attributes
|
||||
*/
|
||||
virtual bool GetAttr(
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol,
|
||||
wxDataViewItemAttr& aAttr ) const override;
|
||||
|
||||
private:
|
||||
CMP_FILTER_TYPE m_filter;
|
||||
bool m_show_units;
|
||||
SYMBOL_LIB_TABLE* m_libs;
|
||||
LIB_ID m_preselect_lib_id;
|
||||
int m_preselect_unit;
|
||||
|
||||
CMP_TREE_NODE_ROOT m_tree;
|
||||
|
||||
wxDataViewColumn* m_col_part;
|
||||
wxDataViewColumn* m_col_desc;
|
||||
wxDataViewCtrl* m_widget;
|
||||
|
||||
WX_DECLARE_STRING_HASH_MAP( std::vector<int>, WIDTH_CACHE );
|
||||
|
||||
static WIDTH_CACHE m_width_cache;
|
||||
|
||||
/**
|
||||
* Compute the width required for the given column of a node and its
|
||||
* children.
|
||||
*
|
||||
* @param aTree - root node of the tree
|
||||
* @param aCol - column number
|
||||
* @param aHeading - heading text, to set the minimum width
|
||||
*/
|
||||
int ColWidth( CMP_TREE_NODE& aTree, int aCol, wxString const& aHeading );
|
||||
|
||||
/**
|
||||
* Return the width required to display a single row's aCol text.
|
||||
* This is cached for efficiency as it's very slow on some platforms
|
||||
* (*cough* macOS)
|
||||
*/
|
||||
int WidthFor( CMP_TREE_NODE& aNode, int aCol );
|
||||
|
||||
/**
|
||||
* Return the width required to display a column's heading. This is
|
||||
* cached by column number for the same reason as the width per cell.
|
||||
*/
|
||||
int WidthFor( wxString const& aHeading, int aCol );
|
||||
|
||||
/**
|
||||
* Find any results worth highlighting and expand them, according to given
|
||||
* criteria (f(CMP_TREE_NODE const*) -> bool)
|
||||
*
|
||||
* @return whether a node was expanded
|
||||
*/
|
||||
bool FindAndExpand(
|
||||
CMP_TREE_NODE& aNode,
|
||||
std::function<bool( CMP_TREE_NODE const* )> aFunc );
|
||||
|
||||
/**
|
||||
* Find and expand successful search results
|
||||
*/
|
||||
bool ShowResults();
|
||||
|
||||
/**
|
||||
* Find and expand preselected node
|
||||
*/
|
||||
bool ShowPreselect();
|
||||
|
||||
/**
|
||||
* Find and expand a library if there is only one
|
||||
*/
|
||||
bool ShowSingleLibrary();
|
||||
};
|
||||
|
||||
#endif // _CMP_TREE_MODEL_ADAPTER_H
|
||||
|
|
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
|
||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||
* Copyright (C) 2014-2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cmp_tree_model_adapter_base.h>
|
||||
|
||||
#include <eda_pattern_match.h>
|
||||
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/tokenzr.h>
|
||||
|
||||
|
||||
CMP_TREE_MODEL_ADAPTER_BASE::WIDTH_CACHE CMP_TREE_MODEL_ADAPTER_BASE::m_width_cache;
|
||||
|
||||
|
||||
static const int kDataViewIndent = 20;
|
||||
|
||||
|
||||
/**
|
||||
* Convert CMP_TREE_NODE -> wxDataViewItem
|
||||
*/
|
||||
wxDataViewItem CMP_TREE_MODEL_ADAPTER_BASE::ToItem( CMP_TREE_NODE const* aNode )
|
||||
{
|
||||
return wxDataViewItem( const_cast<void*>( static_cast<void const*>( aNode ) ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert wxDataViewItem -> CMP_TREE_NODE
|
||||
*/
|
||||
CMP_TREE_NODE const* CMP_TREE_MODEL_ADAPTER_BASE::ToNode( wxDataViewItem aItem )
|
||||
{
|
||||
return static_cast<CMP_TREE_NODE const*>( aItem.GetID() );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert CMP_TREE_NODE's children to wxDataViewItemArray
|
||||
*/
|
||||
unsigned int CMP_TREE_MODEL_ADAPTER_BASE::IntoArray(
|
||||
CMP_TREE_NODE const& aNode, wxDataViewItemArray& aChildren )
|
||||
{
|
||||
unsigned int n = 0;
|
||||
|
||||
for( auto const& child: aNode.Children )
|
||||
{
|
||||
if( child->Score > 0 )
|
||||
{
|
||||
aChildren.Add( ToItem( &*child ) );
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
CMP_TREE_MODEL_ADAPTER_BASE::CMP_TREE_MODEL_ADAPTER_BASE()
|
||||
:m_filter( CMP_FILTER_NONE ),
|
||||
m_show_units( true ),
|
||||
m_preselect_unit( 0 ),
|
||||
m_col_part( nullptr ),
|
||||
m_col_desc( nullptr ),
|
||||
m_widget( nullptr )
|
||||
{}
|
||||
|
||||
|
||||
CMP_TREE_MODEL_ADAPTER_BASE::~CMP_TREE_MODEL_ADAPTER_BASE()
|
||||
{}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER_BASE::SetFilter( CMP_FILTER_TYPE aFilter )
|
||||
{
|
||||
m_filter = aFilter;
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER_BASE::ShowUnits( bool aShow )
|
||||
{
|
||||
m_show_units = aShow;
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER_BASE::SetPreselectNode( LIB_ID const& aLibId, int aUnit )
|
||||
{
|
||||
m_preselect_lib_id = aLibId;
|
||||
m_preselect_unit = aUnit;
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER_BASE::AddLibrariesWithProgress(
|
||||
const std::vector<wxString>& aNicknames, wxWindow* aParent )
|
||||
{
|
||||
auto* prg = new wxProgressDialog(
|
||||
_( "Loading symbol libraries" ),
|
||||
wxEmptyString,
|
||||
aNicknames.size(),
|
||||
aParent );
|
||||
|
||||
unsigned int ii = 0;
|
||||
|
||||
for( auto nickname : aNicknames )
|
||||
{
|
||||
prg->Update( ii++, wxString::Format( _( "Loading library '%s'" ), nickname ) );
|
||||
AddLibrary( nickname );
|
||||
}
|
||||
|
||||
prg->Destroy();
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER_BASE::AddAliasList(
|
||||
wxString const& aNodeName,
|
||||
std::vector<LIB_ALIAS*> const& aAliasList )
|
||||
{
|
||||
auto& lib_node = m_tree.AddLib( aNodeName );
|
||||
|
||||
for( auto a: aAliasList )
|
||||
{
|
||||
lib_node.AddAlias( a );
|
||||
}
|
||||
|
||||
lib_node.AssignIntrinsicRanks();
|
||||
m_tree.AssignIntrinsicRanks();
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER_BASE::UpdateSearchString( wxString const& aSearch )
|
||||
{
|
||||
m_tree.ResetScore();
|
||||
|
||||
wxStringTokenizer tokenizer( aSearch );
|
||||
|
||||
while( tokenizer.HasMoreTokens() )
|
||||
{
|
||||
const wxString term = tokenizer.GetNextToken().Lower();
|
||||
EDA_COMBINED_MATCHER matcher( term );
|
||||
|
||||
m_tree.UpdateScore( matcher );
|
||||
}
|
||||
|
||||
m_tree.SortNodes();
|
||||
Cleared();
|
||||
AttachTo( m_widget );
|
||||
|
||||
ShowResults() || ShowPreselect() || ShowSingleLibrary();
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER_BASE::AttachTo( wxDataViewCtrl* aDataViewCtrl )
|
||||
{
|
||||
m_widget = aDataViewCtrl;
|
||||
aDataViewCtrl->Freeze();
|
||||
aDataViewCtrl->SetIndent( kDataViewIndent );
|
||||
aDataViewCtrl->AssociateModel( this );
|
||||
aDataViewCtrl->ClearColumns();
|
||||
|
||||
wxString part_head = _( "Part" );
|
||||
wxString desc_head = _( "Desc" );
|
||||
|
||||
m_col_part = aDataViewCtrl->AppendTextColumn( part_head, 0, wxDATAVIEW_CELL_INERT,
|
||||
ColWidth( m_tree, 0, part_head ) );
|
||||
m_col_desc = aDataViewCtrl->AppendTextColumn( desc_head, 1, wxDATAVIEW_CELL_INERT,
|
||||
ColWidth( m_tree, 1, desc_head ) );
|
||||
aDataViewCtrl->Thaw();
|
||||
}
|
||||
|
||||
|
||||
LIB_ID CMP_TREE_MODEL_ADAPTER_BASE::GetAliasFor( const wxDataViewItem& aSelection ) const
|
||||
{
|
||||
auto node = ToNode( aSelection );
|
||||
|
||||
LIB_ID emptyId;
|
||||
|
||||
if( !node )
|
||||
return emptyId;
|
||||
|
||||
return node->LibId;
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER_BASE::GetUnitFor( const wxDataViewItem& aSelection ) const
|
||||
{
|
||||
auto node = ToNode( aSelection );
|
||||
return node ? node->Unit : 0;
|
||||
}
|
||||
|
||||
|
||||
CMP_TREE_NODE::TYPE CMP_TREE_MODEL_ADAPTER_BASE::GetTypeFor( const wxDataViewItem& aSelection ) const
|
||||
{
|
||||
auto node = ToNode( aSelection );
|
||||
return node ? node->Type : CMP_TREE_NODE::INVALID;
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER_BASE::GetComponentsCount() const
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for( auto& lib: m_tree.Children )
|
||||
{
|
||||
for( auto& alias: lib->Children )
|
||||
{
|
||||
(void) alias;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER_BASE::HasContainerColumns( wxDataViewItem const& aItem ) const
|
||||
{
|
||||
return IsContainer( aItem );
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER_BASE::IsContainer( wxDataViewItem const& aItem ) const
|
||||
{
|
||||
auto node = ToNode( aItem );
|
||||
return node ? node->Children.size() : true;
|
||||
}
|
||||
|
||||
|
||||
wxDataViewItem CMP_TREE_MODEL_ADAPTER_BASE::GetParent( wxDataViewItem const& aItem ) const
|
||||
{
|
||||
auto node = ToNode( aItem );
|
||||
auto parent = node ? node->Parent : nullptr;
|
||||
|
||||
// wxDataViewModel has no root node, but rather top-level elements have
|
||||
// an invalid (null) parent.
|
||||
if( !node || !parent || parent->Type == CMP_TREE_NODE::TYPE::ROOT )
|
||||
{
|
||||
return ToItem( nullptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToItem( parent );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int CMP_TREE_MODEL_ADAPTER_BASE::GetChildren(
|
||||
wxDataViewItem const& aItem,
|
||||
wxDataViewItemArray& aChildren ) const
|
||||
{
|
||||
auto node = ( aItem.IsOk() ? ToNode( aItem ) : &m_tree );
|
||||
|
||||
if( node->Type != CMP_TREE_NODE::TYPE::LIBID || m_show_units )
|
||||
return IntoArray( *node, aChildren );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CMP_TREE_MODEL_ADAPTER_BASE::GetValue(
|
||||
wxVariant& aVariant,
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol ) const
|
||||
{
|
||||
auto node = ToNode( aItem );
|
||||
wxASSERT( node );
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
case 0:
|
||||
aVariant = node->Name;
|
||||
break;
|
||||
case 1:
|
||||
aVariant = node->Desc;
|
||||
break;
|
||||
default:
|
||||
wxFAIL_MSG( "Invalid column ID!" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER_BASE::GetAttr(
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol,
|
||||
wxDataViewItemAttr& aAttr ) const
|
||||
{
|
||||
auto node = ToNode( aItem );
|
||||
wxASSERT( node );
|
||||
|
||||
if( node->Type != CMP_TREE_NODE::LIBID )
|
||||
{
|
||||
// Currently only aliases are formatted at all
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !node->IsRoot && aCol == 0 )
|
||||
{
|
||||
// Names of non-root aliases are italicized
|
||||
aAttr.SetItalic( true );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER_BASE::ColWidth( CMP_TREE_NODE& aTree, int aCol, wxString const& aHeading )
|
||||
{
|
||||
const int indent = aCol ? 0 : kDataViewIndent;
|
||||
|
||||
int min_width = WidthFor( aHeading, aCol );
|
||||
int width = std::max( aTree.Score > 0 ? WidthFor( aTree, aCol ) : 0, min_width );
|
||||
|
||||
if( aTree.Score > 0 )
|
||||
{
|
||||
for( auto& node: aTree.Children )
|
||||
{
|
||||
width = std::max( width, ColWidth( *node, aCol, aHeading ) + indent );
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER_BASE::WidthFor( CMP_TREE_NODE& aNode, int aCol )
|
||||
{
|
||||
auto result = m_width_cache.find( aNode.Name );
|
||||
|
||||
if( result != m_width_cache.end() )
|
||||
{
|
||||
return result->second[aCol];
|
||||
}
|
||||
else
|
||||
{
|
||||
int wname = m_widget->GetTextExtent( aNode.Name ).x + kDataViewIndent;
|
||||
int wdesc = m_widget->GetTextExtent( aNode.Desc ).x;
|
||||
|
||||
auto& val = m_width_cache[aNode.Name];
|
||||
val.push_back( wname );
|
||||
val.push_back( wdesc );
|
||||
return val[aCol];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CMP_TREE_MODEL_ADAPTER_BASE::WidthFor( wxString const& aHeading, int aCol )
|
||||
{
|
||||
static std::vector<int> widths;
|
||||
|
||||
for( int i = (int) widths.size(); i <= aCol; ++i )
|
||||
{
|
||||
widths.push_back( 0 );
|
||||
}
|
||||
|
||||
if( widths[aCol] == 0 )
|
||||
{
|
||||
widths[aCol] = m_widget->GetTextExtent( aHeading ).x;
|
||||
}
|
||||
|
||||
return widths[aCol];
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER_BASE::FindAndExpand(
|
||||
CMP_TREE_NODE& aNode,
|
||||
std::function<bool( CMP_TREE_NODE const* )> aFunc )
|
||||
{
|
||||
for( auto& node: aNode.Children )
|
||||
{
|
||||
if( aFunc( &*node ) )
|
||||
{
|
||||
auto item = wxDataViewItem(
|
||||
const_cast<void*>( static_cast<void const*>( &*node ) ) );
|
||||
m_widget->ExpandAncestors( item );
|
||||
m_widget->EnsureVisible( item );
|
||||
m_widget->Select( item );
|
||||
return true;
|
||||
}
|
||||
else if( FindAndExpand( *node, aFunc ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER_BASE::ShowResults()
|
||||
{
|
||||
return FindAndExpand( m_tree,
|
||||
[]( CMP_TREE_NODE const* n )
|
||||
{
|
||||
return n->Type == CMP_TREE_NODE::TYPE::LIBID && n->Score > 1;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER_BASE::ShowPreselect()
|
||||
{
|
||||
if( !m_preselect_lib_id.IsValid() )
|
||||
return false;
|
||||
|
||||
return FindAndExpand( m_tree,
|
||||
[&]( CMP_TREE_NODE const* n )
|
||||
{
|
||||
if( n->Type == CMP_TREE_NODE::LIBID && ( n->Children.empty() || !m_preselect_unit ) )
|
||||
return m_preselect_lib_id == n->LibId;
|
||||
else if( n->Type == CMP_TREE_NODE::UNIT && m_preselect_unit )
|
||||
return m_preselect_lib_id == n->Parent->LibId && m_preselect_unit == n->Unit;
|
||||
else
|
||||
return false;
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
bool CMP_TREE_MODEL_ADAPTER_BASE::ShowSingleLibrary()
|
||||
{
|
||||
return FindAndExpand( m_tree,
|
||||
[]( CMP_TREE_NODE const* n )
|
||||
{
|
||||
return n->Type == CMP_TREE_NODE::TYPE::LIBID &&
|
||||
n->Parent->Parent->Children.size() == 1;
|
||||
} );
|
||||
}
|
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
|
||||
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
|
||||
* Copyright (C) 2014-2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CMP_TREE_MODEL_ADAPTER_BASE_H
|
||||
#define _CMP_TREE_MODEL_ADAPTER_BASE_H
|
||||
|
||||
#include <lib_id.h>
|
||||
|
||||
#include <cmp_tree_model.h>
|
||||
|
||||
#include <wx/hashmap.h>
|
||||
#include <wx/dataview.h>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
|
||||
/**
|
||||
* Adapter class in the component selector Model-View-Adapter (mediated MVC)
|
||||
* architecture. The other pieces are in:
|
||||
*
|
||||
* - Model: CMP_TREE_NODE and descendants in eeschema/cmp_tree_model.h
|
||||
* - View:
|
||||
* - DIALOG_CHOOSE_COMPONENT in eeschema/dialogs/dialog_choose_component.h
|
||||
* - wxDataViewCtrl
|
||||
*
|
||||
* This adapter presents the interface specified by wxDataViewModel to the
|
||||
* wxDataViewCtrl:
|
||||
*
|
||||
* +---+ +------------------+
|
||||
* +---+ Generates | A | | VIEW |
|
||||
* | M | from libs | D | wxDataViewModel |------------------|
|
||||
* | O | <---------- | A | <------------------> | wxDataViewCtrl |
|
||||
* | D | | P | |------------------|
|
||||
* | E | <---------> | T | <------------------- | wxTextCtrl |
|
||||
* | L | UpdateScore | E | UpdateSearchString() |------------------|
|
||||
* +---+ | R | | |
|
||||
* +---+ +------------------+
|
||||
*
|
||||
* Because this adapter is a wxDataViewModel, it is reference-counted by
|
||||
* wxObject. To ensure this interface is used correctly, the constructor
|
||||
* is private; CMP_TREE_MODEL_ADAPTER should be created by the static
|
||||
* factory method CMP_TREE_MODEL_ADAPTER::Create().
|
||||
*
|
||||
* Quick summary of methods used to drive this class:
|
||||
*
|
||||
* - `SetFilter()` - set whether the view is restricted to power parts
|
||||
* - `ShowUnits()` - set whether units are displayed
|
||||
* - `SetPreselectNode()` - set a node to highlight when not searching
|
||||
* - `AddLibrary()` - populate the model with all aliases in a library
|
||||
* - `AddAliasList()` - populate the model with a specific list of aliases
|
||||
*
|
||||
* Quick summary of methods used by the View:
|
||||
*
|
||||
* - `UpdateSearchString()` - pass in the user's search text
|
||||
* - `AttachTo()` - pass in the wxDataViewCtrl
|
||||
* - `GetAliasFor()` - get the LIB_ALIAS* for a selected item
|
||||
* - `GetUnitFor()` - get the unit for a selected item
|
||||
* - `GetComponentsCount()` - count the aliases loaded
|
||||
*
|
||||
* Methods implemented as part of wxDataViewModel:
|
||||
*
|
||||
* - `HasContainerColumns()` - whether a parent item has more than one column
|
||||
* - `IsContainer()` - whether an item is a parent
|
||||
* - `GetParent()` - return the parent of an item, or invalid if root
|
||||
* - `GetChildren()` - get the children of an item
|
||||
* - `GetColumnCount()` - get the number of columns in the view
|
||||
* - `GetColumnType()` - get the data type shown in each column
|
||||
* - `GetValue()` - get the data shown in a cell
|
||||
* - `SetValue()` - edit the data in a cell (does nothing)
|
||||
* - `GetAttr()` - get any per-item formatting
|
||||
* - `Compare()` - compare two rows, for sorting
|
||||
* - `HasDefaultCompare()` - whether sorted by default
|
||||
*/
|
||||
class CMP_TREE_MODEL_ADAPTER_BASE: public wxDataViewModel
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Reference-counting container for a pointer to CMP_TREE_MODEL_ADAPTER_BASE.
|
||||
*/
|
||||
typedef wxObjectDataPtr<CMP_TREE_MODEL_ADAPTER_BASE> PTR;
|
||||
|
||||
/**
|
||||
* Destructor. Do NOT delete this class manually; it is reference-counted
|
||||
* by wxObject.
|
||||
*/
|
||||
~CMP_TREE_MODEL_ADAPTER_BASE();
|
||||
|
||||
/**
|
||||
* This enum allows a selective filtering of components to list
|
||||
*/
|
||||
enum CMP_FILTER_TYPE
|
||||
{
|
||||
CMP_FILTER_NONE, ///< no filtering
|
||||
CMP_FILTER_POWER, ///< list components flagged PWR
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the component filter type. Must be set before adding libraries
|
||||
*
|
||||
* @param aFilter if CMP_FILTER_POWER, only power parts are loaded
|
||||
*/
|
||||
void SetFilter( CMP_FILTER_TYPE aFilter );
|
||||
|
||||
/**
|
||||
* Return the active filter.
|
||||
*/
|
||||
CMP_FILTER_TYPE GetFilter() const { return m_filter; }
|
||||
|
||||
/**
|
||||
* Whether or not to show units. May be set at any time; updates at the next
|
||||
* UpdateSearchString()
|
||||
*
|
||||
* @param aShow if true, units are displayed
|
||||
*/
|
||||
void ShowUnits( bool aShow );
|
||||
|
||||
/**
|
||||
* Set the component name to be selected if there are no search results.
|
||||
* May be set at any time; updates at the next UpdateSearchString().
|
||||
*
|
||||
* @param aLibId symbol #LIB_ID to be selected
|
||||
* @param aUnit unit to be selected, if > 0 (0 selects the alias itself)
|
||||
*/
|
||||
void SetPreselectNode( LIB_ID const& aLibId, int aUnit );
|
||||
|
||||
/**
|
||||
* Add all the components and their aliases in this library. To be called
|
||||
* in the setup phase.
|
||||
*
|
||||
* @param aLibNickname reference to a symbol library nickname
|
||||
*/
|
||||
virtual void AddLibrary( wxString const& aLibNickname ) = 0;
|
||||
|
||||
/**
|
||||
* Add all the libraries in a SYMBOL_LIB_TABLE to the model,
|
||||
* displaying a progress dialog attached to the parent frame
|
||||
*
|
||||
* @param aNicknames is the list of library nicknames
|
||||
* @param aParent is the parent window to display the progress dialog
|
||||
*/
|
||||
void AddLibrariesWithProgress( const std::vector<wxString>& aNicknames,
|
||||
wxWindow* aParent );
|
||||
|
||||
/**
|
||||
* Add the given list of components, by name. To be called in the setup
|
||||
* phase.
|
||||
*
|
||||
* @param aNodeName the parent node the components will appear under
|
||||
* @param aAliasNameList list of alias names
|
||||
*/
|
||||
virtual void AddAliasList(
|
||||
wxString const& aNodeName,
|
||||
wxArrayString const& aAliasNameList ) = 0;
|
||||
|
||||
/**
|
||||
* Add the given list of components by alias. To be called in the setup
|
||||
* phase.
|
||||
*
|
||||
* @param aNodeName the parent node the components will appear under
|
||||
* @param aAliasList list of aliases
|
||||
*/
|
||||
void AddAliasList(
|
||||
wxString const& aNodeName,
|
||||
std::vector<LIB_ALIAS*> const& aAliasList );
|
||||
|
||||
/**
|
||||
* Set the search string provided by the user.
|
||||
*
|
||||
* @param aSearch full, unprocessed search text
|
||||
*/
|
||||
void UpdateSearchString( wxString const& aSearch );
|
||||
|
||||
/**
|
||||
* Attach to a wxDataViewCtrl and initialize it. This will set up columns
|
||||
* and associate the model via the adapter.
|
||||
*
|
||||
* @param aDataViewCtrl the view component in the dialog
|
||||
*/
|
||||
void AttachTo( wxDataViewCtrl* aDataViewCtrl );
|
||||
|
||||
/**
|
||||
* Return the alias for the given item.
|
||||
*
|
||||
* @param aSelection item from the wxDataViewCtrl
|
||||
* (see wxDataViewCtrl::GetSelection())
|
||||
*
|
||||
* @return alias, or nullptr if none is selected
|
||||
*/
|
||||
LIB_ID GetAliasFor( const wxDataViewItem& aSelection ) const;
|
||||
|
||||
/**
|
||||
* Return the unit for the given item.
|
||||
*
|
||||
* @param aSelection item from the wxDataViewCtrl
|
||||
* (see wxDataViewCtrl::GetSelection())
|
||||
*
|
||||
* @return Unit, or zero if the alias itself is selected. Return valid is
|
||||
* invalid if GetAliasFor() returns nullptr.
|
||||
*/
|
||||
int GetUnitFor( const wxDataViewItem& aSelection ) const;
|
||||
|
||||
/**
|
||||
* Return node type for the given item.
|
||||
*
|
||||
* @param aSelection item from the wxDataViewCtrl
|
||||
* (see wxDataViewCtrl::GetSelection())
|
||||
*
|
||||
* @return Type of the selected node, might be INVALID.
|
||||
*/
|
||||
CMP_TREE_NODE::TYPE GetTypeFor( const wxDataViewItem& aSelection ) const;
|
||||
|
||||
/**
|
||||
* Return the number of components loaded in the tree.
|
||||
*/
|
||||
int GetComponentsCount() const;
|
||||
|
||||
protected:
|
||||
static wxDataViewItem ToItem( CMP_TREE_NODE const* aNode );
|
||||
static CMP_TREE_NODE const* ToNode( wxDataViewItem aItem );
|
||||
static unsigned int IntoArray( CMP_TREE_NODE const& aNode, wxDataViewItemArray& aChildren );
|
||||
|
||||
CMP_TREE_NODE_ROOT m_tree;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
CMP_TREE_MODEL_ADAPTER_BASE();
|
||||
|
||||
/**
|
||||
* Check whether a container has columns too
|
||||
*/
|
||||
virtual bool HasContainerColumns( wxDataViewItem const& aItem ) const override;
|
||||
|
||||
/**
|
||||
* Check whether an item can have children.
|
||||
*/
|
||||
virtual bool IsContainer( wxDataViewItem const& aItem ) const override;
|
||||
|
||||
/**
|
||||
* Get the parent of an item.
|
||||
*
|
||||
* @param aItem item to get the parent of
|
||||
* @return parent of aItem, or an invalid wxDataViewItem if parent is root
|
||||
*/
|
||||
virtual wxDataViewItem GetParent( wxDataViewItem const& aItem ) const override;
|
||||
|
||||
/**
|
||||
* Populate a list of all the children of an item
|
||||
*
|
||||
* @return number of children
|
||||
*/
|
||||
virtual unsigned int GetChildren(
|
||||
wxDataViewItem const& aItem,
|
||||
wxDataViewItemArray& aChildren ) const override;
|
||||
|
||||
/**
|
||||
* Return the number of columns in the model
|
||||
*/
|
||||
virtual unsigned int GetColumnCount() const override { return 2; }
|
||||
|
||||
/**
|
||||
* Return the type of data stored in the column
|
||||
*
|
||||
* @return type of data as indicated by wxVariant::GetType()
|
||||
*/
|
||||
virtual wxString GetColumnType( unsigned int aCol ) const override { return "string"; }
|
||||
|
||||
/**
|
||||
* Get the value of an item.
|
||||
*
|
||||
* @param aVariant wxVariant to receive the data
|
||||
* @param aItem item whose data will be placed into aVariant
|
||||
* @param aCol column number of the data
|
||||
*/
|
||||
virtual void GetValue(
|
||||
wxVariant& aVariant,
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol ) const override;
|
||||
|
||||
/**
|
||||
* Set the value of an item. Does nothing - this model doesn't support
|
||||
* editing.
|
||||
*/
|
||||
virtual bool SetValue(
|
||||
wxVariant const& aVariant,
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol ) override { return false; }
|
||||
|
||||
/**
|
||||
* Get any formatting for an item.
|
||||
*
|
||||
* @param aItem item to get formatting for
|
||||
* @param aCol column number of interest
|
||||
* @param aAttr receiver for attributes
|
||||
* @return true iff the item has non-default attributes
|
||||
*/
|
||||
virtual bool GetAttr(
|
||||
wxDataViewItem const& aItem,
|
||||
unsigned int aCol,
|
||||
wxDataViewItemAttr& aAttr ) const override;
|
||||
|
||||
private:
|
||||
CMP_FILTER_TYPE m_filter;
|
||||
bool m_show_units;
|
||||
LIB_ID m_preselect_lib_id;
|
||||
int m_preselect_unit;
|
||||
|
||||
wxDataViewColumn* m_col_part;
|
||||
wxDataViewColumn* m_col_desc;
|
||||
wxDataViewCtrl* m_widget;
|
||||
|
||||
WX_DECLARE_STRING_HASH_MAP( std::vector<int>, WIDTH_CACHE );
|
||||
|
||||
static WIDTH_CACHE m_width_cache;
|
||||
|
||||
/**
|
||||
* Compute the width required for the given column of a node and its
|
||||
* children.
|
||||
*
|
||||
* @param aTree - root node of the tree
|
||||
* @param aCol - column number
|
||||
* @param aHeading - heading text, to set the minimum width
|
||||
*/
|
||||
int ColWidth( CMP_TREE_NODE& aTree, int aCol, wxString const& aHeading );
|
||||
|
||||
/**
|
||||
* Return the width required to display a single row's aCol text.
|
||||
* This is cached for efficiency as it's very slow on some platforms
|
||||
* (*cough* macOS)
|
||||
*/
|
||||
int WidthFor( CMP_TREE_NODE& aNode, int aCol );
|
||||
|
||||
/**
|
||||
* Return the width required to display a column's heading. This is
|
||||
* cached by column number for the same reason as the width per cell.
|
||||
*/
|
||||
int WidthFor( wxString const& aHeading, int aCol );
|
||||
|
||||
/**
|
||||
* Find any results worth highlighting and expand them, according to given
|
||||
* criteria (f(CMP_TREE_NODE const*) -> bool)
|
||||
*
|
||||
* @return whether a node was expanded
|
||||
*/
|
||||
bool FindAndExpand(
|
||||
CMP_TREE_NODE& aNode,
|
||||
std::function<bool( CMP_TREE_NODE const* )> aFunc );
|
||||
|
||||
/**
|
||||
* Find and expand successful search results
|
||||
*/
|
||||
bool ShowResults();
|
||||
|
||||
/**
|
||||
* Find and expand preselected node
|
||||
*/
|
||||
bool ShowPreselect();
|
||||
|
||||
/**
|
||||
* Find and expand a library if there is only one
|
||||
*/
|
||||
bool ShowSingleLibrary();
|
||||
};
|
||||
|
||||
#endif // _CMP_TREE_MODEL_ADAPTER_BASE_H
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
|
||||
COMPONENT_TREE::COMPONENT_TREE( wxWindow* aParent, SYMBOL_LIB_TABLE* aSymLibTable,
|
||||
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter, WIDGETS aWidgets )
|
||||
CMP_TREE_MODEL_ADAPTER_BASE::PTR& aAdapter, WIDGETS aWidgets )
|
||||
: wxPanel( aParent ),
|
||||
m_sym_lib_table( aSymLibTable ),
|
||||
m_adapter( aAdapter ),
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
enum WIDGETS { NONE = 0x00, SEARCH = 0x01, DETAILS = 0x02, ALL = 0xFF };
|
||||
|
||||
COMPONENT_TREE( wxWindow* aParent, SYMBOL_LIB_TABLE* aSymLibTable,
|
||||
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter, WIDGETS aWidgets = ALL );
|
||||
CMP_TREE_MODEL_ADAPTER_BASE::PTR& aAdapter, WIDGETS aWidgets = ALL );
|
||||
|
||||
/**
|
||||
* For multi-unit components, if the user selects the component itself
|
||||
|
|
Loading…
Reference in New Issue