diff --git a/common/design_block_library_adapter.cpp b/common/design_block_library_adapter.cpp index 741670d568..7b796e684a 100644 --- a/common/design_block_library_adapter.cpp +++ b/common/design_block_library_adapter.cpp @@ -67,8 +67,7 @@ LIBRARY_RESULT 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 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 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& aMap, std::mutex& aMutex ) - { - std::lock_guard lock( aMutex ); - - if( aMap.contains( aLib ) ) + []( const wxString& aLib, std::map& 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 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 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 options = lib->row->GetOptionsMap(); + LIBRARY_RESULT 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_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 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 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 maybeLib = fetchIfLoaded( aNickname ) ) { diff --git a/common/design_block_library_adapter.h b/common/design_block_library_adapter.h index 61f4c5daf4..c01ba44144 100644 --- a/common/design_block_library_adapter.h +++ b/common/design_block_library_adapter.h @@ -42,6 +42,8 @@ public: void AsyncLoad() override; + std::optional LoadOne( LIB_DATA* aLib ) override; + // Currently unused for design blocks std::optional GetLibraryStatus( const wxString& aNickname ) const override { return std::nullopt; } diff --git a/common/dialogs/panel_design_block_lib_table_base.cpp b/common/dialogs/panel_design_block_lib_table_base.cpp index a507a08da8..d441d3f04b 100644 --- a/common/dialogs/panel_design_block_lib_table_base.cpp +++ b/common/dialogs/panel_design_block_lib_table_base.cpp @@ -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 ); diff --git a/common/dialogs/panel_design_block_lib_table_base.fbp b/common/dialogs/panel_design_block_lib_table_base.fbp index ab9fc37686..db5805180c 100644 --- a/common/dialogs/panel_design_block_lib_table_base.fbp +++ b/common/dialogs/panel_design_block_lib_table_base.fbp @@ -62,7 +62,7 @@ none 5 - wxEXPAND | wxALL + wxEXPAND|wxTOP|wxRIGHT|wxLEFT 1 1 @@ -123,7 +123,7 @@ 8 - wxEXPAND|wxALL + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 0 diff --git a/common/lib_table_grid_tricks.cpp b/common/lib_table_grid_tricks.cpp index 6aae6b32d1..3078334d57 100644 --- a/common/lib_table_grid_tricks.cpp +++ b/common/lib_table_grid_tricks.cpp @@ -469,38 +469,19 @@ bool LIB_TABLE_GRID_TRICKS::VerifyTable( WX_GRID* aGrid, std::functionGetValue( 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(); diff --git a/common/libraries/lib_table_grid_data_model.cpp b/common/libraries/lib_table_grid_data_model.cpp index c9a8d8c356..332f176698 100644 --- a/common/libraries/lib_table_grid_data_model.cpp +++ b/common/libraries/lib_table_grid_data_model.cpp @@ -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( 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 error = m_adapter->LibraryError( r.Nickname() ) ) + return error->message; - if( std::optional 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( 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( 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( 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( 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 ); } diff --git a/common/libraries/library_manager.cpp b/common/libraries/library_manager.cpp index a9d5718278..e14001b6c0 100644 --- a/common/libraries/library_manager.cpp +++ b/common/libraries/library_manager.cpp @@ -780,6 +780,36 @@ void LIBRARY_MANAGER_ADAPTER::GlobalTablesChanged( std::initializer_list plugin = createPlugin( &aRow ); + + if( plugin.has_value() ) + { + LIB_DATA lib; + lib.row = &aRow; + lib.plugin.reset( *plugin ); + + std::optional 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 LIBRARY_MANAGER_ADAPTER::fetchIfLoaded( LIBRARY_RESULT LIBRARY_MANAGER_ADAPTER::loadIfNeeded( const wxString& aNickname ) { auto tryLoadFromScope = - [&]( LIBRARY_TABLE_SCOPE aScope, std::map& aTarget, - std::mutex& aMutex ) -> LIBRARY_RESULT - { - bool present = false; - + [&]( LIBRARY_TABLE_SCOPE aScope, std::map& aTarget, + std::mutex& aMutex ) -> LIBRARY_RESULT { - 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 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 plugin = createPlugin( row ); plugin.has_value() ) + { + std::lock_guard lock( aMutex ); - LIBRARY_RESULT 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 result = tryLoadFromScope( LIBRARY_TABLE_SCOPE::PROJECT, m_libraries, + m_libraries_mutex ); if( !result.has_value() || *result ) return result; diff --git a/eeschema/dialogs/panel_sym_lib_table_base.cpp b/eeschema/dialogs/panel_sym_lib_table_base.cpp index 3398d773a6..0d9d9d5df7 100644 --- a/eeschema/dialogs/panel_sym_lib_table_base.cpp +++ b/eeschema/dialogs/panel_sym_lib_table_base.cpp @@ -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 ); diff --git a/eeschema/dialogs/panel_sym_lib_table_base.fbp b/eeschema/dialogs/panel_sym_lib_table_base.fbp index 851baa3582..0fcc93e07f 100644 --- a/eeschema/dialogs/panel_sym_lib_table_base.fbp +++ b/eeschema/dialogs/panel_sym_lib_table_base.fbp @@ -62,7 +62,7 @@ none 5 - wxEXPAND | wxALL + wxEXPAND|wxTOP|wxRIGHT|wxLEFT 1 1 @@ -124,7 +124,7 @@ 3 - wxEXPAND|wxALL + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 0 diff --git a/eeschema/libraries/symbol_library_adapter.cpp b/eeschema/libraries/symbol_library_adapter.cpp index 729c2496cb..6ca8bdc554 100644 --- a/eeschema/libraries/symbol_library_adapter.cpp +++ b/eeschema/libraries/symbol_library_adapter.cpp @@ -64,34 +64,43 @@ SCH_IO* SYMBOL_LIBRARY_ADAPTER::schplugin( const LIB_DATA* aRow ) } -std::optional SYMBOL_LIBRARY_ADAPTER::LoadOne( const wxString& aNickname ) +/// Loads or reloads the given library, if it exists +std::optional SYMBOL_LIBRARY_ADAPTER::LoadOne( LIB_DATA* aLib ) { - if( LIBRARY_RESULT result = loadIfNeeded( aNickname ); result.has_value() ) + std::lock_guard lock ( aLib->mutex ); + aLib->status.load_status = LOAD_STATUS::LOADING; + + std::map options = aLib->row->GetOptionsMap(); + + try { - LIB_DATA* lib = *result; - std::lock_guard lock ( lib->mutex ); - lib->status.load_status = LOAD_STATUS::LOADING; - - std::map 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 SYMBOL_LIBRARY_ADAPTER::LoadOne( const wxString& nickname ) +{ + LIBRARY_RESULT result = loadIfNeeded( nickname ); + + if( result.has_value() ) + return LoadOne( *result ); + + return LIB_STATUS{ + .load_status = LOAD_STATUS::LOAD_ERROR, + .error = LIBRARY_ERROR( { result.error() } ) + }; } diff --git a/eeschema/libraries/symbol_library_adapter.h b/eeschema/libraries/symbol_library_adapter.h index d4e32efbb6..b7deb75706 100644 --- a/eeschema/libraries/symbol_library_adapter.h +++ b/eeschema/libraries/symbol_library_adapter.h @@ -61,6 +61,9 @@ public: void AsyncLoad() override; + /// Loads or reloads the given library, if it exists + std::optional LoadOne( LIB_DATA* aLib ) override; + /// Loads or reloads the given library, if it exists std::optional LoadOne( const wxString& aNickname ); diff --git a/include/lib_table_grid_data_model.h b/include/lib_table_grid_data_model.h index 8d1424b9f0..fcd20b569d 100644 --- a/include/lib_table_grid_data_model.h +++ b/include/lib_table_grid_data_model.h @@ -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; diff --git a/include/libraries/library_manager.h b/include/libraries/library_manager.h index 1b9bc48fd3..dafae550ac 100644 --- a/include/libraries/library_manager.h +++ b/include/libraries/library_manager.h @@ -128,9 +128,13 @@ public: /// Notify the adapter that the global library tables have changed void GlobalTablesChanged( std::initializer_list 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 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 AsyncLoadProgress() const; diff --git a/pcbnew/dialogs/panel_fp_lib_table_base.cpp b/pcbnew/dialogs/panel_fp_lib_table_base.cpp index 6a3d9db6a8..fcf05d71bd 100644 --- a/pcbnew/dialogs/panel_fp_lib_table_base.cpp +++ b/pcbnew/dialogs/panel_fp_lib_table_base.cpp @@ -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 ); diff --git a/pcbnew/dialogs/panel_fp_lib_table_base.fbp b/pcbnew/dialogs/panel_fp_lib_table_base.fbp index 0f87ca7e25..9716c83955 100644 --- a/pcbnew/dialogs/panel_fp_lib_table_base.fbp +++ b/pcbnew/dialogs/panel_fp_lib_table_base.fbp @@ -62,7 +62,7 @@ none 5 - wxEXPAND | wxALL + wxEXPAND|wxTOP|wxRIGHT|wxLEFT 1 1 @@ -124,7 +124,7 @@ 8 - wxEXPAND|wxALL + wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 0 diff --git a/pcbnew/footprint_library_adapter.cpp b/pcbnew/footprint_library_adapter.cpp index 175e605c19..580c624ed3 100644 --- a/pcbnew/footprint_library_adapter.cpp +++ b/pcbnew/footprint_library_adapter.cpp @@ -180,34 +180,43 @@ void FOOTPRINT_LIBRARY_ADAPTER::AsyncLoad() } -std::optional FOOTPRINT_LIBRARY_ADAPTER::LoadOne( const wxString& aNickname ) +/// Loads or reloads the given library, if it exists +std::optional FOOTPRINT_LIBRARY_ADAPTER::LoadOne( LIB_DATA* aLib ) { - if( LIBRARY_RESULT result = loadIfNeeded( aNickname ); result.has_value() ) + std::lock_guard lock ( aLib->mutex ); + aLib->status.load_status = LOAD_STATUS::LOADING; + + std::map options = aLib->row->GetOptionsMap(); + + try { - LIB_DATA* lib = *result; - std::lock_guard lock ( lib->mutex ); - lib->status.load_status = LOAD_STATUS::LOADING; - - std::map 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 FOOTPRINT_LIBRARY_ADAPTER::LoadOne( const wxString& nickname ) +{ + LIBRARY_RESULT result = loadIfNeeded( nickname ); + + if( result.has_value() ) + return LoadOne( *result ); + + return LIB_STATUS{ + .load_status = LOAD_STATUS::LOAD_ERROR, + .error = LIBRARY_ERROR( { result.error() } ) + }; } diff --git a/pcbnew/footprint_library_adapter.h b/pcbnew/footprint_library_adapter.h index 163528ae68..f016bc2907 100644 --- a/pcbnew/footprint_library_adapter.h +++ b/pcbnew/footprint_library_adapter.h @@ -48,6 +48,9 @@ public: void AsyncLoad() override; + /// Loads or reloads the given library, if it exists + std::optional LoadOne( LIB_DATA* aLib ) override; + /// Loads or reloads the given library, if it exists std::optional LoadOne( const wxString& aNickname );