Convert component chooser dialog over to use symbol library table.

Change all of the component tree helper objects to use LIB_IDs instead of
LIB_ALIAS pointers.  LIB_ALIAS pointers are dangerous to use because they
can be deleted in the symbol library editor while the component chooser
dialog has copies of them.  With LIB_IDs, the LIB_ALIAS pointer is found
on demand and can be guaranteed to be valid.

Update the chooser dialog to load the symbol library table instead of the
libraries defined in the project file and return a LIB_ID instead of a
LIB_ALIAS pointer.

Modify SCH_BASE_FRAME::SelectComponentFromLibrary() to handle the LIB_IDs
returned from the component chooser dialog.
This commit is contained in:
Wayne Stambaugh 2017-09-15 10:17:44 -04:00
parent 81e8d8fd89
commit 329fc18732
14 changed files with 364 additions and 209 deletions

View File

@ -107,7 +107,6 @@ CMP_TREE_NODE::CMP_TREE_NODE()
Type( INVALID ),
IntrinsicRank( 0 ),
Score( kLowestDefaultScore ),
Alias( nullptr ),
Unit( 0 )
{}
@ -118,7 +117,7 @@ CMP_TREE_NODE_UNIT::CMP_TREE_NODE_UNIT( CMP_TREE_NODE* aParent, int aUnit )
Type = UNIT;
Unit = aUnit;
Alias = aParent->Alias;
LibId = aParent->LibId;
Name = _( "Unit" ) + " " + LIB_PART::SubReference( aUnit, false );
Desc = wxEmptyString;
@ -128,13 +127,17 @@ CMP_TREE_NODE_UNIT::CMP_TREE_NODE_UNIT( CMP_TREE_NODE* aParent, int aUnit )
}
CMP_TREE_NODE_ALIAS::CMP_TREE_NODE_ALIAS( CMP_TREE_NODE* aParent, LIB_ALIAS* aAlias )
CMP_TREE_NODE_LIB_ID::CMP_TREE_NODE_LIB_ID( CMP_TREE_NODE* aParent, LIB_ALIAS* aAlias )
{
Parent = aParent;
Type = ALIAS;
Name = aAlias->GetName();
Desc = aAlias->GetDescription();
Alias = aAlias;
// Parent node is the library nickname so set the LIB_ID library nickname.
LibId.SetLibNickname( aParent->Name );
LibId.SetLibItemName( aAlias->GetName() );
IsRoot = aAlias->IsRoot();
// Pre-normalized strings for fast case-insensitive matching
// Search text spaces out keywords and description to penalize description
@ -170,7 +173,7 @@ CMP_TREE_NODE_ALIAS::CMP_TREE_NODE_ALIAS( CMP_TREE_NODE* aParent, LIB_ALIAS* aAl
}
CMP_TREE_NODE_UNIT& CMP_TREE_NODE_ALIAS::AddUnit( int aUnit )
CMP_TREE_NODE_UNIT& CMP_TREE_NODE_LIB_ID::AddUnit( int aUnit )
{
CMP_TREE_NODE_UNIT* unit = new CMP_TREE_NODE_UNIT( this, aUnit );
Children.push_back( std::unique_ptr<CMP_TREE_NODE>( unit ) );
@ -178,7 +181,7 @@ CMP_TREE_NODE_UNIT& CMP_TREE_NODE_ALIAS::AddUnit( int aUnit )
}
void CMP_TREE_NODE_ALIAS::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
void CMP_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
{
if( Score <= 0 )
return; // Leaf nodes without scores are out of the game.
@ -235,9 +238,9 @@ CMP_TREE_NODE_LIB::CMP_TREE_NODE_LIB( CMP_TREE_NODE* aParent, wxString const& aN
}
CMP_TREE_NODE_ALIAS& CMP_TREE_NODE_LIB::AddAlias( LIB_ALIAS* aAlias )
CMP_TREE_NODE_LIB_ID& CMP_TREE_NODE_LIB::AddAlias( LIB_ALIAS* aAlias )
{
CMP_TREE_NODE_ALIAS* alias = new CMP_TREE_NODE_ALIAS( this, aAlias );
CMP_TREE_NODE_LIB_ID* alias = new CMP_TREE_NODE_LIB_ID( this, aAlias );
Children.push_back( std::unique_ptr<CMP_TREE_NODE>( alias ) );
return *alias;
}

View File

@ -25,6 +25,7 @@
#include <vector>
#include <memory>
#include <wx/string.h>
#include <lib_id.h>
class EDA_COMBINED_MATCHER;
@ -70,7 +71,7 @@ class LIB_ALIAS;
* - `Desc` - description of the alias, to be displayed
* - `MatchName` - Name, normalized to lowercase for matching
* - `SearchText` - normalized composite of keywords and description
* - `Alias` - the LIB_ALIAS* this alias or unit is from, or nullptr
* - `LibId` - the #LIB_ID this alias or unit is from, or not valid
* - `Unit` - the unit number, or zero for non-units
*/
class CMP_TREE_NODE {
@ -98,16 +99,15 @@ public:
wxString MatchName; ///< Normalized name for matching
wxString SearchText; ///< Descriptive text to search
LIB_ALIAS* Alias; ///< Actual LIB_ALIAS*, or null
LIB_ID LibId; ///< LIB_ID determined by the parent library nickname and alias name.
int Unit; ///< Actual unit, or zero
bool IsRoot; ///< Indicates if the symbol is a root symbol instead of an alias.
/**
* Update the score for this part. This is accumulative - it will be
* called once per search term.
*
* @param aMatcher an EDA_COMBINED_MATCHER initialized with the search
* term
* @param aMatcher an EDA_COMBINED_MATCHER initialized with the search term
*/
virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher ) = 0;
@ -173,29 +173,32 @@ public:
/**
* Node type: alias.
* Node type: #LIB_ID.
*/
class CMP_TREE_NODE_ALIAS: public CMP_TREE_NODE
class CMP_TREE_NODE_LIB_ID: public CMP_TREE_NODE
{
public:
/**
* The addresses of CMP_TREE_NODEs are used as unique IDs for the
* wxDataViewModel, so don't let them be copied around.
*/
CMP_TREE_NODE_ALIAS( CMP_TREE_NODE_ALIAS const& _ ) = delete;
void operator=( CMP_TREE_NODE_ALIAS const& _ ) = delete;
CMP_TREE_NODE_LIB_ID( CMP_TREE_NODE_LIB_ID const& _ ) = delete;
void operator=( CMP_TREE_NODE_LIB_ID const& _ ) = delete;
/**
* Construct an alias node.
* Construct a #LIB_ID node.
*
* All fields will be populated from the LIB_ALIAS, including children
* (unit nodes will be generated automatically).
* (unit nodes will be generated automatically). This does not keep
* the pointer to the #LIB_ALIAS object because at any time, a #LIB_ALIAS
* can be remove from a libray which will result in an invalid pointer.
* The alias must be resolved at the time of use. Anything else is a bug.
*
* @param aParent parent node, should be a CMP_TREE_NODE_LIB
* @param aAlias LIB_ALIAS to populate the node
* @param aAlias LIB_ALIAS to populate the node.
*/
CMP_TREE_NODE_ALIAS( CMP_TREE_NODE* aParent, LIB_ALIAS* aAlias );
CMP_TREE_NODE_LIB_ID( CMP_TREE_NODE* aParent, LIB_ALIAS* aAlias );
/**
@ -240,7 +243,7 @@ public:
*
* @param aAlias LIB_ALIAS to provide data
*/
CMP_TREE_NODE_ALIAS& AddAlias( LIB_ALIAS* aAlias );
CMP_TREE_NODE_LIB_ID& AddAlias( LIB_ALIAS* aAlias );
virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher ) override;
};

View File

@ -21,9 +21,9 @@
#include <cmp_tree_model_adapter.h>
#include <class_library.h>
#include <eda_pattern_match.h>
#include <wx/tokenzr.h>
#include <symbol_lib_table.h>
CMP_TREE_MODEL_ADAPTER::WIDTH_CACHE CMP_TREE_MODEL_ADAPTER::m_width_cache;
@ -70,7 +70,7 @@ static unsigned int IntoArray( CMP_TREE_NODE const& aNode, wxDataViewItemArray&
}
CMP_TREE_MODEL_ADAPTER::PTR CMP_TREE_MODEL_ADAPTER::Create( PART_LIBS* aLibs )
CMP_TREE_MODEL_ADAPTER::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 );
@ -78,7 +78,7 @@ CMP_TREE_MODEL_ADAPTER::PTR CMP_TREE_MODEL_ADAPTER::Create( PART_LIBS* aLibs )
}
CMP_TREE_MODEL_ADAPTER::CMP_TREE_MODEL_ADAPTER( PART_LIBS* aLibs )
CMP_TREE_MODEL_ADAPTER::CMP_TREE_MODEL_ADAPTER( SYMBOL_LIB_TABLE* aLibs )
:m_filter( CMP_FILTER_NONE ),
m_show_units( true ),
m_libs( aLibs ),
@ -105,60 +105,68 @@ void CMP_TREE_MODEL_ADAPTER::ShowUnits( bool aShow )
}
void CMP_TREE_MODEL_ADAPTER::SetPreselectNode( wxString const& aName, int aUnit )
void CMP_TREE_MODEL_ADAPTER::SetPreselectNode( LIB_ID const& aLibId, int aUnit )
{
m_preselect_name = aName;
m_preselect_lib_id = aLibId;
m_preselect_unit = aUnit;
}
void CMP_TREE_MODEL_ADAPTER::AddLibrary( PART_LIB& aLib )
void CMP_TREE_MODEL_ADAPTER::AddLibrary( wxString const& aLibNickname )
{
if( m_filter == CMP_FILTER_POWER )
bool onlyPowerSymbols = ( m_filter == CMP_FILTER_POWER );
wxArrayString aliases;
try
{
wxArrayString all_aliases;
aLib.GetEntryTypePowerNames( all_aliases );
AddAliasList( aLib.GetName(), all_aliases, &aLib );
m_libs->EnumerateSymbolLib( aLibNickname, aliases, onlyPowerSymbols );
}
else
catch( const IO_ERROR& ioe )
{
std::vector<LIB_ALIAS*> all_aliases;
aLib.GetAliases( all_aliases );
AddAliasList( aLib.GetName(), all_aliases, &aLib );
wxLogError( wxString::Format( _( "Error occurred loading symbol library %s."
"\n\n%s" ), aLibNickname, ioe.What() ) );
return;
}
AddAliasList( aLibNickname, aliases );
m_tree.AssignIntrinsicRanks();
}
void CMP_TREE_MODEL_ADAPTER::AddAliasList(
wxString const& aNodeName,
wxArrayString const& aAliasNameList,
PART_LIB* aOptionalLib )
wxArrayString const& aAliasNameList )
{
std::vector<LIB_ALIAS*> alias_list;
for( const wxString& name: aAliasNameList )
{
LIB_ALIAS* a;
LIB_ALIAS* a = nullptr;
if( aOptionalLib )
a = aOptionalLib->FindAlias( name );
else
a = m_libs->FindLibraryAlias( LIB_ID( wxEmptyString, name ), wxEmptyString );
try
{
a = m_libs->LoadSymbol( aNodeName, name );
}
catch( const IO_ERROR& ioe )
{
wxLogError( wxString::Format( _( "Error occurred loading symbol %s from library %s."
"\n\n%s" ), name, aNodeName, ioe.What() ) );
continue;
}
if( a )
alias_list.push_back( a );
}
AddAliasList( aNodeName, alias_list, aOptionalLib );
AddAliasList( aNodeName, alias_list );
}
void CMP_TREE_MODEL_ADAPTER::AddAliasList(
wxString const& aNodeName,
std::vector<LIB_ALIAS*> const& aAliasList,
PART_LIB* aOptionalLib )
std::vector<LIB_ALIAS*> const& aAliasList )
{
auto& lib_node = m_tree.AddLib( aNodeName );
@ -213,10 +221,16 @@ void CMP_TREE_MODEL_ADAPTER::AttachTo( wxDataViewCtrl* aDataViewCtrl )
}
LIB_ALIAS* CMP_TREE_MODEL_ADAPTER::GetAliasFor( wxDataViewItem aSelection ) const
LIB_ID CMP_TREE_MODEL_ADAPTER::GetAliasFor( wxDataViewItem aSelection ) const
{
auto node = ToNode( aSelection );
return node ? node->Alias : nullptr;
LIB_ID emptyId;
if( !node )
return emptyId;
return node->LibId;
}
@ -324,7 +338,7 @@ bool CMP_TREE_MODEL_ADAPTER::GetAttr(
return false;
}
if( node->Alias && !node->Alias->IsRoot() && aCol == 0 )
if( !node->IsRoot && aCol == 0 )
{
// Names of non-root aliases are italicized
aAttr.SetItalic( true );
@ -432,16 +446,16 @@ bool CMP_TREE_MODEL_ADAPTER::ShowResults()
bool CMP_TREE_MODEL_ADAPTER::ShowPreselect()
{
if( m_preselect_name == wxEmptyString )
if( !m_preselect_lib_id.IsValid() )
return false;
return FindAndExpand( m_tree,
[&]( CMP_TREE_NODE const* n )
{
if( n->Type == CMP_TREE_NODE::ALIAS && ( n->Children.empty() || !m_preselect_unit ) )
return m_preselect_name == n->Name;
return m_preselect_lib_id == n->LibId;
else if( n->Type == CMP_TREE_NODE::UNIT && m_preselect_unit )
return m_preselect_name == n->Parent->Name && m_preselect_unit == n->Unit;
return m_preselect_lib_id == n->Parent->LibId && m_preselect_unit == n->Unit;
else
return false;
} );

View File

@ -22,6 +22,8 @@
#ifndef _CMP_TREE_MODEL_ADAPTER_H
#define _CMP_TREE_MODEL_ADAPTER_H
#include <lib_id.h>
#include <cmp_tree_model.h>
#include <wx/hashmap.h>
@ -29,9 +31,7 @@
#include <vector>
#include <functional>
class LIB_ALIAS;
class PART_LIB;
class PART_LIBS;
class SYMBOL_LIB_TABLE;
/**
@ -112,7 +112,7 @@ public:
*
* @param aLibs library set from which parts will be loaded
*/
static PTR Create( PART_LIBS* aLibs );
static PTR Create( SYMBOL_LIB_TABLE* aLibs );
/**
* This enum allows a selective filtering of components to list
@ -142,18 +142,18 @@ public:
* 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 aName component name to be selected
* @param aLibId symbol #LIB_ID to be selected
* @param aUnit unit to be selected, if > 0 (0 selects the alias itself)
*/
void SetPreselectNode( wxString const& aName, int aUnit );
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 aLib reference to a library
* @param aLibNickname reference to a symbol library nickname
*/
void AddLibrary( PART_LIB& aLib );
void AddLibrary( wxString const& aLibNickname );
/**
* Add the given list of components, by name. To be called in the setup
@ -161,12 +161,10 @@ public:
*
* @param aNodeName the parent node the components will appear under
* @param aAliasNameList list of alias names
* @param aOptionalLib library to look up names in (null = global)
*/
void AddAliasList(
wxString const& aNodeName,
wxArrayString const& aAliasNameList,
PART_LIB* aOptionalLib = nullptr );
wxArrayString const& aAliasNameList );
/**
* Add the given list of components by alias. To be called in the setup
@ -174,12 +172,10 @@ public:
*
* @param aNodeName the parent node the components will appear under
* @param aAliasList list of aliases
* @param aOptionalLib library to look up names in (null = global)
*/
void AddAliasList(
wxString const& aNodeName,
std::vector<LIB_ALIAS*> const& aAliasList,
PART_LIB* aOptionalLib = nullptr );
std::vector<LIB_ALIAS*> const& aAliasList );
/**
* Set the search string provided by the user.
@ -204,7 +200,7 @@ public:
*
* @return alias, or nullptr if none is selected
*/
LIB_ALIAS* GetAliasFor( wxDataViewItem aSelection ) const;
LIB_ID GetAliasFor( wxDataViewItem aSelection ) const;
/**
* Return the unit for the given item.
@ -227,7 +223,7 @@ protected:
/**
* Constructor; takes a set of libraries to be included in the search.
*/
CMP_TREE_MODEL_ADAPTER( PART_LIBS* aLibs );
CMP_TREE_MODEL_ADAPTER( SYMBOL_LIB_TABLE* aLibs );
/**
* Check whether a container has columns too
@ -305,8 +301,8 @@ protected:
private:
CMP_FILTER_TYPE m_filter;
bool m_show_units;
PART_LIBS* m_libs;
wxString m_preselect_name;
SYMBOL_LIB_TABLE* m_libs;
LIB_ID m_preselect_lib_id;
int m_preselect_unit;
CMP_TREE_NODE_ROOT m_tree;

View File

@ -40,6 +40,7 @@
#include <class_library.h>
#include <sch_base_frame.h>
#include <template_fieldnames.h>
#include <symbol_lib_table.h>
#include <widgets/component_tree.h>
#include <widgets/footprint_preview_widget.h>
#include <widgets/footprint_select_widget.h>
@ -63,7 +64,7 @@ DIALOG_CHOOSE_COMPONENT::DIALOG_CHOOSE_COMPONENT( SCH_BASE_FRAME* aParent, const
auto splitter = new wxSplitterWindow(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_LIVE_UPDATE );
m_tree = new COMPONENT_TREE( splitter, aAdapter );
m_tree = new COMPONENT_TREE( splitter, Prj().SchSymbolLibTable(), aAdapter );
auto right_panel = ConstructRightPanel( splitter );
auto buttons = new wxStdDialogButtonSizer();
m_dbl_click_timer = new wxTimer( this );
@ -153,9 +154,9 @@ void DIALOG_CHOOSE_COMPONENT::OnInitDialog( wxInitDialogEvent& aEvent )
}
LIB_ALIAS* DIALOG_CHOOSE_COMPONENT::GetSelectedAlias( int* aUnit ) const
LIB_ID DIALOG_CHOOSE_COMPONENT::GetSelectedLibId( int* aUnit ) const
{
return m_tree->GetSelectedAlias( aUnit );
return m_tree->GetSelectedLibId( aUnit );
}
@ -187,12 +188,32 @@ void DIALOG_CHOOSE_COMPONENT::OnSchViewDClick( wxMouseEvent& aEvent )
}
void DIALOG_CHOOSE_COMPONENT::ShowFootprintFor( LIB_ALIAS* aAlias )
void DIALOG_CHOOSE_COMPONENT::ShowFootprintFor( LIB_ID const& aLibId )
{
if( !m_fp_view_ctrl->IsInitialized() )
return;
LIB_FIELD* fp_field = aAlias->GetPart()->GetField( FOOTPRINT );
LIB_ALIAS* alias = nullptr;
try
{
alias = Prj().SchSymbolLibTable()->LoadSymbol( aLibId );
}
catch( const IO_ERROR& ioe )
{
wxLogError( wxString::Format( _( "Error occurred loading symbol %s from library %s."
"\n\n%s" ),
aLibId.GetLibItemName().wx_str(),
aLibId.GetLibNickname().wx_str(),
ioe.What() ) );
}
if( alias == nullptr )
{
return;
}
LIB_FIELD* fp_field = alias->GetPart()->GetField( FOOTPRINT );
wxString fp_name = fp_field ? fp_field->GetFullText() : wxString( "" );
ShowFootprint( fp_name );
@ -207,32 +228,54 @@ void DIALOG_CHOOSE_COMPONENT::ShowFootprint( wxString const& aName )
}
else
{
LIB_ID lib_id( aName );
LIB_ID lib_id;
if( lib_id.Parse( aName ) == -1 && lib_id.IsValid() )
{
m_fp_view_ctrl->ClearStatus();
m_fp_view_ctrl->CacheFootprint( lib_id );
m_fp_view_ctrl->DisplayFootprint( lib_id );
}
else
{
m_fp_view_ctrl->SetStatusText( _( "Invalid footprint specified" ) );
}
}
}
void DIALOG_CHOOSE_COMPONENT::PopulateFootprintSelector( LIB_ALIAS* aAlias )
void DIALOG_CHOOSE_COMPONENT::PopulateFootprintSelector( LIB_ID const& aLibId )
{
if( !m_fp_sel_ctrl )
return;
m_fp_sel_ctrl->ClearFilters();
if( aAlias )
LIB_ALIAS* alias = nullptr;
try
{
alias = Prj().SchSymbolLibTable()->LoadSymbol( aLibId );
}
catch( const IO_ERROR& ioe )
{
wxLogError( wxString::Format( _( "Error occurred loading symbol %s from library %s."
"\n\n%s" ),
aLibId.GetLibItemName().wx_str(),
aLibId.GetLibNickname().wx_str(),
ioe.What() ) );
}
if( alias != nullptr )
{
LIB_PINS temp_pins;
LIB_FIELD* fp_field = aAlias->GetPart()->GetField( FOOTPRINT );
LIB_FIELD* fp_field = alias->GetPart()->GetField( FOOTPRINT );
wxString fp_name = fp_field ? fp_field->GetFullText() : wxString( "" );
aAlias->GetPart()->GetPins( temp_pins );
alias->GetPart()->GetPins( temp_pins );
m_fp_sel_ctrl->FilterByPinCount( temp_pins.size() );
m_fp_sel_ctrl->FilterByFootprintFilters( aAlias->GetPart()->GetFootPrints(), true );
m_fp_sel_ctrl->FilterByFootprintFilters( alias->GetPart()->GetFootPrints(), true );
m_fp_sel_ctrl->SetDefaultFootprint( fp_name );
m_fp_sel_ctrl->UpdateList();
m_fp_sel_ctrl->Enable();
@ -248,7 +291,29 @@ void DIALOG_CHOOSE_COMPONENT::PopulateFootprintSelector( LIB_ALIAS* aAlias )
void DIALOG_CHOOSE_COMPONENT::OnSchViewPaint( wxPaintEvent& aEvent )
{
int unit = 0;
LIB_ALIAS* alias = m_tree->GetSelectedAlias( &unit );
LIB_ID id = m_tree->GetSelectedLibId( &unit );
if( !id.IsValid() )
return;
LIB_ALIAS* alias = nullptr;
try
{
alias = Prj().SchSymbolLibTable()->LoadSymbol( id );
}
catch( const IO_ERROR& ioe )
{
wxLogError( wxString::Format( _( "Error occurred loading symbol %s from library %s."
"\n\n%s" ),
id.GetLibItemName().wx_str(),
id.GetLibNickname().wx_str(),
ioe.What() ) );
}
if( alias == nullptr )
return;
LIB_PART* part = alias ? alias->GetPart() : nullptr;
// Don't draw anything (not even the background) if we don't have
@ -292,28 +357,29 @@ void DIALOG_CHOOSE_COMPONENT::OnFootprintSelected( wxCommandEvent& aEvent )
void DIALOG_CHOOSE_COMPONENT::OnComponentPreselected( wxCommandEvent& aEvent )
{
int unit = 0;
LIB_ALIAS* alias = m_tree->GetSelectedAlias( &unit );
LIB_ID id = m_tree->GetSelectedLibId( &unit );
m_sch_view_ctrl->Refresh();
if( alias )
if( id.IsValid() )
{
ShowFootprintFor( alias );
PopulateFootprintSelector( alias );
ShowFootprintFor( id );
PopulateFootprintSelector( id );
}
else
{
if( m_fp_view_ctrl->IsInitialized() )
m_fp_view_ctrl->SetStatusText( wxEmptyString );
PopulateFootprintSelector( nullptr );
PopulateFootprintSelector( id );
}
}
void DIALOG_CHOOSE_COMPONENT::OnComponentSelected( wxCommandEvent& aEvent )
{
if( m_tree->GetSelectedAlias() )
if( m_tree->GetSelectedLibId().IsValid() )
{
// Got a selection. We can't just end the modal dialog here, because
// wx leaks some events back to the parent window (in particular, the

View File

@ -60,14 +60,18 @@ class SCH_BASE_FRAME;
* for thorough documentation. A simple example usage follows:
*
* // Create the adapter class
* auto adapter( CMP_TREE_MODEL_ADAPTER::Create( Prj().SchLibs() ) );
* auto adapter( CMP_TREE_MODEL_ADAPTER::Create( Prj().SchSymbolLibTable() ) );
*
* // Perform any configuration of adapter properties here
* adapter->SetPreselectNode( "TL072", 2 );
* adapter->SetPreselectNode( "LIB_NICKNAME", "SYMBO_NAME", 2 );
*
* // Initialize model from PART_LIBs
* for( PART_LIB& lib: *libs )
* adapter->AddLibrary( lib );
* // Initialize model from #SYMBOL_LIB_TABLE
* libNicknames = libs->GetLogicalLibs();
*
* for( auto nickname : libNicknames )
* {
* adapter->AddLibrary( nickname );
* }
*
* // Create and display dialog
* DIALOG_CHOOSE_COMPONENT dlg( this, title, adapter, 1 );
@ -77,8 +81,8 @@ class SCH_BASE_FRAME;
* if( selected )
* {
* int unit;
* LIB_ALIAS* alias = dlg.GetSelectedAlias( &unit );
* do_something( alias, unit );
* #LIB_ID id = dlg.GetSelectedAlias( &unit );
* do_something( id, unit );
* }
*
*/
@ -111,9 +115,9 @@ public:
* with whatever default is desired (usually 1).
*
* @param aUnit if not NULL, the selected unit is filled in here.
* @return the alias that has been selected, or NULL if there is none.
* @return the #LIB_ID of the symbol that has been selected.
*/
LIB_ALIAS* GetSelectedAlias( int* aUnit = nullptr ) const;
LIB_ID GetSelectedLibId( int* aUnit = nullptr ) const;
/**
* Get a list of fields edited by the user.
@ -159,21 +163,21 @@ protected:
void OnComponentSelected( wxCommandEvent& aEvent );
/**
* Look up the footprint for a given alias and display it.
* Look up the footprint for a given symbol specified in the #LIB_ID and display it.
*/
void ShowFootprintFor( LIB_ALIAS* aAlias );
void ShowFootprintFor( LIB_ID const& aLibId );
/**
* Display the given footprint by name.
*/
void ShowFootprint( wxString const& aName );
void ShowFootprint( wxString const& aFootprint );
/**
* Populate the footprint selector for a given alias.
*
* @param aAlias alias, or null to clear
* @param aLibId the #LIB_ID of the selection or invalid to clear
*/
void PopulateFootprintSelector( LIB_ALIAS* aAlias );
void PopulateFootprintSelector( LIB_ID const& aLibId );
/**
* Display a given component into the schematic symbol preview.

View File

@ -21,6 +21,9 @@
#include <generate_alias_info.h>
#include <kicad_string.h>
#include <template_fieldnames.h>
#include <class_libentry.h>
#include <symbol_lib_table.h>
static const wxString DescriptionFormat =
"<b>__NAME__</b>"
@ -45,13 +48,17 @@ static const wxString DatasheetLinkFormat = "<a href=\"__VALUE__\">__VALUE__</a>
class ALIAS_INFO_GENERATOR
{
wxString m_html;
LIB_ALIAS const * m_part;
SYMBOL_LIB_TABLE* m_sym_lib_table;
LIB_ID const m_lib_id;
LIB_ALIAS* m_alias;
int m_unit;
public:
ALIAS_INFO_GENERATOR( LIB_ALIAS const * aAlias, int aUnit )
ALIAS_INFO_GENERATOR( SYMBOL_LIB_TABLE* aSymbolLibTable, LIB_ID const& aLibId, int aUnit )
: m_html( DescriptionFormat ),
m_part( aAlias ),
m_sym_lib_table( aSymbolLibTable ),
m_lib_id( aLibId ),
m_alias( nullptr ),
m_unit( aUnit )
{ }
@ -59,6 +66,27 @@ public:
* Generate the HTML internally.
*/
void GenerateHtml()
{
wxCHECK_RET( m_sym_lib_table, "Symbol library table pointer is not valid" );
if( !m_lib_id.IsValid() )
return;
try
{
m_alias = const_cast< LIB_ALIAS* >( m_sym_lib_table->LoadSymbol( m_lib_id ) );
}
catch( const IO_ERROR& ioe )
{
wxLogError( wxString::Format( _( "Error occurred loading symbol %s from library %s."
"\n\n%s" ),
m_lib_id.GetLibItemName().wx_str(),
m_lib_id.GetLibNickname().wx_str(),
ioe.What() ) );
return;
}
if( m_alias )
{
SetHtmlName();
SetHtmlAliasOf();
@ -66,6 +94,7 @@ public:
SetHtmlKeywords();
SetHtmlFieldTable();
}
}
/**
* Return the generated HTML.
@ -78,13 +107,13 @@ public:
protected:
void SetHtmlName()
{
m_html.Replace( "__NAME__", EscapedHTML( m_part->GetName() ) );
m_html.Replace( "__NAME__", EscapedHTML( m_alias->GetName() ) );
}
void SetHtmlAliasOf()
{
if( m_part->IsRoot() )
if( m_alias->IsRoot() )
{
m_html.Replace( "__ALIASOF__", wxEmptyString );
}
@ -93,7 +122,7 @@ protected:
wxString root_name = _( "Unknown" );
wxString root_desc = "";
LIB_PART* root = m_part->GetPart();
LIB_PART* root = m_alias->GetPart();
LIB_ALIAS* root_alias = root ? root->GetAlias( 0 ) : nullptr;
if( root )
@ -111,7 +140,7 @@ protected:
void SetHtmlDesc()
{
wxString raw_desc = m_part->GetDescription();
wxString raw_desc = m_alias->GetDescription();
m_html.Replace( "__DESC__", wxString::Format( DescFormat, EscapedHTML( raw_desc ) ) );
}
@ -119,7 +148,7 @@ protected:
void SetHtmlKeywords()
{
wxString keywords = m_part->GetKeyWords();
wxString keywords = m_alias->GetKeyWords();
if( keywords.empty() )
m_html.Replace( "__KEY__", wxEmptyString );
@ -159,7 +188,7 @@ protected:
{
wxString fieldtable;
LIB_FIELDS fields;
m_part->GetPart()->GetFields( fields );
m_alias->GetPart()->GetFields( fields );
for( auto const & field: fields )
{
@ -171,9 +200,9 @@ protected:
};
wxString GenerateAliasInfo( LIB_ALIAS const * aAlias, int aUnit )
wxString GenerateAliasInfo( SYMBOL_LIB_TABLE* aSymLibTable, LIB_ID const& aLibId, int aUnit )
{
ALIAS_INFO_GENERATOR gen( aAlias, aUnit );
ALIAS_INFO_GENERATOR gen( aSymLibTable, aLibId, aUnit );
gen.GenerateHtml();
return gen.GetHtml();
}

View File

@ -21,12 +21,15 @@
#ifndef GENERATE_ALIAS_INFO_H
#define GENERATE_ALIAS_INFO_H
#include <class_libentry.h>
#include <wx/string.h>
class LIB_ID;
class SYMBOL_LIB_TABLE;
/**
* Return an HTML page describing a LIB_ALIAS. This is suitable for inclusion
* Return an HTML page describing a #LIB_ID in a #SYMBOL_LIB_TABLE. This is suitable for inclusion
* in a wxHtmlWindow.
*/
wxString GenerateAliasInfo( LIB_ALIAS const * aAlias, int aUnit );
wxString GenerateAliasInfo( SYMBOL_LIB_TABLE* aSymLibTable, LIB_ID const& aLibId, int aUnit );
#endif // GENERATE_ALIAS_INFO_H

