Support sub-libraries in symbol library browser

Fixes https://gitlab.com/kicad/code/kicad/-/issues/12842
This commit is contained in:
Jon Evans 2023-01-22 19:25:15 -05:00
parent 91d154cd28
commit e419b0bfe8
4 changed files with 172 additions and 37 deletions

View File

@ -272,3 +272,11 @@ bool LIB_ID::isLegalLibraryNameChar( unsigned aUniChar )
}
}
const wxString LIB_ID::GetFullLibraryName() const
{
wxString suffix = m_subLibraryName.wx_str().IsEmpty()
? wxS( "" )
: wxString::Format( wxT( " - %s" ), m_subLibraryName.wx_str() );
return wxString::Format( wxT( "%s%s" ), m_libraryName.wx_str(), suffix );
}

View File

@ -27,10 +27,12 @@
#include <symbol_library_common.h>
#include <confirm.h>
#include <dialog_choose_symbol.h>
#include <dialogs/html_message_box.h>
#include <eeschema_id.h>
#include <eeschema_settings.h>
#include <kiface_base.h>
#include <kiway.h>
#include <locale_io.h>
#include <symbol_viewer_frame.h>
#include <widgets/msgpanel.h>
#include <widgets/wx_listbox.h>
@ -41,6 +43,7 @@
#include <pgm_base.h>
#include <project/project_file.h>
#include <settings/settings_manager.h>
#include <symbol_async_loader.h>
#include <tool/action_toolbar.h>
#include <tool/common_control.h>
#include <tool/common_tools.h>
@ -53,6 +56,7 @@
#include <tools/symbol_editor_control.h>
#include <tools/ee_inspection_tool.h>
#include <view/view_controls.h>
#include <widgets/wx_progress_reporters.h>
#include <wx/srchctrl.h>
#include <default_values.h>
@ -60,11 +64,11 @@
#include "eda_pattern_match.h"
// Save previous symbol library viewer state.
wxString SYMBOL_VIEWER_FRAME::m_libraryName;
wxString SYMBOL_VIEWER_FRAME::m_entryName;
LIB_ID SYMBOL_VIEWER_FRAME::m_currentSymbol;
int SYMBOL_VIEWER_FRAME::m_unit = 1;
int SYMBOL_VIEWER_FRAME::m_convert = 1;
bool SYMBOL_VIEWER_FRAME::m_show_progress = true;
BEGIN_EVENT_TABLE( SYMBOL_VIEWER_FRAME, EDA_DRAW_FRAME )
@ -196,14 +200,17 @@ SYMBOL_VIEWER_FRAME::SYMBOL_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAM
symbolPanel->SetSizer( symbolSizer );
symbolPanel->Fit();
// Preload libraries
loadAllLibraries();
if( aLibraryName.empty() )
{
ReCreateLibList();
}
else
{
m_libraryName = aLibraryName;
m_entryName.Clear();
m_currentSymbol.SetLibNickname( aLibraryName );
m_currentSymbol.SetLibItemName( "" );
m_unit = 1;
m_convert = 1;
}
@ -314,6 +321,58 @@ SYMBOL_VIEWER_FRAME::~SYMBOL_VIEWER_FRAME()
}
void SYMBOL_VIEWER_FRAME::loadAllLibraries()
{
// TODO: deduplicate with SYMBOL_TREE_MODEL_ADAPTER::AddLibraries
std::vector<wxString> libraryNames = Prj().SchSymbolLibTable()->GetLogicalLibs();
std::unique_ptr<WX_PROGRESS_REPORTER> progressReporter = nullptr;
if( m_show_progress )
{
progressReporter = std::make_unique<WX_PROGRESS_REPORTER>( this,
_( "Loading Symbol Libraries" ),
libraryNames.size(), true );
}
// Disable KIID generation: not needed for library parts; sometimes very slow
KIID::CreateNilUuids( true );
std::unordered_map<wxString, std::vector<LIB_SYMBOL*>> loadedSymbols;
SYMBOL_ASYNC_LOADER loader( libraryNames, Prj().SchSymbolLibTable(), false, nullptr,
progressReporter.get() );
LOCALE_IO toggle;
loader.Start();
while( !loader.Done() )
{
if( progressReporter && !progressReporter->KeepRefreshing() )
break;
wxMilliSleep( 33 );
}
loader.Join();
KIID::CreateNilUuids( false );
if( !loader.GetErrors().IsEmpty() )
{
HTML_MESSAGE_BOX dlg( this, _( "Load Error" ) );
dlg.MessageSet( _( "Errors loading symbols:" ) );
wxString msg = loader.GetErrors();
msg.Replace( "\n", "<BR>" );
dlg.AddHTML_Text( msg );
dlg.ShowModal();
}
}
void SYMBOL_VIEWER_FRAME::setupTools()
{
// Create the manager and dispatcher & route draw panel events to the dispatcher
@ -423,8 +482,8 @@ LIB_SYMBOL* SYMBOL_VIEWER_FRAME::GetSelectedSymbol() const
{
LIB_SYMBOL* symbol = nullptr;
if( !m_libraryName.IsEmpty() && !m_entryName.IsEmpty() )
symbol = Prj().SchSymbolLibTable()->LoadSymbol( m_libraryName, m_entryName );
if( m_currentSymbol.IsValid() )
symbol = Prj().SchSymbolLibTable()->LoadSymbol( m_currentSymbol );
return symbol;
}
@ -498,8 +557,8 @@ bool SYMBOL_VIEWER_FRAME::ShowModal( wxString* aSymbol, wxWindow* aParent )
}
else
{
SetSelectedLibrary( libid.GetLibNickname() );
SetSelectedSymbol( libid.GetLibItemName());
SetSelectedLibrary( libid.GetLibNickname(), libid.GetSubLibraryName() );
SetSelectedSymbol( libid.GetLibItemName() );
}
}
}
@ -581,10 +640,25 @@ bool SYMBOL_VIEWER_FRAME::ReCreateLibList()
COMMON_SETTINGS* cfg = Pgm().GetCommonSettings();
PROJECT_FILE& project = Kiway().Prj().GetProjectFile();
std::vector<wxString> libs = Prj().SchSymbolLibTable()->GetLogicalLibs();
SYMBOL_LIB_TABLE* libTable = Prj().SchSymbolLibTable();
std::vector<wxString> libs = libTable->GetLogicalLibs();
std::set<wxString> pinnedMatches;
std::set<wxString> otherMatches;
auto doAddLib =
[&]( const wxString& aLib )
{
if( alg::contains( project.m_PinnedSymbolLibs, aLib )
|| alg::contains( cfg->m_Session.pinned_symbol_libs, aLib ) )
{
pinnedMatches.insert( aLib );
}
else
{
otherMatches.insert( aLib );
}
};
auto process =
[&]( const wxString& aLib )
{
@ -606,14 +680,28 @@ bool SYMBOL_VIEWER_FRAME::ReCreateLibList()
return;
}
if( alg::contains( project.m_PinnedSymbolLibs, aLib )
|| alg::contains( cfg->m_Session.pinned_symbol_libs, aLib ) )
SYMBOL_LIB_TABLE_ROW* row = libTable->FindRow( aLib );
if( !row->GetIsVisible() )
return;
if( row->SupportsSubLibraries() )
{
pinnedMatches.insert( aLib );
std::vector<wxString> subLibraries;
row->GetSubLibraryNames( subLibraries );
for( const wxString& lib : subLibraries )
{
wxString suffix = lib.IsEmpty() ? wxT( "" )
: wxString::Format( wxT( " - %s" ), lib );
wxString name = wxString::Format( wxT( "%s%s" ), aLib, suffix );
doAddLib( name );
}
}
else
{
otherMatches.insert( aLib );
doAddLib( aLib );
}
};
@ -650,7 +738,7 @@ bool SYMBOL_VIEWER_FRAME::ReCreateLibList()
m_libList->Append( UnescapeString( name ) );
// Search for a previous selection:
int index = m_libList->FindString( UnescapeString( m_libraryName ) );
int index = m_libList->FindString( UnescapeString( m_currentSymbol.GetUniStringLibNickname() ) );
if( index != wxNOT_FOUND )
{
@ -660,8 +748,9 @@ bool SYMBOL_VIEWER_FRAME::ReCreateLibList()
{
// If not found, clear current library selection because it can be deleted after a
// config change.
m_libraryName = m_libList->GetCount() > 0 ? m_libList->GetBaseString( 0 ) : wxT( "" );
m_entryName = wxEmptyString;
m_currentSymbol.SetLibNickname( m_libList->GetCount() > 0
? m_libList->GetBaseString( 0 ) : wxT( "" ) );
m_currentSymbol.SetLibItemName( wxEmptyString );
m_unit = 1;
m_convert = LIB_ITEM::LIB_CONVERT::BASE;
}
@ -681,15 +770,18 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
m_symbolList->Clear();
if( m_libraryName.IsEmpty() )
wxString libName = m_currentSymbol.GetUniStringLibNickname();
if( libName.IsEmpty() )
return false;
std::vector<LIB_SYMBOL*> symbols;
SYMBOL_LIB_TABLE_ROW* row = Prj().SchSymbolLibTable()->FindRow( libName );
try
{
if( Prj().SchSymbolLibTable()->FindRow( m_libraryName ) )
Prj().SchSymbolLibTable()->LoadSymbolLib( symbols, m_libraryName, m_listPowerOnly );
if( row )
Prj().SchSymbolLibTable()->LoadSymbolLib( symbols, libName, m_listPowerOnly );
}
catch( const IO_ERROR& ) {} // ignore, it is handled below
@ -719,8 +811,16 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
}
}
wxString subLib = m_currentSymbol.GetSubLibraryName();
for( const LIB_SYMBOL* symbol : symbols )
{
if( row->SupportsSubLibraries()
&& !subLib.IsSameAs( symbol->GetLibId().GetSubLibraryName() ) )
{
continue;
}
if( !excludes.count( symbol->GetName() ) )
m_symbolList->Append( UnescapeString( symbol->GetName() ) );
}
@ -728,13 +828,12 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
if( m_symbolList->IsEmpty() )
{
SetSelectedSymbol( wxEmptyString );
m_entryName = wxEmptyString;
m_convert = LIB_ITEM::LIB_CONVERT::BASE;
m_unit = 1;
return true;
}
int index = m_symbolList->FindString( UnescapeString( m_entryName ) );
int index = m_symbolList->FindString( UnescapeString( m_currentSymbol.GetUniStringLibItemName() ) );
bool changed = false;
if( index == wxNOT_FOUND )
@ -746,7 +845,6 @@ bool SYMBOL_VIEWER_FRAME::ReCreateSymbolList()
index = -1;
changed = true;
SetSelectedSymbol( wxEmptyString );
m_entryName = wxEmptyString;
}
m_symbolList->SetSelection( index, true );
@ -764,16 +862,33 @@ void SYMBOL_VIEWER_FRAME::ClickOnLibList( wxCommandEvent& event )
m_selection_changed = true;
SetSelectedLibrary( EscapeString( m_libList->GetBaseString( ii ), CTX_LIBID ) );
wxString selection = EscapeString( m_libList->GetBaseString( ii ), CTX_LIBID );
if( !Prj().SchSymbolLibTable()->FindRow( selection )
&& selection.Find( '-' ) != wxNOT_FOUND )
{
// Probably a sub-library
wxString sublib;
selection = selection.BeforeLast( '-', &sublib ).Trim();
sublib.Trim( false );
SetSelectedLibrary( selection, sublib );
}
else
{
SetSelectedLibrary( selection );
}
}
void SYMBOL_VIEWER_FRAME::SetSelectedLibrary( const wxString& aLibraryName )
void SYMBOL_VIEWER_FRAME::SetSelectedLibrary( const wxString& aLibraryName,
const wxString& aSubLibName )
{
if( m_libraryName == aLibraryName )
if( m_currentSymbol.GetUniStringLibNickname() == aLibraryName &&
wxString( m_currentSymbol.GetSubLibraryName() ) == aSubLibName )
return;
m_libraryName = aLibraryName;
m_currentSymbol.SetLibNickname( aLibraryName );
m_currentSymbol.SetSubLibraryName( aSubLibName );
ReCreateSymbolList();
GetCanvas()->Refresh();
DisplayLibInfos();
@ -781,7 +896,7 @@ void SYMBOL_VIEWER_FRAME::SetSelectedLibrary( const wxString& aLibraryName )
// Ensure the corresponding line in m_libList is selected
// (which is not necessary the case if SetSelectedLibrary is called
// by another caller than ClickOnLibList.
m_libList->SetStringSelection( UnescapeString( m_libraryName ), true );
m_libList->SetStringSelection( UnescapeString( m_currentSymbol.GetFullLibraryName() ), true );
// The m_libList has now the focus, in order to be able to use arrow keys
// to navigate inside the list.
@ -812,9 +927,9 @@ void SYMBOL_VIEWER_FRAME::ClickOnSymbolList( wxCommandEvent& event )
void SYMBOL_VIEWER_FRAME::SetSelectedSymbol( const wxString& aSymbolName )
{
if( m_entryName != aSymbolName )
if( m_currentSymbol.GetUniStringLibItemName() != aSymbolName )
{
m_entryName = aSymbolName;
m_currentSymbol.SetLibItemName( aSymbolName );
// Ensure the corresponding line in m_symbolList is selected
// (which is not necessarily the case if SetSelectedSymbol is called
@ -975,8 +1090,7 @@ void SYMBOL_VIEWER_FRAME::FinishModal()
{
if( m_symbolList->GetSelection() >= 0 )
{
DismissModal( true, m_libraryName + ':'
+ EscapeString( m_symbolList->GetStringSelection(), CTX_LIBID ) );
DismissModal( true, m_currentSymbol.Format() );
}
else
{
@ -1034,7 +1148,7 @@ void SYMBOL_VIEWER_FRAME::OnSelectSymbol( wxCommandEvent& aEvent )
if( !id.IsValid() )
return;
SetSelectedLibrary( id.GetLibNickname() );
SetSelectedLibrary( id.GetLibNickname(), id.GetSubLibraryName() );
SetSelectedSymbol( id.GetLibItemName() );
SetUnitAndConvert( unit, 1 );
}
@ -1173,9 +1287,12 @@ void SYMBOL_VIEWER_FRAME::onSelectSymbolUnit( wxCommandEvent& aEvent )
void SYMBOL_VIEWER_FRAME::DisplayLibInfos()
{
if( m_libList && !m_libList->IsEmpty() && !m_libraryName.IsEmpty() )
wxString libName = m_currentSymbol.GetUniStringLibNickname();
if( m_libList && !m_libList->IsEmpty() && !libName.IsEmpty() )
{
const SYMBOL_LIB_TABLE_ROW* row = Prj().SchSymbolLibTable()->FindRow( m_libraryName, true );
const SYMBOL_LIB_TABLE_ROW* row =
Prj().SchSymbolLibTable()->FindRow( libName, true );
wxString title = row ? row->GetFullURI( true ) : _( "[no library selected]" );

View File

@ -117,7 +117,8 @@ public:
/**
* Set the selected library in the library window.
*/
void SetSelectedLibrary( const wxString& aLibName );
void SetSelectedLibrary( const wxString& aLibName,
const wxString& aSubLibName = wxEmptyString );
/**
* Set the selected symbol.
@ -170,6 +171,8 @@ private:
void updatePreviewSymbol();
void loadAllLibraries();
private:
wxChoice* m_unitChoice;
@ -185,11 +188,11 @@ private:
bool m_listPowerOnly;
wxArrayString m_allowedLibs;
static wxString m_libraryName;
static wxString m_entryName;
static LIB_ID m_currentSymbol;
static int m_unit;
static int m_convert;
static bool m_show_progress;
/**
* Updated to `true` if a list rewrite on GUI activation resulted in the symbol

View File

@ -85,6 +85,7 @@ public:
* Return the logical library name portion of a LIB_ID.
*/
const UTF8& GetLibNickname() const { return m_libraryName; }
const wxString GetUniStringLibNickname() const { return m_libraryName.wx_str(); }
/**
* Override the logical library name portion of the LIB_ID to @a aNickname.
@ -128,6 +129,12 @@ public:
*/
UTF8 GetSubLibraryName() const { return m_subLibraryName; }
void SetSubLibraryName( const UTF8& aName ) { m_subLibraryName = aName; }
const wxString GetUniStringSubLibraryName() const { return m_subLibraryName.wx_str(); }
/**
* @return a display-formatted name of the library and sublibrary (if present)
*/
const wxString GetFullLibraryName() const;
/**
* @return the fully formatted text of the LIB_ID in a UTF8 string.