From 58299fc9213b3d2894cd5eb133bf56ef584a5de2 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Wed, 17 Oct 2012 10:12:17 -0500 Subject: [PATCH] more fp_lib_table work --- common/fp_lib_table.cpp | 152 ++++++++++--------------- include/fp_lib_table.h | 137 ++++++++++++---------- pcbnew/dialogs/dialog_fp_lib_table.cpp | 42 ++----- pcbnew/io_mgr.cpp | 36 +++++- pcbnew/io_mgr.h | 6 + pcbnew/pcbnew_config.cpp | 10 ++ 6 files changed, 194 insertions(+), 189 deletions(-) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 2c79b21ee6..3cb01343b0 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -74,18 +74,6 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedRIGHT(); - // (type "TYPE") - in->NeedLEFT(); - - if( ( tok = in->NextTok() ) != T_type ) - in->Expecting( T_type ); - - in->NeedSYMBOLorNUMBER(); - - row.SetType( in->FromUTF8() ); - - in->NeedRIGHT(); - // (uri "FULL_URI") in->NeedLEFT(); @@ -98,6 +86,18 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedRIGHT(); + // (type "TYPE") + in->NeedLEFT(); + + if( ( tok = in->NextTok() ) != T_type ) + in->Expecting( T_type ); + + in->NeedSYMBOLorNUMBER(); + + row.SetType( in->FromUTF8() ); + + in->NeedRIGHT(); + // (options "OPTIONS") in->NeedLEFT(); @@ -142,11 +142,11 @@ void FP_LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const void FP_LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ) { - out->Print( nestLevel, "(lib (name %s)(type %s)(full_uri %s)(options %s))\n", - out->Quotew( nickName ).c_str(), - out->Quotew( type ).c_str(), - out->Quotew( uri ).c_str(), - out->Quotew( options ).c_str() + out->Print( nestLevel, "(lib (name %s)(full_uri %s)(type %s)(options %s))\n", + out->Quotew( GetNickName() ).c_str(), + out->Quotew( GetFullURI() ).c_str(), + out->Quotew( GetType() ).c_str(), + out->Quotew( GetOptions() ).c_str() ); } @@ -178,19 +178,19 @@ std::vector FP_LIB_TABLE::GetLogicalLibs() } -FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aNickName ) const +const FP_LIB_TABLE::ROW* FP_LIB_TABLE::findRow( const wxString& aNickName ) { - // this function must be *super* fast, so therefore should not instantiate - // anything which would require using the heap. - const FP_LIB_TABLE* cur = this; + FP_LIB_TABLE* cur = this; do { + cur->ensureIndex(); + INDEX_CITER it = cur->nickIndex.find( aNickName ); if( it != cur->nickIndex.end() ) { - return (FP_LIB_TABLE::ROW*) &cur->rows[it->second]; // found + return &cur->rows[it->second]; // found } // not found, search fall back table(s), if any @@ -202,7 +202,7 @@ FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aNickName ) const bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace ) { - // this does not need to be super fast. + ensureIndex(); INDEX_CITER it = nickIndex.find( aRow.nickName ); @@ -223,82 +223,50 @@ bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace ) } +const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aLibraryNickName ) + throw( IO_ERROR ) +{ + const ROW* row = findRow( aLibraryNickName ); -#if 0 // will need PLUGIN_RELEASER. + if( !row ) + { + wxString msg = wxString::Format( _("lib table contains no logical lib '%s'" ), + GetChars( aLibraryNickName ) ); + THROW_IO_ERROR( msg ); + } + + return row; +} + + +PLUGIN* FP_LIB_TABLE::PluginFind( const wxString& aLibraryNickName ) + throw( IO_ERROR ) +{ + const ROW* row = FindRow( aLibraryNickName ); + + // row will never be NULL here. + + PLUGIN* plugin = IO_MGR::PluginFind( row->type ); + + return plugin; +} + + +#if 0 // don't know that this is needed yet MODULE* FP_LIB_TABLE::LookupFootprint( const FP_LIB_ID& aFootprintId ) throw( IO_ERROR ) { - PLUGIN* plugin = lookupLib( aFootprintId ); + const ROW* row = FindRow( aFootprintId.GetLibraryNickName() ); - return plugin->FootprintLoad( FROM_UTF8( aFootprintId.GetBaseName().c_str() ), - FROM_UTF8( aFootprintId.GetLogicalLib().c_str() ) ); -} + // row will never be NULL here. + PLUGIN::RELEASER pi( PluginFind( row->type ) ); -PLUGIN* FP_LIB_TABLE::lookupLib( const FP_LIB_ID& aFootprintId ) - throw( IO_ERROR ) -{ - if( aFootprintId.GetLogicalLib().size() ) - { - ROW* row = FindRow( aFootprintId.GetLogicalLib() ); + return pi->FootprintLoad( aLibraryPath->GetFullURI() ), + aFootprintId.GetFootprintName(), - if( !row ) - { - std::string msg = "lib table contains no logical lib '"; - msg += aFootprintId.GetLogicalLib(); - msg += '\''; - THROW_IO_ERROR( msg ); - } - - if( !row->lib ) - { - loadLib( row ); - } - - assert( row->lib ); // fix loadLib() to throw if cannot load - - return row->lib; - } - - std::string msg = "lookupLib() requires logicalLibName"; - THROW_IO_ERROR( msg ); -} - - -void FP_LIB_TABLE::loadLib( ROW* aRow ) throw( IO_ERROR ) -{ - assert( !aRow->lib ); // caller should know better. - - const std::string& type = aRow->GetType(); - - if( !type.compare( "dir" ) ) - { - // @todo Look up plug in here. - } - -/* - else if( !type.compare( "schematic" ) ) - { - // @todo code and load SCHEMATIC_LIB_SOURCE - } - - else if( !type.compare( "subversion" ) ) - { - // @todo code and load SVN_LIB_SOURCE - } - - else if( !type.compare( "http" ) ) - { - // @todo code and load HTTP_LIB_SOURCE - } -*/ - else - { - std::string msg = "cannot load unknown footprint library type: '"; - msg += type; - msg += '\''; - THROW_IO_ERROR( msg ); - } + // fetch a PROPERTIES instance on stack here + row->GetPropertiesFromOptions() + ); } #endif - diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index 0d4904e3b2..ba5d6482e5 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -23,8 +23,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#ifndef _FP_LIB_TABLE_H_ -#define _FP_LIB_TABLE_H_ +#ifndef FP_LIB_TABLE_H_ +#define FP_LIB_TABLE_H_ #include @@ -32,6 +32,7 @@ #include #include +#include class OUTPUTFORMATTER; @@ -97,6 +98,25 @@ public: public: + typedef IO_MGR::PCB_FILE_T LIB_T; + + ROW(){} + + ROW( const wxString& aNick, const wxString& aURI, const wxString& aType, const wxString& aOptions ) : + nickName( aNick ), + uri( aURI ), + options( aOptions ) + { + SetType( aType ); + } + + bool operator==( const ROW& r ) const + { + return nickName==r.nickName && uri==r.uri && type==r.type && options==r.options; + } + + bool operator!=( const ROW& r ) const { return !( *this == r ); } + /** * Function GetNickName * returns the short name of this library table row. @@ -110,9 +130,9 @@ public: * Function GetType * returns the type of LIB represented by this record. */ - const wxString& GetType() const + const wxString GetType() const { - return type; + return IO_MGR::ShowType( type ); } /** @@ -160,7 +180,7 @@ public: */ void SetType( const wxString& aType ) { - type = aType; + type = IO_MGR::EnumFromStr( aType ); } /** @@ -183,14 +203,11 @@ public: } private: - wxString nickName; - wxString type; - wxString uri; - wxString options; - /* - PLUGIN* lib; ///< ownership of the loaded LIB is here - */ + wxString nickName; + wxString uri; + LIB_T type; + wxString options; }; @@ -240,25 +257,6 @@ public: */ void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ); -#if 0 - /** - * Function LookupPart - * finds and loads a MODULE, and parses it. As long as the part is - * accessible in any LIB_SOURCE, opened or not opened, this function - * will find it and load it into its containing LIB, even if that means - * having to open a LIB in this table that was not previously opened. - * - * @param aFootprintId The fully qualified name of the footprint to look up. - * - * @return MODULE* - this will never be NULL, and no ownership is transferred because - * all MODULEs live in LIBs. You only get to point to them in some LIB. If the MODULE - * cannot be found, then an exception is thrown. - * - * @throw IO_ERROR if any problem occurs or if the footprint cannot be found. - */ - MODULE* LookupFootprint( const FP_LIB_ID& aFootprintId ) throw( IO_ERROR ); -#endif - /** * Function GetLogicalLibs @@ -267,10 +265,13 @@ public: */ std::vector GetLogicalLibs(); + + //-------------------------------------------------------- // the returning of a const wxString* tells if not found, but might be too // promiscuous? +#if 0 /** * Function GetURI * returns the full library path from a logical library name. @@ -306,6 +307,7 @@ public: const ROW* row = FindRow( aLogicalLibraryName ); return row ? &row->options : 0; } +#endif //------------------------------------------------------- @@ -315,9 +317,6 @@ public: void Test(); #endif - -protected: // only a table editor can use these - /** * Function InsertRow * adds aRow if it does not already exist or if doReplace is true. If doReplace @@ -330,12 +329,29 @@ protected: // only a table editor can use these */ bool InsertRow( const ROW& aRow, bool doReplace = false ); + /** + * Function PluginFind + * returns a PLUGIN*. Caller should wrap that in a PLUGIN::RELEASER() + * so when it goes out of scope, IO_MGR::PluginRelease() is called. + */ + PLUGIN* PluginFind( const wxString& aLibraryNickName ) throw( IO_ERROR ); + /** * Function FindRow * returns a #ROW* if aNickName is found in this table or in any chained * fallBack table fragment, else NULL. */ - ROW* FindRow( const wxString& aNickName ) const; + const ROW* FindRow( const wxString& aNickName ) throw( IO_ERROR ); + + +protected: + + /** + * Function findRow + * returns a #ROW* if aNickName is found in this table or in any chained + * fallBack table fragment, else NULL. + */ + const ROW* findRow( const wxString& aNickName ); void reindex() { @@ -345,6 +361,15 @@ protected: // only a table editor can use these nickIndex.insert( INDEX_VALUE( it->nickName, it - rows.begin() ) ); } + void ensureIndex() + { + // The dialog lib table editor may not maintain the nickIndex. + // Lazy indexing may be required. To handle lazy indexing, we must enforce + // that "nickIndex" is either empty or accurate, but never inaccurate. + if( !nickIndex.size() ) + reindex(); + } + typedef std::vector ROWS; typedef ROWS::iterator ROWS_ITER; typedef ROWS::const_iterator ROWS_CITER; @@ -364,35 +389,25 @@ protected: // only a table editor can use these }; - -#if 0 // lets see what we need. - /** - * Function lookupLib - * finds or loads a LIB based on @a aLogicalPartID or @a aFallBackLib. - * If the LIB is already loaded then it is returned as is, else it is loaded. - * - * @param aLogicalPartID holds the partName and may also hold the logicalLibName. If - * logicalLibName is empty, then @a aFallBackLib should not be NULL. - * - * @param aFallBackLib is used only if aLogicalPartID has an empty logicalLibName. - * This is for the case when an LPID has no logicalLibName because the LPID is using - * a partName from the same LIB as was the referring content. - * - * @return PLUGIN* - this will never be NULL, and no ownership is transfered because - * all LIBs live in the FP_LIB_TABLEs. You only get to point to them in some FP_LIB_TABLE. - * If the LIB cannot be found, then an exception is thrown. - * - * @throw IO_ERROR if any problem occurs or if the LIB cannot be found or cannot be loaded. - */ - PLUGIN* lookupLib( const FP_LIB_ID& aLogicalPartID ) throw( IO_ERROR ); +#if 0 // I don't think this is going to be needed. /** - * Function loadLib - * loads a LIB using information in @a aRow. Call only if LIB not - * already loaded. + * Function LookupPart + * finds and loads a MODULE, and parses it. As long as the part is + * accessible in any LIB_SOURCE, opened or not opened, this function + * will find it and load it into its containing LIB, even if that means + * having to open a LIB in this table that was not previously opened. + * + * @param aFootprintId The fully qualified name of the footprint to look up. + * + * @return MODULE* - this will never be NULL, and no ownership is transferred because + * all MODULEs live in LIBs. You only get to point to them in some LIB. If the MODULE + * cannot be found, then an exception is thrown. + * + * @throw IO_ERROR if any problem occurs or if the footprint cannot be found. */ - void loadLib( ROW* aRow ) throw( IO_ERROR ); + MODULE* LookupFootprint( const FP_LIB_ID& aFootprintId ) throw( IO_ERROR ); #endif -#endif // _FP_LIB_TABLE_H_ +#endif // FP_LIB_TABLE_H_ diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index 5eef41e731..f02f0f9c1b 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -31,6 +31,11 @@ #include +/** + * Class FP_TBL_MODEL + * mixes in wxGridTableBase into FP_LIB_TABLE so that the latter can be used + * as table within wxGrid. + */ class FP_TBL_MODEL : public wxGridTableBase, public FP_LIB_TABLE { public: @@ -161,6 +166,9 @@ public: */ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE { + typedef FP_LIB_TABLE::ROW ROW; + + //--------------------------------------- void pageChangedHandler( wxAuiNotebookEvent& event ) @@ -228,44 +236,13 @@ public: m_global_model( *aGlobal ), m_project_model( *aProject ) { - /* - GetSizer()->SetSizeHints( this ); - Centre(); - SetAutoLayout( true ); - Layout(); - */ - -#if 1 && defined(DEBUG) - // put some dummy data into table(s) - FP_LIB_TABLE::ROW row; - - row.SetNickName( wxT( "passives" ) ); - row.SetType( wxT( "kicad" ) ); - row.SetFullURI( wxT( "%G/passives" ) ); - row.SetOptions( wxT( "speed=fast,purpose=testing" ) ); - m_global_model.InsertRow( row ); - - row.SetNickName( wxT( "micros" ) ); - row.SetType( wxT( "legacy" ) ); - row.SetFullURI( wxT( "%P/micros" ) ); - row.SetOptions( wxT( "speed=fast,purpose=testing" ) ); - m_global_model.InsertRow( row ); - - row.SetFullURI( wxT( "%P/chips" ) ); - m_project_model.InsertRow( row ); - -#endif - m_global_grid->SetTable( (wxGridTableBase*) &m_global_model ); m_project_grid->SetTable( (wxGridTableBase*) &m_project_model ); - //m_global_grid->AutoSize(); m_global_grid->AutoSizeColumns( false ); - //m_project_grid->AutoSize(); m_project_grid->AutoSizeColumns( false ); - //m_path_subs_grid->AutoSize(); m_path_subs_grid->AutoSizeColumns( false ); } @@ -275,7 +252,8 @@ public: // since the ~wxGrid() wants the wxGridTableBase to still be non-destroyed. // Without this call, the wxGridTableBase objects are destroyed first // (i.e. destructor called) and there is a segfault since wxGridTableBase's vtable - // is then no longer valid. + // is then no longer valid. If ~wxGrid() would not examine a wxGridTableBase that + // it does not own, then this would not be a concern. But it is, since it does. DestroyChildren(); } }; diff --git a/pcbnew/io_mgr.cpp b/pcbnew/io_mgr.cpp index 725b7f0aca..bd113878f7 100644 --- a/pcbnew/io_mgr.cpp +++ b/pcbnew/io_mgr.cpp @@ -79,22 +79,50 @@ void IO_MGR::PluginRelease( PLUGIN* aPlugin ) } -const wxString IO_MGR::ShowType( PCB_FILE_T aFileType ) +const wxString IO_MGR::ShowType( PCB_FILE_T aType ) { - switch( aFileType ) + // keep this function in sync with EnumFromStr() relative to the + // text spellings. If you change the spellings, you will obsolete + // library tables, so don't do change, only additions are ok. + + switch( aType ) { default: - return wxString::Format( _( "Unknown PCB_FILE_T value: %d" ), aFileType ); + return wxString::Format( _( "Unknown PCB_FILE_T value: %d" ), aType ); case LEGACY: - return wxString( wxT( "KiCad Legacy" ) ); + return wxString( wxT( "Legacy" ) ); case KICAD: return wxString( wxT( "KiCad" ) ); + + case EAGLE: + return wxString( wxT( "Eagle" ) ); } } +IO_MGR::PCB_FILE_T IO_MGR::EnumFromStr( const wxString& aType ) +{ + // keep this function in sync with ShowType() relative to the + // text spellings. If you change the spellings, you will obsolete + // library tables, so don't do change, only additions are ok. + + if( aType == wxT( "KiCad" ) ) + return KICAD; + + if( aType == wxT( "Legacy" ) ) + return LEGACY; + + if( aType == wxT( "Eagle" ) ) + return EAGLE; + + // wxASSERT( blow up here ) + + return PCB_FILE_T( -1 ); +} + + const wxString IO_MGR::GetFileExtension( PCB_FILE_T aFileType ) { wxString ext = wxEmptyString; diff --git a/pcbnew/io_mgr.h b/pcbnew/io_mgr.h index 895ddbdb18..086a5bed1f 100644 --- a/pcbnew/io_mgr.h +++ b/pcbnew/io_mgr.h @@ -87,6 +87,12 @@ public: */ static const wxString ShowType( PCB_FILE_T aFileType ); + /** + * Function EnumFromStr + * returns the PCB_FILE_T from the corresponding plugin type name: "kicad", "legacy", etc. + */ + static PCB_FILE_T EnumFromStr( const wxString& aFileType ); + /** * Function GetFileExtension * returns the file extension for \a aFileType. diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 3051347cb6..ce528a3df1 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -84,9 +84,19 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) case ID_PCB_LIB_TABLE_EDIT: { + // scaffolding: dummy up some data into tables, until actual load/save are in place. FP_LIB_TABLE gbl; FP_LIB_TABLE prj; + gbl.InsertRow( FP_LIB_TABLE::ROW( + wxT( "passives" ), wxT( "%G/passives" ), wxT( "KiCad" ), wxT( "speed=fast,purpose=testing" ) ) ); + + gbl.InsertRow( FP_LIB_TABLE::ROW( + wxT( "micros" ), wxT( "%P/micros" ), wxT( "Legacy" ), wxT( "speed=fast,purpose=testing" ) ) ); + + prj.InsertRow( FP_LIB_TABLE::ROW( + wxT( "micros" ), wxT( "%P/potato_chips" ), wxT( "Eagle" ), wxT( "speed=fast,purpose=testing" ) ) ); + int r = InvokePcbLibTableEditor( this, &gbl, &prj ); if( r & 1 )