View File

@ -45,6 +45,7 @@
#include <libeditframe.h>
#include <viewlib_frame.h>
#include <eeschema_id.h>
#include <symbol_lib_table.h>
#include <dialog_choose_component.h>
#include <cmp_tree_model_adapter.h>
@ -53,7 +54,7 @@
SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibBrowser(
const SCHLIB_FILTER* aFilter,
LIB_ALIAS* aPreselectedAlias,
const LIB_ID& aPreselectedLibId,
int aUnit, int aConvert )
{
// Close any open non-modal Lib browser, and open a new one, in "modal" mode:
@ -67,10 +68,10 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibBrowse
if( aFilter )
viewlibFrame->SetFilter( aFilter );
if( aPreselectedAlias )
if( aPreselectedLibId.IsValid() )
{
viewlibFrame->SetSelectedLibrary( aPreselectedAlias->GetLibraryName() );
viewlibFrame->SetSelectedComponent( aPreselectedAlias->GetName() );
viewlibFrame->SetSelectedLibrary( aPreselectedLibId.GetLibNickname() );
viewlibFrame->SetSelectedComponent( aPreselectedLibId.GetLibItemName() );
}
viewlibFrame->SetUnitAndConvert( aUnit, aConvert );
@ -101,7 +102,7 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibrary(
bool aAllowFields )
{
wxString dialogTitle;
PART_LIBS* libs = Prj().SchLibs();
SYMBOL_LIB_TABLE* libs = Prj().SchSymbolLibTable();
auto adapter( CMP_TREE_MODEL_ADAPTER::Create( libs ) );
bool loaded = false;
@ -112,12 +113,10 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibrary(
for( unsigned ii = 0; ii < liblist.GetCount(); ii++ )
{
PART_LIB* currLibrary = libs->FindLibrary( liblist[ii] );
if( currLibrary )
if( libs->HasLibrary( liblist[ii] ) )
{
loaded = true;
adapter->AddLibrary( *currLibrary );
adapter->AddLibrary( liblist[ii] );
}
}
@ -126,23 +125,41 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibrary(
}
if( !aHistoryList.empty() )
{
wxArrayString history_list;
std::vector< LIB_ALIAS* > history_list;
for( auto const& i : aHistoryList )
history_list.push_back( i.Name );
{
LIB_ALIAS* alias = nullptr;
adapter->AddAliasList( "-- " + _( "History" ) + " --", history_list, NULL );
adapter->SetPreselectNode( aHistoryList[0].Name, aHistoryList[0].Unit );
try
{
alias = libs->LoadSymbol( i.LibNickname, i.Name );
}
catch( const IO_ERROR& ioe )
{
wxLogError( wxString::Format( _( "Error occurred loading symbol %s from library %s."
"\n\n%s" ), i.Name, i.LibNickname, ioe.What() ) );
continue;
}
if( alias )
history_list.push_back( alias );
}
adapter->AddAliasList( "-- " + _( "History" ) + " --", history_list );
adapter->SetPreselectNode( LIB_ID( aHistoryList[0].LibNickname, aHistoryList[0].Name ),
aHistoryList[0].Unit );
}
std::vector< wxString > libNicknames = libs->GetLogicalLibs();
if( !loaded )
{
for( PART_LIB& lib : *libs )
for( auto nickname : libNicknames )
{
adapter->AddLibrary( lib );
adapter->AddLibrary( nickname );
}
}
@ -157,21 +174,19 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectComponentFromLibrary(
return COMPONENT_SELECTION();
COMPONENT_SELECTION sel;
LIB_ALIAS* const alias = dlg.GetSelectedAlias( &sel.Unit );
LIB_ID id = dlg.GetSelectedLibId( &sel.Unit );
if( alias == nullptr ) // Dialog closed by OK button, but no symbol selected
if( !id.IsValid() ) // Dialog closed by OK button, but no symbol selected
return COMPONENT_SELECTION();
if( sel.Unit == 0 )
sel.Unit = 1;
sel.Fields = dlg.GetFields();
if ( alias )
sel.Name = alias->GetName();
sel.Name = id.GetLibItemName();
if( dlg.IsExternalBrowserSelected() ) // User requested component browser.
sel = SelectComponentFromLibBrowser( aFilter, alias, sel.Unit, sel.Convert );
sel = SelectComponentFromLibBrowser( aFilter, id, sel.Unit, sel.Convert );
if( !sel.Name.empty() )
{

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
@ -45,6 +45,7 @@
#include <template_fieldnames.h>
#include <wildcards_and_files_ext.h>
#include <schframe.h>
#include <symbol_lib_table.h>
#include <dialog_choose_component.h>
#include <cmp_tree_model_adapter.h>
@ -514,7 +515,6 @@ void LIB_EDIT_FRAME::DisplayCmpDoc()
void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
{
wxString cmp_name;
LIB_ALIAS* libEntry;
wxArrayString nameList;
wxString msg;
@ -538,12 +538,12 @@ void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
}
}
auto adapter( CMP_TREE_MODEL_ADAPTER::Create( Prj().SchLibs() ) );
auto adapter( CMP_TREE_MODEL_ADAPTER::Create( Prj().SchSymbolLibTable() ) );
wxString name = part ? part->GetName() : wxString( wxEmptyString );
adapter->SetPreselectNode( name, /* aUnit */ 0 );
adapter->ShowUnits( false );
adapter->AddLibrary( *lib );
adapter->AddLibrary( lib->GetName() );
wxString dialogTitle;
dialogTitle.Printf( _( "Delete Component (%u items loaded)" ), adapter->GetComponentsCount() );
@ -555,25 +555,29 @@ void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
return;
}
libEntry = dlg.GetSelectedAlias( NULL );
LIB_ID id;
if( !libEntry )
{
id = dlg.GetSelectedLibId();
if( !id.IsValid() )
return;
LIB_ALIAS* alias = Prj().SchSymbolLibTable()->LoadSymbol( id );
if( !alias )
return;
}
msg.Printf( _( "Delete component '%s' from library '%s' ?" ),
GetChars( libEntry->GetName() ),
GetChars( lib->GetName() ) );
id.GetLibItemName().wx_str(), id.GetLibNickname().wx_str() );
if( !IsOK( this, msg ) )
return;
part = GetCurPart();
if( !part || !part->HasAlias( libEntry->GetName() ) )
if( !part || !part->HasAlias( id.GetLibItemName() ) )
{
lib->RemoveAlias( libEntry );
Prj().SchSymbolLibTable()->DeleteAlias( id.GetLibNickname(), id.GetLibItemName() );
m_canvas->Refresh();
return;
}
@ -588,19 +592,10 @@ void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
return;
}
LIB_ALIAS* nextEntry = lib->RemoveAlias( libEntry );
Prj().SchSymbolLibTable()->DeleteAlias( id.GetLibNickname(), id.GetLibItemName() );
if( nextEntry != NULL )
{
if( LoadOneLibraryPartAux( nextEntry, lib ) )
Zoom_Automatique( false );
}
else
{
SetCurPart( NULL ); // delete CurPart
m_aliasName.Empty();
}
m_canvas->Refresh();
}

