Improve error reporting for lib table rows.
This commit is contained in:
@@ -67,8 +67,7 @@ LIBRARY_RESULT<IO_BASE*> DESIGN_BLOCK_LIBRARY_ADAPTER::createPlugin( const LIBRA
|
||||
if( type == DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_UNKNOWN )
|
||||
{
|
||||
wxLogTrace( traceLibraries, "Sym: Plugin type %s is unknown!", row->Type() );
|
||||
wxString msg =
|
||||
wxString::Format( _( "Unknown library type %s " ), row->Type() );
|
||||
wxString msg = wxString::Format( _( "Unknown library type %s " ), row->Type() );
|
||||
return tl::unexpected( LIBRARY_ERROR( msg ) );
|
||||
}
|
||||
|
||||
@@ -85,6 +84,32 @@ IO_BASE* DESIGN_BLOCK_LIBRARY_ADAPTER::plugin( const LIB_DATA* aRow )
|
||||
}
|
||||
|
||||
|
||||
/// Loads or reloads the given library, if it exists
|
||||
std::optional<LIB_STATUS> DESIGN_BLOCK_LIBRARY_ADAPTER::LoadOne( LIB_DATA* aLib )
|
||||
{
|
||||
wxArrayString dummyList;
|
||||
std::lock_guard lock ( aLib->mutex );
|
||||
aLib->status.load_status = LOAD_STATUS::LOADING;
|
||||
|
||||
std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
|
||||
|
||||
try
|
||||
{
|
||||
dbplugin( aLib )->DesignBlockEnumerate( dummyList, getUri( aLib->row ), false, &options );
|
||||
wxLogTrace( traceLibraries, "DB: %s: library enumerated %zu items", aLib->row->Nickname(), dummyList.size() );
|
||||
aLib->status.load_status = LOAD_STATUS::LOADED;
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
{
|
||||
aLib->status.load_status = LOAD_STATUS::LOAD_ERROR;
|
||||
aLib->status.error = LIBRARY_ERROR( { e.What() } );
|
||||
wxLogTrace( traceLibraries, "DB: %s: plugin threw exception: %s", aLib->row->Nickname(), e.What() );
|
||||
}
|
||||
|
||||
return aLib->status;
|
||||
}
|
||||
|
||||
|
||||
void DESIGN_BLOCK_LIBRARY_ADAPTER::AsyncLoad()
|
||||
{
|
||||
// TODO(JE) library tables - how much of this can be shared with other library types?
|
||||
@@ -116,20 +141,20 @@ void DESIGN_BLOCK_LIBRARY_ADAPTER::AsyncLoad()
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
|
||||
auto check =
|
||||
[]( const wxString& aLib, std::map<wxString, LIB_DATA>& aMap, std::mutex& aMutex )
|
||||
{
|
||||
std::lock_guard lock( aMutex );
|
||||
|
||||
if( aMap.contains( aLib ) )
|
||||
[]( const wxString& aLib, std::map<wxString, LIB_DATA>& aMap, std::mutex& aMutex )
|
||||
{
|
||||
if( aMap[aLib].status.load_status == LOAD_STATUS::LOADED )
|
||||
return true;
|
||||
std::lock_guard lock( aMutex );
|
||||
|
||||
aMap.erase( aLib );
|
||||
}
|
||||
if( aMap.contains( aLib ) )
|
||||
{
|
||||
if( aMap[aLib].status.load_status == LOAD_STATUS::LOADED )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
aMap.erase( aLib );
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
std::set<wxString> libNamesCurrentlyValid;
|
||||
|
||||
@@ -154,71 +179,53 @@ void DESIGN_BLOCK_LIBRARY_ADAPTER::AsyncLoad()
|
||||
}
|
||||
|
||||
m_futures.emplace_back( tp.submit_task(
|
||||
[this, nickname, scope]()
|
||||
{
|
||||
if( m_abort.load() )
|
||||
return;
|
||||
|
||||
LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( nickname );
|
||||
|
||||
if( result.has_value() )
|
||||
[this, nickname, scope]()
|
||||
{
|
||||
LIB_DATA* lib = *result;
|
||||
wxArrayString dummyList;
|
||||
std::lock_guard lock ( lib->mutex );
|
||||
lib->status.load_status = LOAD_STATUS::LOADING;
|
||||
if( m_abort.load() )
|
||||
return;
|
||||
|
||||
std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
|
||||
LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( nickname );
|
||||
|
||||
try
|
||||
if( result.has_value() )
|
||||
{
|
||||
dbplugin( lib )->DesignBlockEnumerate( dummyList, getUri( lib->row ), false, &options );
|
||||
wxLogTrace( traceLibraries, "DB: %s: library enumerated %zu items", nickname, dummyList.size() );
|
||||
lib->status.load_status = LOAD_STATUS::LOADED;
|
||||
LoadOne( *result );
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
else
|
||||
{
|
||||
lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
|
||||
lib->status.error = LIBRARY_ERROR( { e.What() } );
|
||||
wxLogTrace( traceLibraries, "DB: %s: plugin threw exception: %s", nickname, e.What() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( scope )
|
||||
{
|
||||
case LIBRARY_TABLE_SCOPE::GLOBAL:
|
||||
{
|
||||
std::lock_guard lock( GlobalLibraryMutex );
|
||||
switch( scope )
|
||||
{
|
||||
case LIBRARY_TABLE_SCOPE::GLOBAL:
|
||||
{
|
||||
std::lock_guard lock( GlobalLibraryMutex );
|
||||
|
||||
GlobalLibraries[nickname].status = LIB_STATUS( {
|
||||
.load_status = LOAD_STATUS::LOAD_ERROR,
|
||||
.error = result.error()
|
||||
} );
|
||||
GlobalLibraries[nickname].status = LIB_STATUS( {
|
||||
.load_status = LOAD_STATUS::LOAD_ERROR,
|
||||
.error = result.error()
|
||||
} );
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
case LIBRARY_TABLE_SCOPE::PROJECT:
|
||||
{
|
||||
wxLogTrace( traceLibraries, "DB: project library error: %s: %s", nickname, result.error().message );
|
||||
std::lock_guard lock( m_libraries_mutex );
|
||||
|
||||
m_libraries[nickname].status = LIB_STATUS( {
|
||||
.load_status = LOAD_STATUS::LOAD_ERROR,
|
||||
.error = result.error()
|
||||
} );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "Unexpected library table scope" );
|
||||
}
|
||||
}
|
||||
|
||||
case LIBRARY_TABLE_SCOPE::PROJECT:
|
||||
{
|
||||
wxLogTrace( traceLibraries, "DB: project library error: %s: %s", nickname, result.error().message );
|
||||
std::lock_guard lock( m_libraries_mutex );
|
||||
|
||||
m_libraries[nickname].status = LIB_STATUS( {
|
||||
.load_status = LOAD_STATUS::LOAD_ERROR,
|
||||
.error = result.error()
|
||||
} );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
wxFAIL_MSG( "Unexpected library table scope" );
|
||||
}
|
||||
}
|
||||
|
||||
++m_loadCount;
|
||||
}, BS::pr::lowest ) );
|
||||
++m_loadCount;
|
||||
}, BS::pr::lowest ) );
|
||||
}
|
||||
|
||||
// Cleanup libraries that were removed from the table
|
||||
@@ -262,8 +269,7 @@ std::vector<DESIGN_BLOCK*> DESIGN_BLOCK_LIBRARY_ADAPTER::GetDesignBlocks( const
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
{
|
||||
wxLogTrace( traceLibraries, "DB: Exception enumerating library %s: %s",
|
||||
lib->row->Nickname(), e.What() );
|
||||
wxLogTrace( traceLibraries, "DB: Exception enumerating library %s: %s", lib->row->Nickname(), e.What() );
|
||||
}
|
||||
|
||||
for( const wxString& blockName : blockNames )
|
||||
@@ -304,7 +310,7 @@ std::vector<wxString> DESIGN_BLOCK_LIBRARY_ADAPTER::GetDesignBlockNames( const w
|
||||
|
||||
|
||||
DESIGN_BLOCK* DESIGN_BLOCK_LIBRARY_ADAPTER::LoadDesignBlock( const wxString& aNickname,
|
||||
const wxString& aDesignBlockName, bool aKeepUUID )
|
||||
const wxString& aDesignBlockName, bool aKeepUUID )
|
||||
{
|
||||
if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
|
||||
{
|
||||
@@ -350,7 +356,8 @@ const DESIGN_BLOCK* DESIGN_BLOCK_LIBRARY_ADAPTER::GetEnumeratedDesignBlock( cons
|
||||
|
||||
|
||||
DESIGN_BLOCK_LIBRARY_ADAPTER::SAVE_T DESIGN_BLOCK_LIBRARY_ADAPTER::SaveDesignBlock( const wxString& aNickname,
|
||||
const DESIGN_BLOCK* aDesignBlock, bool aOverwrite )
|
||||
const DESIGN_BLOCK* aDesignBlock,
|
||||
bool aOverwrite )
|
||||
{
|
||||
if( std::optional<const LIB_DATA*> maybeLib = fetchIfLoaded( aNickname ) )
|
||||
{
|
||||
|
||||
@@ -42,6 +42,8 @@ public:
|
||||
|
||||
void AsyncLoad() override;
|
||||
|
||||
std::optional<LIB_STATUS> LoadOne( LIB_DATA* aLib ) override;
|
||||
|
||||
// Currently unused for design blocks
|
||||
std::optional<LIB_STATUS> GetLibraryStatus( const wxString& aNickname ) const override { return std::nullopt; }
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ PANEL_DESIGN_BLOCK_LIB_TABLE_BASE::PANEL_DESIGN_BLOCK_LIB_TABLE_BASE( wxWindow*
|
||||
|
||||
m_notebook = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_CLOSE_ON_ALL_TABS|wxAUI_NB_DEFAULT_STYLE );
|
||||
|
||||
bMainSizer->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );
|
||||
bMainSizer->Add( m_notebook, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
wxBoxSizer* bButtonsSizer;
|
||||
bButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
@@ -59,7 +59,7 @@ PANEL_DESIGN_BLOCK_LIB_TABLE_BASE::PANEL_DESIGN_BLOCK_LIB_TABLE_BASE( wxWindow*
|
||||
bButtonsSizer->Add( m_migrate_libs_button, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
|
||||
bMainSizer->Add( bButtonsSizer, 0, wxEXPAND|wxALL, 8 );
|
||||
bMainSizer->Add( bButtonsSizer, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 8 );
|
||||
|
||||
wxStaticText* stPathsLabel;
|
||||
stPathsLabel = new wxStaticText( this, wxID_ANY, _("Available path substitutions:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND | wxALL</property>
|
||||
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxAuiNotebook" expanded="true">
|
||||
<property name="BottomDockable">1</property>
|
||||
@@ -123,7 +123,7 @@
|
||||
</object>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">8</property>
|
||||
<property name="flag">wxEXPAND|wxALL</property>
|
||||
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="true">
|
||||
<property name="minimum_size"></property>
|
||||
|
||||
@@ -469,38 +469,19 @@ bool LIB_TABLE_GRID_TRICKS::VerifyTable( WX_GRID* aGrid, std::function<void( int
|
||||
wxString uri = model->GetValue( r, COL_URI ).Trim( false ).Trim();
|
||||
unsigned illegalCh = 0;
|
||||
|
||||
if( !nick || !uri )
|
||||
if( !uri )
|
||||
{
|
||||
if( !nick && !uri )
|
||||
msg = _( "A library table row nickname and path cells are empty." );
|
||||
else if( !nick )
|
||||
msg = _( "A library table row nickname cell is empty." );
|
||||
else
|
||||
msg = _( "A library table row path cell is empty." );
|
||||
|
||||
wxMessageDialog badCellDlg( topLevelParent, msg, _( "Invalid Row Definition" ),
|
||||
wxYES_NO | wxCENTER | wxICON_QUESTION | wxYES_DEFAULT );
|
||||
badCellDlg.SetExtendedMessage( _( "Empty cells will result in all rows that are "
|
||||
"invalid to be removed from the table." ) );
|
||||
badCellDlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Remove Invalid Cells" ) ),
|
||||
wxMessageDialog::ButtonLabel( _( "Cancel Table Update" ) ) );
|
||||
|
||||
if( badCellDlg.ShowModal() == wxID_NO )
|
||||
return false;
|
||||
|
||||
// Delete the "empty" row, where empty means missing nick or uri.
|
||||
// This also updates the UI which could be slow, but there should only be a few
|
||||
// rows to delete, unless the user fell asleep on the Add Row
|
||||
// button.
|
||||
// Silently nuke rows that have no libraray URI
|
||||
model->DeleteRows( r, 1 );
|
||||
}
|
||||
else if( ( illegalCh = LIB_ID::FindIllegalLibraryNameChar( nick ) ) )
|
||||
else if( !nick || ( illegalCh = LIB_ID::FindIllegalLibraryNameChar( nick ) ) )
|
||||
{
|
||||
msg = wxString::Format( _( "Illegal character '%c' in nickname '%s'." ),
|
||||
illegalCh,
|
||||
nick );
|
||||
if( !nick )
|
||||
msg = _( "Library must have a nickname." );
|
||||
else
|
||||
msg = wxString::Format( _( "Illegal character '%c' in nickname '%s'." ), illegalCh, nick );
|
||||
|
||||
aErrorHandler( r, 1 );
|
||||
aErrorHandler( r, COL_NICKNAME );
|
||||
|
||||
wxMessageDialog errdlg( topLevelParent, msg, _( "Library Nickname Error" ) );
|
||||
errdlg.ShowModal();
|
||||
|
||||
@@ -54,6 +54,10 @@ LIB_TABLE_GRID_DATA_MODEL::LIB_TABLE_GRID_DATA_MODEL( DIALOG_SHIM* aDialog, WX_G
|
||||
m_warningAttr->SetReadOnly();
|
||||
m_warningAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
|
||||
|
||||
m_noStatusAttr = new wxGridCellAttr;
|
||||
m_noStatusAttr->SetReadOnly();
|
||||
m_noStatusAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
|
||||
|
||||
m_editSettingsAttr = new wxGridCellAttr;
|
||||
m_editSettingsAttr->SetRenderer( new GRID_BITMAP_BUTTON_RENDERER( KiBitmapBundle( BITMAPS::config ) ) );
|
||||
m_editSettingsAttr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
|
||||
@@ -72,55 +76,66 @@ LIB_TABLE_GRID_DATA_MODEL::~LIB_TABLE_GRID_DATA_MODEL()
|
||||
m_typesEditor->DecRef();
|
||||
m_boolAttr->DecRef();
|
||||
m_warningAttr->DecRef();
|
||||
m_noStatusAttr->DecRef();
|
||||
m_editSettingsAttr->DecRef();
|
||||
m_openTableAttr->DecRef();
|
||||
}
|
||||
|
||||
|
||||
bool LIB_TABLE_GRID_DATA_MODEL::badCoords( int aRow, int aCol )
|
||||
{
|
||||
if( aRow < 0 || aRow >= (int) size() )
|
||||
return true;
|
||||
|
||||
if( aCol < 0 || aCol >= GetNumberCols() )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
wxString LIB_TABLE_GRID_DATA_MODEL::GetValue( int aRow, int aCol )
|
||||
{
|
||||
wxCHECK( aRow >= 0, wxEmptyString );
|
||||
size_t row = static_cast<size_t>( aRow );
|
||||
if( badCoords( aRow, aCol ) )
|
||||
return wxEmptyString;
|
||||
|
||||
if( row < size() )
|
||||
const LIBRARY_TABLE_ROW& r = at( aRow );
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
const LIBRARY_TABLE_ROW& r = at( row );
|
||||
case COL_NICKNAME: return UnescapeString( r.Nickname() );
|
||||
case COL_URI: return r.URI();
|
||||
case COL_TYPE: return r.Type();
|
||||
case COL_OPTIONS: return r.Options();
|
||||
case COL_DESCR: return r.Description();
|
||||
case COL_ENABLED: return r.Disabled() ? wxT( "0" ) : wxT( "1" );
|
||||
case COL_VISIBLE: return r.Hidden() ? wxT( "0" ) : wxT( "1" );
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
case COL_NICKNAME: return UnescapeString( r.Nickname() );
|
||||
case COL_URI: return r.URI();
|
||||
case COL_TYPE: return r.Type();
|
||||
case COL_OPTIONS: return r.Options();
|
||||
case COL_DESCR: return r.Description();
|
||||
case COL_ENABLED: return r.Disabled() ? wxT( "0" ) : wxT( "1" );
|
||||
case COL_VISIBLE: return r.Hidden() ? wxT( "0" ) : wxT( "1" );
|
||||
case COL_STATUS:
|
||||
if( !r.IsOk() )
|
||||
return r.ErrorDescription();
|
||||
|
||||
case COL_STATUS:
|
||||
if( !r.IsOk() )
|
||||
return r.ErrorDescription();
|
||||
if( std::optional<LIBRARY_ERROR> error = m_adapter->LibraryError( r.Nickname() ) )
|
||||
return error->message;
|
||||
|
||||
if( std::optional<LIBRARY_ERROR> error = m_adapter->LibraryError( r.Nickname() ) )
|
||||
return error->message;
|
||||
if( m_adapter->SupportsConfigurationDialog( r.Nickname() ) )
|
||||
return _( "Edit settings" );
|
||||
else if( r.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME )
|
||||
return _( "Open library table" );
|
||||
|
||||
if( m_adapter->SupportsConfigurationDialog( r.Nickname() ) )
|
||||
return _( "Edit settings" );
|
||||
else if( r.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME )
|
||||
return _( "Open library table" );
|
||||
return wxEmptyString;
|
||||
|
||||
return wxEmptyString;
|
||||
|
||||
default:
|
||||
return wxEmptyString;
|
||||
}
|
||||
default:
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
wxGridCellAttr* LIB_TABLE_GRID_DATA_MODEL::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
|
||||
{
|
||||
if( badCoords( aRow, aCol ) )
|
||||
return enhanceAttr( nullptr, aRow, aCol, aKind );
|
||||
|
||||
LIBRARY_TABLE_ROW& tableRow = at( aRow );
|
||||
|
||||
switch( aCol )
|
||||
@@ -162,7 +177,8 @@ wxGridCellAttr* LIB_TABLE_GRID_DATA_MODEL::GetAttr( int aRow, int aCol, wxGridCe
|
||||
return enhanceAttr( m_openTableAttr, aRow, aCol, aKind );
|
||||
}
|
||||
|
||||
return enhanceAttr( nullptr, aRow, aCol, aKind );
|
||||
m_noStatusAttr->IncRef();
|
||||
return enhanceAttr( m_noStatusAttr, aRow, aCol, aKind );
|
||||
|
||||
case COL_NICKNAME:
|
||||
case COL_OPTIONS:
|
||||
@@ -175,32 +191,30 @@ wxGridCellAttr* LIB_TABLE_GRID_DATA_MODEL::GetAttr( int aRow, int aCol, wxGridCe
|
||||
|
||||
bool LIB_TABLE_GRID_DATA_MODEL::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
|
||||
{
|
||||
if( aRow < static_cast<int>( size() ) )
|
||||
if( badCoords( aRow, aCol ) )
|
||||
return false;
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
switch( aCol )
|
||||
{
|
||||
case COL_ENABLED:
|
||||
case COL_VISIBLE:
|
||||
return aTypeName == wxGRID_VALUE_BOOL;
|
||||
case COL_ENABLED:
|
||||
case COL_VISIBLE:
|
||||
return aTypeName == wxGRID_VALUE_BOOL;
|
||||
|
||||
default:
|
||||
return aTypeName == wxGRID_VALUE_STRING;
|
||||
}
|
||||
default:
|
||||
return aTypeName == wxGRID_VALUE_STRING;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LIB_TABLE_GRID_DATA_MODEL::GetValueAsBool( int aRow, int aCol )
|
||||
{
|
||||
wxCHECK( aRow >= 0, false );
|
||||
size_t row = static_cast<size_t>( aRow );
|
||||
if( badCoords( aRow, aCol ) )
|
||||
return false;
|
||||
|
||||
if( row < size() && aCol == COL_ENABLED )
|
||||
return !at( row ).Disabled();
|
||||
else if( row < size() && aCol == COL_VISIBLE )
|
||||
return !at( row ).Hidden();
|
||||
if( aCol == COL_ENABLED )
|
||||
return !at( aRow ).Disabled();
|
||||
else if( aCol == COL_VISIBLE )
|
||||
return !at( aRow ).Hidden();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
@@ -208,36 +222,50 @@ bool LIB_TABLE_GRID_DATA_MODEL::GetValueAsBool( int aRow, int aCol )
|
||||
|
||||
void LIB_TABLE_GRID_DATA_MODEL::SetValue( int aRow, int aCol, const wxString& aValue )
|
||||
{
|
||||
wxCHECK( aRow >= 0, /* void */ );
|
||||
size_t row = static_cast<size_t>( aRow );
|
||||
if( badCoords( aRow, aCol ) )
|
||||
return;
|
||||
|
||||
if( row < size() )
|
||||
LIBRARY_TABLE_ROW& r = at( aRow );
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
LIBRARY_TABLE_ROW& r = at( row );
|
||||
case COL_NICKNAME: r.SetNickname( EscapeString( aValue, CTX_LIBID ) ); break;
|
||||
case COL_URI: r.SetURI( aValue ); break;
|
||||
case COL_TYPE: r.SetType( aValue ); break;
|
||||
case COL_OPTIONS: r.SetOptions( aValue ); break;
|
||||
case COL_DESCR: r.SetDescription( aValue ); break;
|
||||
case COL_ENABLED: r.SetDisabled( aValue == wxT( "0" ) ); break;
|
||||
case COL_VISIBLE: r.SetHidden( aValue == wxT( "0" ) ); break;
|
||||
case COL_STATUS: break;
|
||||
}
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
case COL_NICKNAME: r.SetNickname( EscapeString( aValue, CTX_LIBID ) ); break;
|
||||
case COL_URI: r.SetURI( aValue ); break;
|
||||
case COL_TYPE: r.SetType( aValue ); break;
|
||||
case COL_OPTIONS: r.SetOptions( aValue ); break;
|
||||
case COL_DESCR: r.SetDescription( aValue ); break;
|
||||
case COL_ENABLED: r.SetDisabled( aValue == wxT( "0" ) ); break;
|
||||
case COL_VISIBLE: r.SetHidden( aValue == wxT( "0" ) ); break;
|
||||
case COL_STATUS: break;
|
||||
}
|
||||
if( aCol == COL_URI || aCol == COL_TYPE || aCol == COL_OPTIONS )
|
||||
{
|
||||
GetView()->CallAfter(
|
||||
[this, aRow, aCol]()
|
||||
{
|
||||
if( badCoords( aRow, aCol ) )
|
||||
return;
|
||||
|
||||
LIBRARY_TABLE_ROW& r = at( aRow );
|
||||
|
||||
m_adapter->CheckTableRow( r );
|
||||
|
||||
GetView()->RefreshBlock( aRow, COL_STATUS, aRow, COL_STATUS );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LIB_TABLE_GRID_DATA_MODEL::SetValueAsBool( int aRow, int aCol, bool aValue )
|
||||
{
|
||||
wxCHECK( aRow >= 0, /* void */ );
|
||||
size_t row = static_cast<size_t>( aRow );
|
||||
if( badCoords( aRow, aCol ) )
|
||||
return;
|
||||
|
||||
if( row < size() && aCol == COL_ENABLED )
|
||||
at( row ).SetDisabled( !aValue );
|
||||
else if( row < size() && aCol == COL_VISIBLE )
|
||||
at( row ).SetHidden( !aValue );
|
||||
if( aCol == COL_ENABLED )
|
||||
at( aRow ).SetDisabled( !aValue );
|
||||
else if( aCol == COL_VISIBLE )
|
||||
at( aRow ).SetHidden( !aValue );
|
||||
}
|
||||
|
||||
|
||||
@@ -357,7 +385,8 @@ LIBRARY_TABLE_ROWS_ITER LIB_TABLE_GRID_DATA_MODEL::begin()
|
||||
}
|
||||
|
||||
|
||||
LIBRARY_TABLE_ROWS_ITER LIB_TABLE_GRID_DATA_MODEL::insert( LIBRARY_TABLE_ROWS_ITER aIterator, const LIBRARY_TABLE_ROW& aRow )
|
||||
LIBRARY_TABLE_ROWS_ITER LIB_TABLE_GRID_DATA_MODEL::insert( LIBRARY_TABLE_ROWS_ITER aIterator,
|
||||
const LIBRARY_TABLE_ROW& aRow )
|
||||
{
|
||||
return m_table.Rows().insert( aIterator, aRow );
|
||||
}
|
||||
@@ -369,7 +398,8 @@ void LIB_TABLE_GRID_DATA_MODEL::push_back( const LIBRARY_TABLE_ROW& aRow )
|
||||
}
|
||||
|
||||
|
||||
LIBRARY_TABLE_ROWS_ITER LIB_TABLE_GRID_DATA_MODEL::erase( LIBRARY_TABLE_ROWS_ITER aFirst, LIBRARY_TABLE_ROWS_ITER aLast )
|
||||
LIBRARY_TABLE_ROWS_ITER LIB_TABLE_GRID_DATA_MODEL::erase( LIBRARY_TABLE_ROWS_ITER aFirst,
|
||||
LIBRARY_TABLE_ROWS_ITER aLast )
|
||||
{
|
||||
return m_table.Rows().erase( aFirst, aLast );
|
||||
}
|
||||
|
||||
@@ -780,6 +780,36 @@ void LIBRARY_MANAGER_ADAPTER::GlobalTablesChanged( std::initializer_list<LIBRARY
|
||||
globalLibs().clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LIBRARY_MANAGER_ADAPTER::CheckTableRow( LIBRARY_TABLE_ROW& aRow )
|
||||
{
|
||||
abortLoad();
|
||||
|
||||
LIBRARY_RESULT<IO_BASE*> plugin = createPlugin( &aRow );
|
||||
|
||||
if( plugin.has_value() )
|
||||
{
|
||||
LIB_DATA lib;
|
||||
lib.row = &aRow;
|
||||
lib.plugin.reset( *plugin );
|
||||
|
||||
std::optional<LIB_STATUS> status = LoadOne( &lib );
|
||||
|
||||
if( status.has_value() )
|
||||
{
|
||||
aRow.SetOk( status.value().load_status == LOAD_STATUS::LOADED );
|
||||
|
||||
if( status.value().error.has_value() )
|
||||
aRow.SetErrorDescription( status.value().error.value().message );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aRow.SetOk( false );
|
||||
aRow.SetErrorDescription( plugin.error().message );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1035,48 +1065,48 @@ std::optional<LIB_DATA*> LIBRARY_MANAGER_ADAPTER::fetchIfLoaded(
|
||||
LIBRARY_RESULT<LIB_DATA*> LIBRARY_MANAGER_ADAPTER::loadIfNeeded( const wxString& aNickname )
|
||||
{
|
||||
auto tryLoadFromScope =
|
||||
[&]( LIBRARY_TABLE_SCOPE aScope, std::map<wxString, LIB_DATA>& aTarget,
|
||||
std::mutex& aMutex ) -> LIBRARY_RESULT<LIB_DATA*>
|
||||
{
|
||||
bool present = false;
|
||||
|
||||
[&]( LIBRARY_TABLE_SCOPE aScope, std::map<wxString, LIB_DATA>& aTarget,
|
||||
std::mutex& aMutex ) -> LIBRARY_RESULT<LIB_DATA*>
|
||||
{
|
||||
std::lock_guard lock( aMutex );
|
||||
present = aTarget.contains( aNickname ) && aTarget.at( aNickname ).plugin;
|
||||
}
|
||||
bool present = false;
|
||||
|
||||
if( !present )
|
||||
{
|
||||
if( auto result = m_manager.GetRow( Type(), aNickname, aScope ) )
|
||||
{
|
||||
const LIBRARY_TABLE_ROW* row = *result;
|
||||
wxLogTrace( traceLibraries, "Library %s (%s) not yet loaded, will attempt...",
|
||||
aNickname, magic_enum::enum_name( aScope ) );
|
||||
|
||||
if( LIBRARY_RESULT<IO_BASE*> plugin = createPlugin( row ); plugin.has_value() )
|
||||
{
|
||||
std::lock_guard lock( aMutex );
|
||||
|
||||
aTarget[ row->Nickname() ].status.load_status = LOAD_STATUS::LOADING;
|
||||
aTarget[ row->Nickname() ].row = row;
|
||||
aTarget[ row->Nickname() ].plugin.reset( *plugin );
|
||||
|
||||
return &aTarget.at( aNickname );
|
||||
}
|
||||
else
|
||||
{
|
||||
return tl::unexpected( plugin.error() );
|
||||
}
|
||||
std::lock_guard lock( aMutex );
|
||||
present = aTarget.contains( aNickname ) && aTarget.at( aNickname ).plugin;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
if( !present )
|
||||
{
|
||||
if( auto result = m_manager.GetRow( Type(), aNickname, aScope ) )
|
||||
{
|
||||
const LIBRARY_TABLE_ROW* row = *result;
|
||||
wxLogTrace( traceLibraries, "Library %s (%s) not yet loaded, will attempt...",
|
||||
aNickname, magic_enum::enum_name( aScope ) );
|
||||
|
||||
return &aTarget.at( aNickname );
|
||||
};
|
||||
if( LIBRARY_RESULT<IO_BASE*> plugin = createPlugin( row ); plugin.has_value() )
|
||||
{
|
||||
std::lock_guard lock( aMutex );
|
||||
|
||||
LIBRARY_RESULT<LIB_DATA*> result =
|
||||
tryLoadFromScope( LIBRARY_TABLE_SCOPE::PROJECT, m_libraries, m_libraries_mutex );
|
||||
aTarget[ row->Nickname() ].status.load_status = LOAD_STATUS::LOADING;
|
||||
aTarget[ row->Nickname() ].row = row;
|
||||
aTarget[ row->Nickname() ].plugin.reset( *plugin );
|
||||
|
||||
return &aTarget.at( aNickname );
|
||||
}
|
||||
else
|
||||
{
|
||||
return tl::unexpected( plugin.error() );
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &aTarget.at( aNickname );
|
||||
};
|
||||
|
||||
LIBRARY_RESULT<LIB_DATA*> result = tryLoadFromScope( LIBRARY_TABLE_SCOPE::PROJECT, m_libraries,
|
||||
m_libraries_mutex );
|
||||
|
||||
if( !result.has_value() || *result )
|
||||
return result;
|
||||
|
||||
@@ -19,7 +19,7 @@ PANEL_SYM_LIB_TABLE_BASE::PANEL_SYM_LIB_TABLE_BASE( wxWindow* parent, wxWindowID
|
||||
|
||||
m_notebook = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_CLOSE_ON_ALL_TABS|wxAUI_NB_DEFAULT_STYLE );
|
||||
|
||||
bMainSizer->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );
|
||||
bMainSizer->Add( m_notebook, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
wxBoxSizer* bButtonsSizer;
|
||||
bButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
@@ -65,7 +65,7 @@ PANEL_SYM_LIB_TABLE_BASE::PANEL_SYM_LIB_TABLE_BASE( wxWindow* parent, wxWindowID
|
||||
bButtonsSizer->Add( m_convertLegacy, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
|
||||
bMainSizer->Add( bButtonsSizer, 0, wxEXPAND|wxALL, 3 );
|
||||
bMainSizer->Add( bButtonsSizer, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 3 );
|
||||
|
||||
|
||||
bMainSizer->Add( 0, 5, 0, wxEXPAND, 5 );
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND | wxALL</property>
|
||||
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxAuiNotebook" expanded="true">
|
||||
<property name="BottomDockable">1</property>
|
||||
@@ -124,7 +124,7 @@
|
||||
</object>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">3</property>
|
||||
<property name="flag">wxEXPAND|wxALL</property>
|
||||
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="true">
|
||||
<property name="minimum_size"></property>
|
||||
|
||||
@@ -64,34 +64,43 @@ SCH_IO* SYMBOL_LIBRARY_ADAPTER::schplugin( const LIB_DATA* aRow )
|
||||
}
|
||||
|
||||
|
||||
std::optional<LIB_STATUS> SYMBOL_LIBRARY_ADAPTER::LoadOne( const wxString& aNickname )
|
||||
/// Loads or reloads the given library, if it exists
|
||||
std::optional<LIB_STATUS> SYMBOL_LIBRARY_ADAPTER::LoadOne( LIB_DATA* aLib )
|
||||
{
|
||||
if( LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( aNickname ); result.has_value() )
|
||||
std::lock_guard lock ( aLib->mutex );
|
||||
aLib->status.load_status = LOAD_STATUS::LOADING;
|
||||
|
||||
std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
|
||||
|
||||
try
|
||||
{
|
||||
LIB_DATA* lib = *result;
|
||||
std::lock_guard lock ( lib->mutex );
|
||||
lib->status.load_status = LOAD_STATUS::LOADING;
|
||||
|
||||
std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
|
||||
|
||||
try
|
||||
{
|
||||
wxArrayString dummyList;
|
||||
schplugin( lib )->EnumerateSymbolLib( dummyList, getUri( lib->row ), &options );
|
||||
wxLogTrace( traceLibraries, "Sym: %s: library enumerated %zu items", aNickname, dummyList.size() );
|
||||
lib->status.load_status = LOAD_STATUS::LOADED;
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
{
|
||||
lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
|
||||
lib->status.error = LIBRARY_ERROR( { e.What() } );
|
||||
wxLogTrace( traceLibraries, "Sym: %s: plugin threw exception: %s", aNickname, e.What() );
|
||||
}
|
||||
|
||||
return lib->status;
|
||||
wxArrayString dummyList;
|
||||
schplugin( aLib )->EnumerateSymbolLib( dummyList, getUri( aLib->row ), &options );
|
||||
wxLogTrace( traceLibraries, "Sym: %s: library enumerated %zu items", aLib->row->Nickname(), dummyList.size() );
|
||||
aLib->status.load_status = LOAD_STATUS::LOADED;
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
{
|
||||
aLib->status.load_status = LOAD_STATUS::LOAD_ERROR;
|
||||
aLib->status.error = LIBRARY_ERROR( { e.What() } );
|
||||
wxLogTrace( traceLibraries, "Sym: %s: plugin threw exception: %s", aLib->row->Nickname(), e.What() );
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
return aLib->status;
|
||||
}
|
||||
|
||||
|
||||
std::optional<LIB_STATUS> SYMBOL_LIBRARY_ADAPTER::LoadOne( const wxString& nickname )
|
||||
{
|
||||
LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( nickname );
|
||||
|
||||
if( result.has_value() )
|
||||
return LoadOne( *result );
|
||||
|
||||
return LIB_STATUS{
|
||||
.load_status = LOAD_STATUS::LOAD_ERROR,
|
||||
.error = LIBRARY_ERROR( { result.error() } )
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ public:
|
||||
|
||||
void AsyncLoad() override;
|
||||
|
||||
/// Loads or reloads the given library, if it exists
|
||||
std::optional<LIB_STATUS> LoadOne( LIB_DATA* aLib ) override;
|
||||
|
||||
/// Loads or reloads the given library, if it exists
|
||||
std::optional<LIB_STATUS> LoadOne( const wxString& aNickname );
|
||||
|
||||
|
||||
@@ -97,6 +97,8 @@ public:
|
||||
LIBRARY_MANAGER_ADAPTER* Adapter() const { return m_adapter; }
|
||||
|
||||
protected:
|
||||
bool badCoords( int aRow, int aCol );
|
||||
|
||||
virtual wxString getFileTypes( WX_GRID* aGrid, int aRow ) = 0;
|
||||
|
||||
virtual LIBRARY_TABLE_ROW& at( size_t aIndex );
|
||||
@@ -121,6 +123,7 @@ protected:
|
||||
wxGridCellAttr* m_typesEditor;
|
||||
wxGridCellAttr* m_boolAttr;
|
||||
wxGridCellAttr* m_warningAttr;
|
||||
wxGridCellAttr* m_noStatusAttr;
|
||||
wxGridCellAttr* m_editSettingsAttr;
|
||||
wxGridCellAttr* m_openTableAttr;
|
||||
|
||||
|
||||
@@ -128,9 +128,13 @@ public:
|
||||
/// Notify the adapter that the global library tables have changed
|
||||
void GlobalTablesChanged( std::initializer_list<LIBRARY_TABLE_TYPE> aChangedTables = {} );
|
||||
|
||||
void CheckTableRow( LIBRARY_TABLE_ROW& aRow );
|
||||
|
||||
/// Loads all available libraries for this adapter type in the background
|
||||
virtual void AsyncLoad() = 0;
|
||||
|
||||
virtual std::optional<LIB_STATUS> LoadOne( LIB_DATA* aLib ) = 0;
|
||||
|
||||
/// Returns async load progress between 0.0 and 1.0, or nullopt if load is not in progress
|
||||
std::optional<float> AsyncLoadProgress() const;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ PANEL_FP_LIB_TABLE_BASE::PANEL_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID i
|
||||
|
||||
m_notebook = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_CLOSE_ON_ALL_TABS|wxAUI_NB_DEFAULT_STYLE );
|
||||
|
||||
bMainSizer->Add( m_notebook, 1, wxEXPAND | wxALL, 5 );
|
||||
bMainSizer->Add( m_notebook, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
wxBoxSizer* bButtonsSizer;
|
||||
bButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
|
||||
@@ -65,7 +65,7 @@ PANEL_FP_LIB_TABLE_BASE::PANEL_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID i
|
||||
bButtonsSizer->Add( m_migrate_libs_button, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
|
||||
bMainSizer->Add( bButtonsSizer, 0, wxEXPAND|wxALL, 8 );
|
||||
bMainSizer->Add( bButtonsSizer, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 8 );
|
||||
|
||||
wxStaticText* stPathsLabel;
|
||||
stPathsLabel = new wxStaticText( this, wxID_ANY, _("Available path substitutions:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND | wxALL</property>
|
||||
<property name="flag">wxEXPAND|wxTOP|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxAuiNotebook" expanded="true">
|
||||
<property name="BottomDockable">1</property>
|
||||
@@ -124,7 +124,7 @@
|
||||
</object>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">8</property>
|
||||
<property name="flag">wxEXPAND|wxALL</property>
|
||||
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBoxSizer" expanded="true">
|
||||
<property name="minimum_size"></property>
|
||||
|
||||
@@ -180,34 +180,43 @@ void FOOTPRINT_LIBRARY_ADAPTER::AsyncLoad()
|
||||
}
|
||||
|
||||
|
||||
std::optional<LIB_STATUS> FOOTPRINT_LIBRARY_ADAPTER::LoadOne( const wxString& aNickname )
|
||||
/// Loads or reloads the given library, if it exists
|
||||
std::optional<LIB_STATUS> FOOTPRINT_LIBRARY_ADAPTER::LoadOne( LIB_DATA* aLib )
|
||||
{
|
||||
if( LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( aNickname ); result.has_value() )
|
||||
std::lock_guard lock ( aLib->mutex );
|
||||
aLib->status.load_status = LOAD_STATUS::LOADING;
|
||||
|
||||
std::map<std::string, UTF8> options = aLib->row->GetOptionsMap();
|
||||
|
||||
try
|
||||
{
|
||||
LIB_DATA* lib = *result;
|
||||
std::lock_guard lock ( lib->mutex );
|
||||
lib->status.load_status = LOAD_STATUS::LOADING;
|
||||
|
||||
std::map<std::string, UTF8> options = lib->row->GetOptionsMap();
|
||||
|
||||
try
|
||||
{
|
||||
wxArrayString dummyList;
|
||||
pcbplugin( lib )->FootprintEnumerate( dummyList, getUri( lib->row ), true, &options );
|
||||
wxLogTrace( traceLibraries, "Sym: %s: library enumerated %zu items", aNickname, dummyList.size() );
|
||||
lib->status.load_status = LOAD_STATUS::LOADED;
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
{
|
||||
lib->status.load_status = LOAD_STATUS::LOAD_ERROR;
|
||||
lib->status.error = LIBRARY_ERROR( { e.What() } );
|
||||
wxLogTrace( traceLibraries, "Sym: %s: plugin threw exception: %s", aNickname, e.What() );
|
||||
}
|
||||
|
||||
return lib->status;
|
||||
wxArrayString dummyList;
|
||||
pcbplugin( aLib )->FootprintEnumerate( dummyList, getUri( aLib->row ), false, &options );
|
||||
wxLogTrace( traceLibraries, "Sym: %s: library enumerated %zu items", aLib->row->Nickname(), dummyList.size() );
|
||||
aLib->status.load_status = LOAD_STATUS::LOADED;
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
{
|
||||
aLib->status.load_status = LOAD_STATUS::LOAD_ERROR;
|
||||
aLib->status.error = LIBRARY_ERROR( { e.What() } );
|
||||
wxLogTrace( traceLibraries, "Sym: %s: plugin threw exception: %s", aLib->row->Nickname(), e.What() );
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
return aLib->status;
|
||||
}
|
||||
|
||||
|
||||
std::optional<LIB_STATUS> FOOTPRINT_LIBRARY_ADAPTER::LoadOne( const wxString& nickname )
|
||||
{
|
||||
LIBRARY_RESULT<LIB_DATA*> result = loadIfNeeded( nickname );
|
||||
|
||||
if( result.has_value() )
|
||||
return LoadOne( *result );
|
||||
|
||||
return LIB_STATUS{
|
||||
.load_status = LOAD_STATUS::LOAD_ERROR,
|
||||
.error = LIBRARY_ERROR( { result.error() } )
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ public:
|
||||
|
||||
void AsyncLoad() override;
|
||||
|
||||
/// Loads or reloads the given library, if it exists
|
||||
std::optional<LIB_STATUS> LoadOne( LIB_DATA* aLib ) override;
|
||||
|
||||
/// Loads or reloads the given library, if it exists
|
||||
std::optional<LIB_STATUS> LoadOne( const wxString& aNickname );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user