View File

@ -34,6 +34,7 @@ class LIB_EDIT_FRAME;
class LIB_ALIAS;
class PART_LIB;
class SCHLIB_FILTER;
class LIB_ID;
/**
* Class SCH_BASE_FRAME
@ -127,6 +128,7 @@ public:
struct COMPONENT_SELECTION
{
wxString LibNickname;
wxString Name;
int Unit;
int Convert;
@ -134,9 +136,10 @@ public:
std::vector<std::pair<int, wxString>> Fields;
COMPONENT_SELECTION():
Name(""),
Unit(1),
Convert(1)
LibNickname( "" ),
Name( "" ),
Unit( 1 ),
Convert( 1 )
{}
};
@ -185,14 +188,14 @@ protected:
* in modal mode.
* @param aFilter is a filter to pass the allowed library names
* and/or some other filter
* @param aPreselectedAlias Preselected component alias. NULL if none.
* @param aPreselectedLibId Preselected component LIB_ID. Not valid if none selected.
* @param aUnit preselected unit
* @param aConvert preselected deMorgan conversion
* @return the selected component
*/
COMPONENT_SELECTION SelectComponentFromLibBrowser(
const SCHLIB_FILTER* aFilter,
LIB_ALIAS* aPreselectedAlias,
const LIB_ID& aPreselectedLibid,
int aUnit, int aConvert );
/**

View File

@ -48,14 +48,18 @@
void LIB_VIEW_FRAME::OnSelectSymbol( wxCommandEvent& aEvent )
{
wxString dialogTitle;
PART_LIBS* libs = Prj().SchLibs();
SYMBOL_LIB_TABLE* libs = Prj().SchSymbolLibTable();
// Container doing search-as-you-type.
auto adapter( CMP_TREE_MODEL_ADAPTER::Create( libs ) );
for( PART_LIB& lib : *libs )
std::vector< wxString > libNicknames;
libNicknames = libs->GetLogicalLibs();
for( auto nickname : libNicknames )
{
adapter->AddLibrary( lib );
adapter->AddLibrary( nickname );
}
dialogTitle.Printf( _( "Choose Component (%d items loaded)" ),
@ -67,21 +71,24 @@ void LIB_VIEW_FRAME::OnSelectSymbol( wxCommandEvent& aEvent )
/// @todo: The unit selection gets reset to 1 by SetSelectedComponent() so the unit
/// selection feature of the choose symbol dialog doesn't work.
LIB_ALIAS* const alias = dlg.GetSelectedAlias( &m_unit );
LIB_ID id = dlg.GetSelectedLibId( &m_unit );
if( !alias || !alias->GetLib() )
if( !id.IsValid() || id.GetLibNickname().empty() )
return;
if( m_libraryName == alias->GetLib()->GetName() )
if( m_libraryName == id.GetLibNickname() )
{
if( m_entryName != alias->GetName() )
SetSelectedComponent( alias->GetName() );
if( m_entryName != id.GetLibItemName() )
SetSelectedComponent( id.GetLibItemName() );
}
else
{
m_entryName = alias->GetName();
SetSelectedLibrary( alias->GetLib()->GetName() );
m_entryName = id.GetLibItemName();
SetSelectedLibrary( id.GetLibNickname() );
SetSelectedComponent( id.GetLibItemName() );
}
Zoom_Automatique( false );
}

View File

@ -32,9 +32,16 @@
#include <wx/statbmp.h>
#include <wx/html/htmlwin.h>
COMPONENT_TREE::COMPONENT_TREE( wxWindow* aParent,
#include <symbol_lib_table.h>
COMPONENT_TREE::COMPONENT_TREE( wxWindow* aParent, SYMBOL_LIB_TABLE* aSymLibTable,
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter, WIDGETS aWidgets )
: wxPanel( aParent ), m_adapter( aAdapter ), m_query_ctrl( nullptr ), m_details_ctrl( nullptr )
: wxPanel( aParent ),
m_sym_lib_table( aSymLibTable ),
m_adapter( aAdapter ),
m_query_ctrl( nullptr ),
m_details_ctrl( nullptr )
{
auto sizer = new wxBoxSizer( wxVERTICAL );
@ -43,8 +50,8 @@ COMPONENT_TREE::COMPONENT_TREE( wxWindow* aParent,
{
auto search_sizer = new wxBoxSizer( wxHORIZONTAL );
m_query_ctrl = new wxTextCtrl(
this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
m_query_ctrl = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxTE_PROCESS_ENTER );
// Additional visual cue for GTK, which hides the placeholder text on focus
#ifdef __WXGTK__
@ -102,10 +109,17 @@ COMPONENT_TREE::COMPONENT_TREE( wxWindow* aParent,
}
LIB_ALIAS* COMPONENT_TREE::GetSelectedAlias( int* aUnit ) const
LIB_ID COMPONENT_TREE::GetSelectedLibId( int* aUnit ) const
{
auto sel = m_tree_ctrl->GetSelection();
if( !sel )
{
LIB_ID emptyId;
return emptyId;
}
if( aUnit )
*aUnit = m_adapter->GetUnitFor( sel );
@ -151,7 +165,7 @@ void COMPONENT_TREE::onQueryText( wxCommandEvent& aEvent )
void COMPONENT_TREE::onQueryEnter( wxCommandEvent& aEvent )
{
if( GetSelectedAlias() )
if( GetSelectedLibId().IsValid() )
postSelectEvent();
}
@ -181,7 +195,7 @@ void COMPONENT_TREE::onTreeSelect( wxDataViewEvent& aEvent )
void COMPONENT_TREE::onTreeActivate( wxDataViewEvent& aEvent )
{
if( !GetSelectedAlias() )
if( !GetSelectedLibId().IsValid() )
{
// Expand library/part units subtree
auto const sel = m_tree_ctrl->GetSelection();
@ -210,10 +224,10 @@ void COMPONENT_TREE::onPreselect( wxCommandEvent& aEvent )
if( m_details_ctrl )
{
int unit = 0;
LIB_ALIAS* alias = GetSelectedAlias( &unit );
LIB_ID id = GetSelectedLibId( &unit );
if( alias )
m_details_ctrl->SetPage( GenerateAliasInfo( alias, unit ) );
if( id.IsValid() )
m_details_ctrl->SetPage( GenerateAliasInfo( m_sym_lib_table, id, unit ) );
else
m_details_ctrl->SetPage( wxEmptyString );
}

View File

@ -33,6 +33,9 @@ class wxDataViewCtrl;
class wxTextCtrl;
class wxHtmlWindow;
class wxHtmlLinkEvent;
class LIB_ID;
class SYMBOL_LIB_TABLE;
/**
* Widget displaying a tree of components with optional search text control and description panel.
@ -43,7 +46,7 @@ public:
///> Flags to select extra widgets
enum WIDGETS { NONE = 0x00, SEARCH = 0x01, DETAILS = 0x02, ALL = 0xFF };
COMPONENT_TREE( wxWindow* aParent,
COMPONENT_TREE( wxWindow* aParent, SYMBOL_LIB_TABLE* aSymLibTable,
CMP_TREE_MODEL_ADAPTER::PTR& aAdapter, WIDGETS aWidgets = ALL );
/**
@ -53,9 +56,9 @@ public:
* with whatever default is desired (usually 1).
*
* @param aUnit if not NULL, the selected unit is filled in here.
* @return the alias that has been selected, or NULL if there is none.
* @return the library id of the symbol that has been selected.
*/
LIB_ALIAS* GetSelectedAlias( int* aUnit = nullptr ) const;
LIB_ID GetSelectedLibId( int* aUnit = nullptr ) const;
protected:
/**
@ -84,8 +87,8 @@ protected:
void onDetailsLink( wxHtmlLinkEvent& aEvent );
void onPreselect( wxCommandEvent& aEvent );
SYMBOL_LIB_TABLE* m_sym_lib_table;
CMP_TREE_MODEL_ADAPTER::PTR m_adapter;
wxTextCtrl* m_query_ctrl;
wxDataViewCtrl* m_tree_ctrl;
wxHtmlWindow* m_details_ctrl;