From 063907211e3653e1d71179cda9de02f88fd0e076 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Sat, 8 Dec 2012 17:58:03 -0600 Subject: [PATCH 1/6] more fp_lib_table work, enhance parser --- common/dsnlexer.cpp | 10 ++- common/fp_lib_table.cpp | 136 +++++++++++++++++++++++++---------- common/fp_lib_table.keywords | 8 +-- common/richio.cpp | 51 ++++++++++--- include/fp_lib_table.h | 124 ++++++++++++++++---------------- include/richio.h | 20 +----- pcbnew/pcb_plot_params.h | 7 +- pcbnew/pcbnew_config.cpp | 38 ++++++++++ 8 files changed, 251 insertions(+), 143 deletions(-) diff --git a/common/dsnlexer.cpp b/common/dsnlexer.cpp index f49d9ec0c7..b2eb6880c9 100644 --- a/common/dsnlexer.cpp +++ b/common/dsnlexer.cpp @@ -304,9 +304,8 @@ void DSNLEXER::Unexpected( int aTok ) throw( IO_ERROR ) void DSNLEXER::Duplicate( int aTok ) throw( IO_ERROR ) { - wxString errText; - - errText.Printf( _("%s is a duplicate"), GetTokenString( aTok ).GetData() ); + wxString errText = wxString::Format( + _("%s is a duplicate"), GetTokenString( aTok ).GetData() ); THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); } @@ -358,9 +357,8 @@ int DSNLEXER::NeedNUMBER( const char* aExpectation ) throw( IO_ERROR ) int tok = NextTok(); if( tok != DSN_NUMBER ) { - wxString errText; - - errText.Printf( _("need a NUMBER for '%s'"), wxString::FromUTF8( aExpectation ).GetData() ); + wxString errText = wxString::Format( + _("need a NUMBER for '%s'"), wxString::FromUTF8( aExpectation ).GetData() ); THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() ); } return tok; diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 3cb01343b0..301d0db680 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -24,6 +24,8 @@ */ +#include // wxExpandEnvVars() + #include #include @@ -45,11 +47,29 @@ FP_LIB_TABLE::FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable ) : void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR ) { - T tok; + /* + (fp_lib_table + (lib (name NICKNAME)(descr DESCRIPTION)(type TYPE)(full_uri FULL_URI)(options OPTIONS)) + : + ) + + Elements after (name) are order independent. + */ + + T tok; + + // This table may be nested within a larger s-expression, or not. + // Allow for parser of that optional outter s-epression to have looked ahead. + if( in->CurTok() != T_fp_lib_table ) + { + in->NeedLEFT(); + if( ( tok = in->NextTok() ) != T_fp_lib_table ) + in->Expecting( T_fp_lib_table ); + } while( ( tok = in->NextTok() ) != T_RIGHT ) { - // (lib (name "LOGICAL")(type "TYPE")(full_uri "FULL_URI")(options "OPTIONS")) + ROW row; // reconstructed for each row in input stream. if( tok == T_EOF ) in->Expecting( T_RIGHT ); @@ -57,10 +77,14 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR if( tok != T_LEFT ) in->Expecting( T_LEFT ); - if( ( tok = in->NextTok() ) != T_fp_lib ) - in->Expecting( T_fp_lib ); + // in case there is a "row integrity" error, tell where later. + int lineNum = in->CurLineNumber(); + int offset = in->CurOffset(); - // (name "LOGICAL_NAME") + if( ( tok = in->NextTok() ) != T_lib ) + in->Expecting( T_lib ); + + // (name LOGICAL_NAME) in->NeedLEFT(); if( ( tok = in->NextTok() ) != T_name ) @@ -68,48 +92,74 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - ROW row; - row.SetNickName( in->FromUTF8() ); in->NeedRIGHT(); - // (uri "FULL_URI") - in->NeedLEFT(); + // After (name), remaining (lib) elements are order independent, and in + // the future, perhaps optional. Flexibility for future changes. - if( ( tok = in->NextTok() ) != T_full_uri ) - in->Expecting( T_full_uri ); + bool sawType = false; + bool sawOpts = false; + bool sawDesc = false; + bool sawUri = false; - in->NeedSYMBOLorNUMBER(); + while( ( tok = in->NextTok() ) != T_RIGHT ) + { + if( tok == T_EOF ) + in->Unexpected( T_EOF ); - row.SetFullURI( in->FromUTF8() ); + if( tok != T_LEFT ) + in->Expecting( T_LEFT ); - in->NeedRIGHT(); + tok = in->NeedSYMBOLorNUMBER(); - // (type "TYPE") - in->NeedLEFT(); + switch( tok ) + { + case T_uri: + if( sawUri ) + in->Duplicate( tok ); + sawUri = true; + in->NeedSYMBOLorNUMBER(); + row.SetFullURI( in->FromUTF8() ); + break; - if( ( tok = in->NextTok() ) != T_type ) + case T_type: + if( sawType ) + in->Duplicate( tok ); + sawType = true; + in->NeedSYMBOLorNUMBER(); + row.SetType( in->FromUTF8() ); + break; + + case T_options: + if( sawOpts ) + in->Duplicate( tok ); + sawOpts = true; + in->NeedSYMBOLorNUMBER(); + row.SetOptions( in->FromUTF8() ); + break; + + case T_descr: + if( sawDesc ) + in->Duplicate( tok ); + sawDesc = true; + in->NeedSYMBOLorNUMBER(); + row.SetDescr( in->FromUTF8() ); + break; + + default: + in->Unexpected( tok ); + } + + in->NeedRIGHT(); + } + + if( !sawType ) in->Expecting( T_type ); - in->NeedSYMBOLorNUMBER(); - - row.SetType( in->FromUTF8() ); - - in->NeedRIGHT(); - - // (options "OPTIONS") - in->NeedLEFT(); - - if( ( tok = in->NextTok() ) != T_options ) - in->Expecting( T_options ); - - in->NeedSYMBOLorNUMBER(); - - row.SetOptions( in->FromUTF8() ); - - in->NeedRIGHT(); - in->NeedRIGHT(); // terminate the (lib..) + if( !sawUri ) + in->Expecting( T_uri ); // all nickNames within this table fragment must be unique, so we do not // use doReplace in InsertRow(). (However a fallBack table can have a @@ -119,9 +169,8 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR { wxString msg = wxString::Format( _( "'%s' is a duplicate footprint library nickName" ), - GetChars( row.nickName ) - ); - THROW_IO_ERROR( msg ); + GetChars( row.nickName ) ); + THROW_PARSE_ERROR( msg, in->CurSource(), in->CurLine(), lineNum, offset ); } } } @@ -142,8 +191,9 @@ 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)(full_uri %s)(type %s)(options %s))\n", + out->Print( nestLevel, "(lib (name %s)(descr %s)(uri %s)(type %s)(options %s))\n", out->Quotew( GetNickName() ).c_str(), + out->Quotew( GetDescr() ).c_str(), out->Quotew( GetFullURI() ).c_str(), out->Quotew( GetType() ).c_str(), out->Quotew( GetOptions() ).c_str() @@ -252,6 +302,14 @@ PLUGIN* FP_LIB_TABLE::PluginFind( const wxString& aLibraryNickName ) } +const wxString FP_LIB_TABLE::ExpandSubtitutions( const wxString aString ) +{ + // We reserve the right to do this another way, but providing our own member + // function. + return wxExpandEnvVars( aString ); +} + + #if 0 // don't know that this is needed yet MODULE* FP_LIB_TABLE::LookupFootprint( const FP_LIB_ID& aFootprintId ) throw( IO_ERROR ) diff --git a/common/fp_lib_table.keywords b/common/fp_lib_table.keywords index 6a678ed707..27b1242e2c 100644 --- a/common/fp_lib_table.keywords +++ b/common/fp_lib_table.keywords @@ -1,9 +1,7 @@ fp_lib_table +lib name type -kicad -legacy -eagle -full_uri +uri options -fp_lib +descr diff --git a/common/richio.cpp b/common/richio.cpp index 19ccb838f7..698c19baed 100644 --- a/common/richio.cpp +++ b/common/richio.cpp @@ -39,27 +39,58 @@ // "richio" after its author, Richard Hollenbeck, aka Dick Hollenbeck. + +void IO_ERROR::init( const char* aThrowersFile, const char* aThrowersLoc, const wxString& aMsg ) +{ + errorText.Printf( IO_FORMAT, aMsg.GetData(), + wxString::FromUTF8( aThrowersFile ).GetData(), + wxString::FromUTF8( aThrowersLoc ).GetData() ); +} + + +void PARSE_ERROR::init( const char* aThrowersFile, const char* aThrowersLoc, + const wxString& aMsg, const wxString& aSource, + const char* aInputLine, + int aLineNumber, int aByteIndex ) +{ + // save inpuLine, lineNumber, and offset for UI (.e.g. Sweet text editor) + inputLine = aInputLine; + lineNumber = aLineNumber; + byteIndex = aByteIndex; + + errorText.Printf( PARSE_FORMAT, aMsg.GetData(), aSource.GetData(), + aLineNumber, aByteIndex, + wxString::FromUTF8( aThrowersFile ).GetData(), + wxString::FromUTF8( aThrowersLoc ).GetData() ); +} + + //----------------------------------------------------------- LINE_READER::LINE_READER( unsigned aMaxLineLength ) { lineNum = 0; - if( aMaxLineLength == 0 ) // caller is goofed up. - aMaxLineLength = LINE_READER_LINE_DEFAULT_MAX; + if( aMaxLineLength == 0 ) + { + line = 0; + } + else + { + maxLineLength = aMaxLineLength; - maxLineLength = aMaxLineLength; + // start at the INITIAL size, expand as needed up to the MAX size in maxLineLength + capacity = LINE_READER_LINE_INITIAL_SIZE; - // start at the INITIAL size, expand as needed up to the MAX size in maxLineLength - capacity = LINE_READER_LINE_INITIAL_SIZE; + // but never go above user's aMaxLineLength, and leave space for trailing nul + if( capacity > aMaxLineLength+1 ) + capacity = aMaxLineLength+1; - // but never go above user's aMaxLineLength, and leave space for trailing nul - if( capacity > aMaxLineLength+1 ) - capacity = aMaxLineLength+1; + line = new char[capacity]; - line = new char[capacity]; + line[0] = '\0'; + } - line[0] = '\0'; length = 0; } diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index 2d23bee00e..b5281d1541 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -41,7 +41,7 @@ class FP_LIB_TABLE_LEXER; /** * Class FP_LIB_TABLE - * holds FP_LIB_TABLE::ROW records, and can be searched based on logical library name. + * holds FP_LIB_TABLE::ROW records (rows), and can be searched based on library nickName. *

* This class owns the footprint library table, which is like fstab in concept and maps * logical library name to the library URI, type, and options. It is heavily based on the SWEET @@ -104,10 +104,12 @@ public: { } - ROW( const wxString& aNick, const wxString& aURI, const wxString& aType, const wxString& aOptions ) : + ROW( const wxString& aNick, const wxString& aURI, const wxString& aType, + const wxString& aOptions, const wxString& aDescr = wxEmptyString ) : nickName( aNick ), uri( aURI ), - options( aOptions ) + options( aOptions ), + description( aDescr ) { SetType( aType ); } @@ -119,42 +121,69 @@ public: bool operator!=( const ROW& r ) const { return !( *this == r ); } + //----------------------------------------------------------- + /** * Function GetNickName * returns the short name of this library table row. */ - const wxString& GetNickName() const - { - return nickName; - } + const wxString& GetNickName() const { return nickName; } + + /** + * Function SetNickName + * changes the logical name of this library, useful for an editor. + */ + void SetNickName( const wxString& aNickName ) { nickName = aNickName; } /** * Function GetType - * returns the type of LIB represented by this record. + * returns the type of LIB represented by this row. */ - const wxString GetType() const - { - return IO_MGR::ShowType( type ); - } + const wxString GetType() const { return IO_MGR::ShowType( type ); } + + /** + * Function SetType + * changes the type represented by this row. + */ + void SetType( const wxString& aType ) { type = IO_MGR::EnumFromStr( aType ); } /** * Function GetFullURI * returns the full location specifying URI for the LIB. */ - const wxString& GetFullURI() const - { - return uri; - } + const wxString& GetFullURI() const { return uri; } + + /** + * Function SetFullURI + * changes the full URI for the library. + */ + void SetFullURI( const wxString& aFullURI ) { uri = aFullURI; } /** * Function GetOptions * returns the options string, which may hold a password or anything else needed to * instantiate the underlying LIB_SOURCE. */ - const wxString& GetOptions() const - { - return options; - } + const wxString& GetOptions() const { return options; } + + /** + * Function SetOptions + */ + void SetOptions( const wxString& aOptions ) { options = aOptions; } + + /** + * Function GetDescr + * returns the description of the library referenced by this row. + */ + const wxString& GetDescr() const { return description; } + + /** + * Function SetDescr + * changes the description of the library referenced by this row. + */ + void SetDescr( const wxString& aDescr ) { description = aDescr; } + + //---------------------------------------------------------- /** * Function Format @@ -167,49 +196,13 @@ public: void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ); - /** - * Function SetNickName - * changes the logical name of this library, useful for an editor. - */ - void SetNickName( const wxString& aNickName ) - { - nickName = aNickName; - } - - /** - * Function SetType - * changes the type represented by this record. - */ - void SetType( const wxString& aType ) - { - type = IO_MGR::EnumFromStr( aType ); - } - - /** - * Function SetFullURI - * changes the full URI for the library, useful from a library table editor. - */ - void SetFullURI( const wxString& aFullURI ) - { - uri = aFullURI; - } - - /** - * Function SetOptions - * changes the options string for this record, and is useful from - * the library table editor. - */ - void SetOptions( const wxString& aOptions ) - { - options = aOptions; - } - private: wxString nickName; wxString uri; LIB_T type; wxString options; + wxString description; }; @@ -219,7 +212,7 @@ public: * @a aFallBackTable. Loading of this table fragment is done by using Parse(). * * @param aFallBackTable is another FP_LIB_TABLE which is searched only when - * a record is not found in this table. No ownership is + * a row is not found in this table. No ownership is * taken of aFallBackTable. */ FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable = NULL ); @@ -249,9 +242,9 @@ public: * *

      * (fp_lib_table
-     *   (lib (name LOGICAL)(type TYPE)(uri FULL_URI)(options OPTIONS))
-     *   (lib (name LOGICAL)(type TYPE)(uri FULL_URI)(options OPTIONS))
-     *   (lib (name LOGICAL)(type TYPE)(uri FULL_URI)(options OPTIONS))
+     *   (lib (name LOGICAL)(descr DESCRIPTION)(uri FULL_URI)(type TYPE)(options OPTIONS))
+     *   (lib (name LOGICAL)(descr DESCRIPTION)(uri FULL_URI)(type TYPE)(options OPTIONS))
+     *   (lib (name LOGICAL)(descr DESCRIPTION)(uri FULL_URI)(type TYPE)(options OPTIONS))
      *  )
      * 
* @@ -363,6 +356,15 @@ public: const ROW* FindRow( const wxString& aNickName ) throw( IO_ERROR ); + /** + * Function ExpandEnvSubsitutions + * replaces any environment variable references with their values and is + * here to fully embellish the ROW::uri in a platform independent way. + * This enables (fp_lib_table)s to have platform dependent environment + * variables in them, allowing for a uniform table across platforms. + */ + static const wxString ExpandSubtitutions( const wxString aString ); + protected: /** diff --git a/include/richio.h b/include/richio.h index 14411aee4d..0a322eca0a 100644 --- a/include/richio.h +++ b/include/richio.h @@ -115,12 +115,7 @@ struct IO_ERROR // : std::exception init( aThrowersFile, aThrowersLoc, wxString( aMsg ) ); } - void init( const char* aThrowersFile, const char* aThrowersLoc, const wxString& aMsg ) - { - errorText.Printf( IO_FORMAT, aMsg.GetData(), - wxString::FromUTF8( aThrowersFile ).GetData(), - wxString::FromUTF8( aThrowersLoc ).GetData() ); - } + void init( const char* aThrowersFile, const char* aThrowersLoc, const wxString& aMsg ); IO_ERROR() {} @@ -165,18 +160,7 @@ struct PARSE_ERROR : public IO_ERROR void init( const char* aThrowersFile, const char* aThrowersLoc, const wxString& aMsg, const wxString& aSource, const char* aInputLine, - int aLineNumber, int aByteIndex ) - { - // save inpuLine, lineNumber, and offset for UI (.e.g. Sweet text editor) - inputLine = aInputLine; - lineNumber = aLineNumber; - byteIndex = aByteIndex; - - errorText.Printf( PARSE_FORMAT, aMsg.GetData(), aSource.GetData(), - aLineNumber, aByteIndex, - wxString::FromUTF8( aThrowersFile ).GetData(), - wxString::FromUTF8( aThrowersLoc ).GetData() ); - } + int aLineNumber, int aByteIndex ); ~PARSE_ERROR() throw ( /*none*/ ){} }; diff --git a/pcbnew/pcb_plot_params.h b/pcbnew/pcb_plot_params.h index bc316d4e59..77d5890788 100644 --- a/pcbnew/pcb_plot_params.h +++ b/pcbnew/pcb_plot_params.h @@ -188,13 +188,13 @@ public: bool operator==( const PCB_PLOT_PARAMS &aPcbPlotParams ) const; bool operator!=( const PCB_PLOT_PARAMS &aPcbPlotParams ) const; - void SetColor( EDA_COLOR_T aVal ) { m_color = aVal; } + void SetColor( EDA_COLOR_T aVal ) { m_color = aVal; } EDA_COLOR_T GetColor() const { return m_color; } - void SetReferenceColor( EDA_COLOR_T aVal ) { m_referenceColor = aVal; } + void SetReferenceColor( EDA_COLOR_T aVal ) { m_referenceColor = aVal; } EDA_COLOR_T GetReferenceColor() const { return m_referenceColor; } - void SetValueColor( EDA_COLOR_T aVal ) { m_valueColor = aVal; } + void SetValueColor( EDA_COLOR_T aVal ) { m_valueColor = aVal; } EDA_COLOR_T GetValueColor() const { return m_valueColor; } void SetTextMode( PlotTextMode aVal ) { m_textMode = aVal; } @@ -292,5 +292,4 @@ public: */ extern int g_DrawDefaultLineThickness; - #endif // PCB_PLOT_PARAMS_H_ diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 8930e593dc..6f7ada1238 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -45,6 +45,10 @@ #include #include +#if defined(DEBUG) + #include +#endif + #include #include #include @@ -88,6 +92,39 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) FP_LIB_TABLE gbl; FP_LIB_TABLE prj; +#if defined(DEBUG) + FP_LIB_TABLE_LEXER glex( + "(fp_lib_table\n" + " (lib (name passives)(descr \"Demo Lib\")(type KiCad)(uri ${KISFP}/passives.pretty))\n" + " (lib (name micros)(descr \"Small stuff\")(type Legacy)(uri ${KISFP}/passives.mod)(options \"op1=2\"))\n" + " (lib (name chips)(descr \"Potatoe chips\")(type Eagle)(uri /opt/eagle-6.2.0/lbr/con-amp-micromatch.lbr))\n" + ")", wxT( "gbl" ) ); + + FP_LIB_TABLE_LEXER plex( + "(fp_lib_table\n" + " (lib (name passives)(descr \"Demo Lib\")(type KiCad)(uri ${KIUFP}/passives.pretty))\n" + " (lib (name micros)(descr \"Small stuff\")(type Legacy)(uri ${KIUFP}/micros.mod)(options \"op1=2\"))\n" + " (lib (name chips)(descr \"Potatoe chips\")(type Eagle)(uri /opt/eagle-6.2.0/lbr/con-amp-micromatch.lbr))\n" + ")", wxT( "prj" ) ); + + try + { + gbl.Parse( &glex ); + prj.Parse( &plex ); + } + /* PARSE_ERROR is an IO_ERROR, handle them the same for now. + catch( PARSE_ERROR pe ) + { + DisplayError( this, pe.errorText ); + break; + } + */ + catch( IO_ERROR ioe ) + { + DisplayError( this, ioe.errorText ); + break; + } +#else gbl.InsertRow( FP_LIB_TABLE::ROW( wxT( "passives" ), wxT( "%G/passives" ), wxT( "KiCad" ), wxT( "speed=fast,purpose=testing" ) ) ); @@ -96,6 +133,7 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) prj.InsertRow( FP_LIB_TABLE::ROW( wxT( "micros" ), wxT( "%P/potato_chips" ), wxT( "Eagle" ), wxT( "speed=fast,purpose=testing" ) ) ); +#endif int r = InvokePcbLibTableEditor( this, &gbl, &prj ); From 9a806749ea4b26ec92cc8abdeeea4f951d884fcc Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Sat, 8 Dec 2012 23:34:12 -0600 Subject: [PATCH 2/6] change spelling to jive with my email on developers list --- common/fp_lib_table.cpp | 2 +- pcbnew/pcbnew_config.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 301d0db680..1129146a33 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -304,7 +304,7 @@ PLUGIN* FP_LIB_TABLE::PluginFind( const wxString& aLibraryNickName ) const wxString FP_LIB_TABLE::ExpandSubtitutions( const wxString aString ) { - // We reserve the right to do this another way, but providing our own member + // We reserve the right to do this another way, by providing our own member // function. return wxExpandEnvVars( aString ); } diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 6f7ada1238..bc9fce26fa 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -95,15 +95,15 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) #if defined(DEBUG) FP_LIB_TABLE_LEXER glex( "(fp_lib_table\n" - " (lib (name passives)(descr \"Demo Lib\")(type KiCad)(uri ${KISFP}/passives.pretty))\n" - " (lib (name micros)(descr \"Small stuff\")(type Legacy)(uri ${KISFP}/passives.mod)(options \"op1=2\"))\n" + " (lib (name passives)(descr \"R/C Lib\")(type KiCad)(uri ${KISYSMODS}/passives.pretty))\n" + " (lib (name micros)(descr \"Small stuff\")(type Legacy)(uri ${KISYSMODS}/passives.mod)(options \"op1=2\"))\n" " (lib (name chips)(descr \"Potatoe chips\")(type Eagle)(uri /opt/eagle-6.2.0/lbr/con-amp-micromatch.lbr))\n" ")", wxT( "gbl" ) ); FP_LIB_TABLE_LEXER plex( "(fp_lib_table\n" - " (lib (name passives)(descr \"Demo Lib\")(type KiCad)(uri ${KIUFP}/passives.pretty))\n" - " (lib (name micros)(descr \"Small stuff\")(type Legacy)(uri ${KIUFP}/micros.mod)(options \"op1=2\"))\n" + " (lib (name passives)(descr \"Demo Lib\")(type KiCad)(uri ${KIUSRMODS}/passives.pretty))\n" + " (lib (name micros)(descr \"Small stuff\")(type Legacy)(uri ${KIUSRMODS}/micros.mod)(options \"op1=2\"))\n" " (lib (name chips)(descr \"Potatoe chips\")(type Eagle)(uri /opt/eagle-6.2.0/lbr/con-amp-micromatch.lbr))\n" ")", wxT( "prj" ) ); From f477464f77b4066939f917cf5efd69a1e83a5157 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Sun, 9 Dec 2012 14:51:42 -0600 Subject: [PATCH 3/6] embellish fp_lib_table editor with beginnings of cut, copy, paste --- common/fp_lib_table.cpp | 14 +- pcbnew/dialogs/dialog_fp_lib_table.cpp | 224 +++++++++++++++++--- pcbnew/dialogs/dialog_fp_lib_table_base.cpp | 20 +- pcbnew/dialogs/dialog_fp_lib_table_base.fbp | 20 +- pcbnew/dialogs/dialog_fp_lib_table_base.h | 4 + 5 files changed, 237 insertions(+), 45 deletions(-) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 1129146a33..e35cda8809 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -59,7 +59,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR T tok; // This table may be nested within a larger s-expression, or not. - // Allow for parser of that optional outter s-epression to have looked ahead. + // Allow for parser of that optional containing s-epression to have looked ahead. if( in->CurTok() != T_fp_lib_table ) { in->NeedLEFT(); @@ -84,7 +84,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR if( ( tok = in->NextTok() ) != T_lib ) in->Expecting( T_lib ); - // (name LOGICAL_NAME) + // (name NICKNAME) in->NeedLEFT(); if( ( tok = in->NextTok() ) != T_name ) @@ -97,7 +97,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedRIGHT(); // After (name), remaining (lib) elements are order independent, and in - // the future, perhaps optional. Flexibility for future changes. + // some cases optional. bool sawType = false; bool sawOpts = false; @@ -191,12 +191,12 @@ 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)(descr %s)(uri %s)(type %s)(options %s))\n", + out->Print( nestLevel, "(lib (name %s)(type %s)(uri %s)(options %s)(descr %s))\n", out->Quotew( GetNickName() ).c_str(), - out->Quotew( GetDescr() ).c_str(), - out->Quotew( GetFullURI() ).c_str(), out->Quotew( GetType() ).c_str(), - out->Quotew( GetOptions() ).c_str() + out->Quotew( GetFullURI() ).c_str(), + out->Quotew( GetOptions() ).c_str(), + out->Quotew( GetDescr() ).c_str() ); } diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index b8fadde2c3..1e669d4ba7 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -28,7 +28,8 @@ #include #include #include - +#include +#include /** * Class FP_TBL_MODEL @@ -39,6 +40,16 @@ class FP_TBL_MODEL : public wxGridTableBase, public FP_LIB_TABLE { public: + enum COL_ORDER // grid column order, established here by this sequence + { + COL_NICKNAME, + COL_URI, + COL_TYPE, + COL_OPTIONS, + COL_DESCR, + COL_COUNT // keep as last + }; + /** * Constructor FP_TBL_MODEL * is a copy constructor that builds a wxGridTableBase (table model) by wrapping @@ -52,7 +63,7 @@ public: //------------------------------------------------ int GetNumberRows () { return rows.size(); } - int GetNumberCols () { return 4; } + int GetNumberCols () { return COL_COUNT; } wxString GetValue( int aRow, int aCol ) { @@ -62,10 +73,11 @@ public: switch( aCol ) { - case 0: return r.GetNickName(); - case 1: return r.GetFullURI(); - case 2: return r.GetType(); - case 3: return r.GetOptions(); + case COL_NICKNAME: return r.GetNickName(); + case COL_URI: return r.GetFullURI(); + case COL_TYPE: return r.GetType(); + case COL_OPTIONS: return r.GetOptions(); + case COL_DESCR: return r.GetDescr(); default: ; // fall thru to wxEmptyString } @@ -82,10 +94,11 @@ public: switch( aCol ) { - case 0: r.SetNickName( aValue ); break; - case 1: r.SetFullURI( aValue ); break; - case 2: r.SetType( aValue ); break; - case 3: r.SetOptions( aValue ); break; + case COL_NICKNAME: r.SetNickName( aValue ); break; + case COL_URI: r.SetFullURI( aValue ); break; + case COL_TYPE: r.SetType( aValue ); break; + case COL_OPTIONS: r.SetOptions( aValue ); break; + case COL_DESCR: r.SetDescr( aValue ); break; } } } @@ -169,19 +182,24 @@ public: { switch( aCol ) { - case 0: return _( "Nickname" ); - case 1: return _( "Library Path" ); - case 2: return _( "Plugin" ); - case 3: return _( "Options" ); - default: return wxEmptyString; + case COL_NICKNAME: return _( "Nickname" ); + case COL_URI: return _( "Library Path" ); + case COL_TYPE: return _( "Plugin" ); + case COL_OPTIONS: return _( "Options" ); + case COL_DESCR: return _( "Description" ); + default: return wxEmptyString; } } //----------------------------------------------- - }; +// It works for table data on clipboard for an excell spreadsheet, +// why not us too for now. +#define COL_SEP wxT( '\t' ) +#define ROW_SEP wxT( '\n' ) + /** * Class DIALOG_FP_LIB_TABLE @@ -192,19 +210,31 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE { typedef FP_LIB_TABLE::ROW ROW; - /* row & col "selection" acquisition, not currently used but works. + enum + { + ID_CUT, // = wxID_HIGHEST + 1, + ID_COPY, + ID_PASTE, + }; + + // row & col "selection" acquisition // selected area by cell coordinate and count int selRowStart; int selColStart; int selRowCount; int selColCount; - /// Gets the selected area into a sensible rectable of sel{Row,Col}{Start,Count} above. + /// Gets the selected area into a sensible rectangle of sel{Row,Col}{Start,Count} above. void getSelectedArea() { wxGridCellCoordsArray topLeft = m_cur_grid->GetSelectionBlockTopLeft(); wxGridCellCoordsArray botRight = m_cur_grid->GetSelectionBlockBottomRight(); + wxArrayInt cols = m_cur_grid->GetSelectedCols(); + wxArrayInt rows = m_cur_grid->GetSelectedRows(); + + D(printf("topLeft.Count():%zd botRight:Count():%zd\n", topLeft.Count(), botRight.Count() );) + if( topLeft.Count() && botRight.Count() ) { selRowStart = topLeft[0].GetRow(); @@ -213,6 +243,20 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE selRowCount = botRight[0].GetRow() - selRowStart + 1; selColCount = botRight[0].GetCol() - selColStart + 1; } + else if( cols.Count() ) + { + selColStart = cols[0]; + selColCount = cols.Count(); + selRowStart = 0; + selRowCount = m_cur_grid->GetNumberRows(); + } + else if( rows.Count() ) + { + selColStart = 0; + selColCount = m_cur_grid->GetNumberCols(); + selRowStart = rows[0]; + selRowCount = rows.Count(); + } else { selRowStart = -1; @@ -221,19 +265,113 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE selColCount = 0; } - D(printf("selRowStart:%d selColStart:%d selRowCount:%d selColCount:%d\n", - selRowStart, selColStart, selRowCount, selColCount );) + // D(printf("selRowStart:%d selColStart:%d selRowCount:%d selColCount:%d\n", selRowStart, selColStart, selRowCount, selColCount );) + } + + void rightClickCellPopupMenu() + { + wxMenu menu; + + menu.Append( ID_CUT, _( "Cut" ), _( "Clear selected cells" ) ); + menu.Append( ID_COPY, _( "Copy" ), _( "Copy selected cells to clipboard" ) ); + menu.Append( ID_PASTE, _( "Paste" ), _( "Paste clipboard cells to matrix at current cell" ) ); + + getSelectedArea(); + + // if nothing is selected, diable cut and copy. + if( !selRowCount && !selColCount ) + { + menu.Enable( ID_CUT, false ); + menu.Enable( ID_COPY, false ); + } + + // if there is no current cell cursor, disable paste. + if( m_cur_row == -1 || m_cur_col == -1 ) + menu.Enable( ID_PASTE, false ); + + PopupMenu( &menu ); + + // passOnFocus(); + } + + // the user clicked on a popup menu choice: + void onPopupSelection( wxCommandEvent& event ) + { + int menuId = event.GetId(); + + // assume getSelectedArea() was called by rightClickPopupMenu() and there's + // no way to have gotten here without that having been called. + + switch( menuId ) + { + case ID_CUT: + case ID_COPY: + if( wxTheClipboard->Open() ) + { + wxGridTableBase* tbl = m_cur_grid->GetTable(); + wxString txt; + + for( int row = selRowStart; row < selRowStart + selRowCount; ++row ) + { + for( int col = selColStart; col < selColStart + selColCount; ++col ) + { + txt += tbl->GetValue( row, col ); + + if( col < selColStart + selColCount - 1 ) // that was not last column + txt += COL_SEP; + + if( menuId == ID_CUT ) + tbl->SetValue( row, col, wxEmptyString ); + } + txt += ROW_SEP; + } + + wxTheClipboard->SetData( new wxTextDataObject( txt ) ); + wxTheClipboard->Close(); + m_cur_grid->ForceRefresh(); + } + break; + + case ID_PASTE: + D(printf( "paste\n" );) + if( wxTheClipboard->Open() ) + { + if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) + { + wxGridTableBase* tbl = m_cur_grid->GetTable(); + wxTextDataObject data; + + wxTheClipboard->GetData( data ); + + wxStringTokenizer rows( data.GetText(), ROW_SEP, wxTOKEN_RET_EMPTY ); + + for( int row = m_cur_row; rows.HasMoreTokens(); ++row ) + { + wxString rowTxt = rows.GetNextToken(); + + wxStringTokenizer cols( rowTxt, COL_SEP, wxTOKEN_RET_EMPTY ); + + for( int col = m_cur_col; cols.HasMoreTokens(); ++col ) + { + wxString cellTxt = cols.GetNextToken(); + tbl->SetValue( row, col, cellTxt ); + } + } + } + + wxTheClipboard->Close(); + m_cur_grid->ForceRefresh(); + } + break; + } } - */ //--------------------------------------- void pageChangedHandler( wxAuiNotebookEvent& event ) { int pageNdx = m_auinotebook->GetSelection(); - m_cur_grid = pageNdx==0 ? m_global_grid : m_project_grid; - - D(printf("%s cur_grid is %s\n", __func__, pageNdx==0 ? "global" : "project" );) + m_cur_grid = ( pageNdx == 0 ) ? m_global_grid : m_project_grid; } void appendRowHandler( wxMouseEvent& event ) @@ -336,8 +474,33 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE EndModal( dialogRet ); } - //-------------------------------------- + void onGridCellLeftClick( wxGridEvent& event ) + { + event.Skip(); + } + void onGridCellLeftDClick( wxGridEvent& event ) + { + event.Skip(); + } + + void onGridCellRightClick( wxGridEvent& event ) + { + rightClickCellPopupMenu(); + } + + void onGridCmdSelectCell( wxGridEvent& event ) + { + m_cur_row = event.GetRow(); + m_cur_col = event.GetCol(); + + D(printf("change cursor(%d,%d)\n", m_cur_row, m_cur_col );) + + // somebody else wants this + event.Skip(); + } + + //-------------------------------------- // caller's tables are modified only on OK button. FP_LIB_TABLE* m_global; @@ -349,6 +512,10 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE wxGrid* m_cur_grid; ///< changed based on tab choice + // wxGrid makes it difficult to know if the cursor is yet visible, + // use this to solve that, initial values are -1 + int m_cur_row; ///< cursor position + int m_cur_col; public: DIALOG_FP_LIB_TABLE( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) : @@ -356,7 +523,9 @@ public: m_global( aGlobal ), m_project( aProject ), m_global_model( *aGlobal ), - m_project_model( *aProject ) + m_project_model( *aProject ), + m_cur_row( -1 ), + m_cur_col( -1 ) { m_global_grid->SetTable( (wxGridTableBase*) &m_global_model ); m_project_grid->SetTable( (wxGridTableBase*) &m_project_model ); @@ -367,6 +536,9 @@ public: m_path_subs_grid->AutoSizeColumns( false ); + Connect( ID_CUT, ID_PASTE, wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler( DIALOG_FP_LIB_TABLE::onPopupSelection ), NULL, this ); + // fire pageChangedHandler() so m_cur_grid gets set wxAuiNotebookEvent uneventful; pageChangedHandler( uneventful ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp index 6844652cf5..5e525ecd3f 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp @@ -34,7 +34,7 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_global_grid = new wxGrid( m_global_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid - m_global_grid->CreateGrid( 1, 4 ); + m_global_grid->CreateGrid( 1, 5 ); m_global_grid->EnableEditing( true ); m_global_grid->EnableGridLines( true ); m_global_grid->EnableDragGridSize( true ); @@ -70,7 +70,7 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_project_grid = new wxGrid( m_project_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid - m_project_grid->CreateGrid( 1, 4 ); + m_project_grid->CreateGrid( 1, 5 ); m_project_grid->EnableEditing( true ); m_project_grid->EnableGridLines( true ); m_project_grid->EnableDragGridSize( true ); @@ -199,6 +199,14 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID // Connect Events m_auinotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( DIALOG_FP_LIB_TABLE_BASE::pageChangedHandler ), NULL, this ); + m_global_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); + m_global_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); + m_global_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); + m_global_grid->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); + m_project_grid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); + m_project_grid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); + m_project_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); + m_project_grid->Connect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); m_append_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::appendRowHandler ), NULL, this ); m_delete_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::deleteRowHandler ), NULL, this ); m_move_up_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::moveUpHandler ), NULL, this ); @@ -211,6 +219,14 @@ DIALOG_FP_LIB_TABLE_BASE::~DIALOG_FP_LIB_TABLE_BASE() { // Disconnect Events m_auinotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( DIALOG_FP_LIB_TABLE_BASE::pageChangedHandler ), NULL, this ); + m_global_grid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); + m_global_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); + m_global_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); + m_global_grid->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); + m_project_grid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftClick ), NULL, this ); + m_project_grid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellLeftDClick ), NULL, this ); + m_project_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCellRightClick ), NULL, this ); + m_project_grid->Disconnect( wxEVT_GRID_SELECT_CELL, wxGridEventHandler( DIALOG_FP_LIB_TABLE_BASE::onGridCmdSelectCell ), NULL, this ); m_append_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::appendRowHandler ), NULL, this ); m_delete_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::deleteRowHandler ), NULL, this ); m_move_up_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::moveUpHandler ), NULL, this ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp index be77cf4205..79bdad58e7 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp @@ -464,7 +464,7 @@ 30 wxALIGN_CENTRE - 4 + 5 1 @@ -524,9 +524,9 @@ - - - + onGridCellLeftClick + onGridCellLeftDClick + onGridCellRightClick @@ -543,7 +543,7 @@ - + onGridCmdSelectCell @@ -693,7 +693,7 @@ 30 wxALIGN_CENTRE - 4 + 5 1 @@ -753,9 +753,9 @@ - - - + onGridCellLeftClick + onGridCellLeftDClick + onGridCellRightClick @@ -772,7 +772,7 @@ - + onGridCmdSelectCell diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.h b/pcbnew/dialogs/dialog_fp_lib_table_base.h index 3156b1cdf5..44ef78ef8a 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.h +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.h @@ -61,6 +61,10 @@ class DIALOG_FP_LIB_TABLE_BASE : public DIALOG_SHIM // Virtual event handlers, overide them in your derived class virtual void pageChangedHandler( wxAuiNotebookEvent& event ) { event.Skip(); } + virtual void onGridCellLeftClick( wxGridEvent& event ) { event.Skip(); } + virtual void onGridCellLeftDClick( wxGridEvent& event ) { event.Skip(); } + virtual void onGridCellRightClick( wxGridEvent& event ) { event.Skip(); } + virtual void onGridCmdSelectCell( wxGridEvent& event ) { event.Skip(); } virtual void appendRowHandler( wxMouseEvent& event ) { event.Skip(); } virtual void deleteRowHandler( wxMouseEvent& event ) { event.Skip(); } virtual void moveUpHandler( wxMouseEvent& event ) { event.Skip(); } From ee48de67447f2432807e5c2cd97860498f0e6432 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Sun, 9 Dec 2012 14:53:46 -0600 Subject: [PATCH 4/6] note that the clipboard format is spreadsheet compatible --- pcbnew/dialogs/dialog_fp_lib_table.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index 1e669d4ba7..3a3b07ccff 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -306,6 +306,7 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE { case ID_CUT: case ID_COPY: + // this format is compatible with most spreadsheets if( wxTheClipboard->Open() ) { wxGridTableBase* tbl = m_cur_grid->GetTable(); @@ -334,6 +335,7 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE case ID_PASTE: D(printf( "paste\n" );) + // assume format came from a spreadsheet or us. if( wxTheClipboard->Open() ) { if( wxTheClipboard->IsSupported( wxDF_TEXT ) ) From 75072f4330990e7486a2c0a6d373126767eb4274 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Thu, 20 Dec 2012 23:29:40 -0600 Subject: [PATCH 5/6] extend fp_lib_table on multiple row paste --- pcbnew/dialogs/dialog_fp_lib_table.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index 3a3b07ccff..711b4f17f4 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -347,6 +347,13 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE wxStringTokenizer rows( data.GetText(), ROW_SEP, wxTOKEN_RET_EMPTY ); + // if clipboard rows would extend paste end of current table size... + if( int( rows.CountTokens() ) > tbl->GetNumberRows() - m_cur_row ) + { + int newRowsNeeded = rows.CountTokens() - ( tbl->GetNumberRows() - m_cur_row ); + tbl->AppendRows( newRowsNeeded ); + } + for( int row = m_cur_row; rows.HasMoreTokens(); ++row ) { wxString rowTxt = rows.GetNextToken(); From 8fd0c322cd19fb6807e761d5a566ff7f005e0970 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Sun, 20 Jan 2013 21:12:16 -0600 Subject: [PATCH 6/6] more fp lib table work --- pcbnew/dialogs/dialog_fp_lib_table.cpp | 142 ++++++++++++++++++-- pcbnew/dialogs/dialog_fp_lib_table_base.cpp | 8 +- pcbnew/dialogs/dialog_fp_lib_table_base.fbp | 10 +- pcbnew/dialogs/dialog_fp_lib_table_base.h | 4 +- pcbnew/io_mgr.h | 2 + pcbnew/pcbnew_config.cpp | 35 ++--- 6 files changed, 161 insertions(+), 40 deletions(-) diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index 711b4f17f4..1dbae2af63 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -24,12 +24,27 @@ */ +/* TODO: + +*) Check for duplicate nicknames per table + +*) Grab text from any pending ChoiceEditor when OK button pressed. + +*) Test wxRE_ADVANCED on Windows. + +*/ + + + #include #include #include #include #include #include +#include +#include +#include /** * Class FP_TBL_MODEL @@ -184,18 +199,32 @@ public: { case COL_NICKNAME: return _( "Nickname" ); case COL_URI: return _( "Library Path" ); - case COL_TYPE: return _( "Plugin" ); + + // keep this text fairly long so column is sized wide enough + case COL_TYPE: return _( "Plugin Type" ); case COL_OPTIONS: return _( "Options" ); case COL_DESCR: return _( "Description" ); default: return wxEmptyString; } } + /* + wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind ) const // overload + { + if( aCol != COL_TYPE ) + return wxGridTableBase::GetAttr( aRow, aCol, aKind ); + else + { + + } + } + */ + //----------------------------------------------- }; -// It works for table data on clipboard for an excell spreadsheet, +// It works for table data on clipboard for an Excell spreadsheet, // why not us too for now. #define COL_SEP wxT( '\t' ) #define ROW_SEP wxT( '\n' ) @@ -509,6 +538,71 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE event.Skip(); } + /// Populate the readonly environment variable table with names and values + /// by examining all the full_uri columns. + void populateEnvironReadOnlyTable() + { + wxRegEx re( wxT( ".*?\\$\\{(.+?)\\}.*?" ), wxRE_ADVANCED ); + wxASSERT( re.IsValid() ); // wxRE_ADVANCED is required. + + std::set< wxString > unique; + typedef std::set::const_iterator SET_CITER; + + m_path_subs_grid->DeleteRows( 0, m_path_subs_grid->GetNumberRows() ); + + int gblRowCount = m_global_model.GetNumberRows(); + int prjRowCount = m_project_model.GetNumberRows(); + int row; + + for( row = 0; row < gblRowCount; ++row ) + { + wxString uri = m_global_model.GetValue( row, FP_TBL_MODEL::COL_URI ); + + while( re.Matches( uri ) ) + { + wxString envvar = re.GetMatch( uri, 1 ); + + // ignore duplicates + unique.insert( envvar ); + + // delete the last match and search again + uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString ); + } + } + + for( row = 0; row < prjRowCount; ++row ) + { + wxString uri = m_project_model.GetValue( row, FP_TBL_MODEL::COL_URI ); + + while( re.Matches( uri ) ) + { + wxString envvar = re.GetMatch( uri, 1 ); + + // ignore duplicates + unique.insert( envvar ); + + // delete the last match and search again + uri.Replace( re.GetMatch( uri, 0 ), wxEmptyString ); + } + } + + m_path_subs_grid->AppendRows( unique.size() ); + + row = 0; + for( SET_CITER it = unique.begin(); it != unique.end(); ++it, ++row ) + { + wxString evName = *it; + wxString evValue; + + m_path_subs_grid->SetCellValue( row, 0, evName ); + + if( wxGetEnv( evName, &evValue ) ) + m_path_subs_grid->SetCellValue( row, 1, evValue ); + } + + m_path_subs_grid->AutoSizeColumns(); + } + //-------------------------------------- // caller's tables are modified only on OK button. @@ -540,14 +634,38 @@ public: m_project_grid->SetTable( (wxGridTableBase*) &m_project_model ); m_global_grid->AutoSizeColumns( false ); - m_project_grid->AutoSizeColumns( false ); - m_path_subs_grid->AutoSizeColumns( false ); + wxArrayString choices; + choices.Add( IO_MGR::ShowType( IO_MGR::KICAD ) ); + choices.Add( IO_MGR::ShowType( IO_MGR::LEGACY ) ); + choices.Add( IO_MGR::ShowType( IO_MGR::EAGLE ) ); + //choices.Add( IO_MGR::ShowType( IO_MGR::GEDA_PCB ) ); + + wxGridCellAttr* attr; + + attr = new wxGridCellAttr; + attr->SetEditor( new wxGridCellChoiceEditor( choices ) ); + m_project_grid->SetColAttr( FP_TBL_MODEL::COL_TYPE, attr ); + + attr = new wxGridCellAttr; + attr->SetEditor( new wxGridCellChoiceEditor( choices ) ); + m_global_grid->SetColAttr( FP_TBL_MODEL::COL_TYPE, attr ); + + m_global_grid->AutoSizeColumns(); + m_project_grid->AutoSizeColumns(); + + m_path_subs_grid->AutoSizeColumns(); Connect( ID_CUT, ID_PASTE, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( DIALOG_FP_LIB_TABLE::onPopupSelection ), NULL, this ); + populateEnvironReadOnlyTable(); + + /* This scrunches the dialog hideously + Fit(); + */ + // fire pageChangedHandler() so m_cur_grid gets set wxAuiNotebookEvent uneventful; pageChangedHandler( uneventful ); @@ -555,18 +673,18 @@ public: ~DIALOG_FP_LIB_TABLE() { - // Destroy the gui stuff first, with a goal of destroying the two wxGrids now, - // 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. 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(); + Disconnect( ID_CUT, ID_PASTE, wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler( DIALOG_FP_LIB_TABLE::onPopupSelection ), NULL, this ); + + // ~wxGrid() examines its table, and the tables will have been destroyed before + // the wxGrids are, so remove the tables from the wxGrids' awareness. + // Otherwise there is a segfault. + m_global_grid->SetTable( NULL ); + m_project_grid->SetTable( NULL ); } }; - int InvokePcbLibTableEditor( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) { DIALOG_FP_LIB_TABLE dlg( aParent, aGlobal, aProject ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp index 5e525ecd3f..c5a43fbef5 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp @@ -142,7 +142,7 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_path_subs_grid = new wxGrid( m_bottom, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid - m_path_subs_grid->CreateGrid( 2, 2 ); + m_path_subs_grid->CreateGrid( 1, 2 ); m_path_subs_grid->EnableEditing( true ); m_path_subs_grid->EnableGridLines( true ); m_path_subs_grid->EnableDragGridSize( false ); @@ -155,15 +155,13 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_path_subs_grid->EnableDragColMove( false ); m_path_subs_grid->EnableDragColSize( true ); m_path_subs_grid->SetColLabelSize( 30 ); - m_path_subs_grid->SetColLabelValue( 0, _("Category") ); + m_path_subs_grid->SetColLabelValue( 0, _("Environment Variable") ); m_path_subs_grid->SetColLabelValue( 1, _("Path Segment") ); m_path_subs_grid->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Rows m_path_subs_grid->EnableDragRowSize( true ); m_path_subs_grid->SetRowLabelSize( 40 ); - m_path_subs_grid->SetRowLabelValue( 0, _("%S") ); - m_path_subs_grid->SetRowLabelValue( 1, _("%P") ); m_path_subs_grid->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Label Appearance @@ -188,7 +186,7 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_bottom->SetSizer( m_bottom_sizer ); m_bottom->Layout(); m_bottom_sizer->Fit( m_bottom ); - m_splitter->SplitHorizontally( m_top, m_bottom, 343 ); + m_splitter->SplitHorizontally( m_top, m_bottom, 398 ); bSizer1->Add( m_splitter, 2, wxEXPAND, 5 ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp index 79bdad58e7..a5e4b1ff83 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp @@ -42,7 +42,7 @@ DIALOG_FP_LIB_TABLE_BASE - 864,652 + 996,652 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER DIALOG_SHIM; dialog_shim.h PCB Library Tables @@ -140,7 +140,7 @@ Resizable 0.0 - 343 + 398 -1 1 @@ -1297,7 +1297,7 @@ 1 wxALIGN_CENTRE 30 - "Category" "Path Segment" + "Environment Variable" "Path Segment" wxALIGN_CENTRE 2 150,500 @@ -1343,10 +1343,10 @@ Resizable wxALIGN_CENTRE 40 - "%S" "%P" + wxALIGN_CENTRE - 2 + 1 1 diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.h b/pcbnew/dialogs/dialog_fp_lib_table_base.h index 44ef78ef8a..5a0e15dcd0 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.h +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.h @@ -75,12 +75,12 @@ class DIALOG_FP_LIB_TABLE_BASE : public DIALOG_SHIM public: - DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("PCB Library Tables"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 864,652 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("PCB Library Tables"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 996,652 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DIALOG_FP_LIB_TABLE_BASE(); void m_splitterOnIdle( wxIdleEvent& ) { - m_splitter->SetSashPosition( 343 ); + m_splitter->SetSashPosition( 398 ); m_splitter->Disconnect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FP_LIB_TABLE_BASE::m_splitterOnIdle ), NULL, this ); } diff --git a/pcbnew/io_mgr.h b/pcbnew/io_mgr.h index 53778ca310..2806e0346f 100644 --- a/pcbnew/io_mgr.h +++ b/pcbnew/io_mgr.h @@ -51,6 +51,8 @@ public: LEGACY, //< Legacy Pcbnew file formats prior to s-expression. KICAD, //< S-expression Pcbnew file format. EAGLE, + PCAD, + GEDA_PCB, //< Geda PCB file formats. // add your type here. diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index bc9fce26fa..2504034eb8 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -45,9 +45,7 @@ #include #include -#if defined(DEBUG) - #include -#endif +#include #include #include @@ -92,7 +90,6 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) FP_LIB_TABLE gbl; FP_LIB_TABLE prj; -#if defined(DEBUG) FP_LIB_TABLE_LEXER glex( "(fp_lib_table\n" " (lib (name passives)(descr \"R/C Lib\")(type KiCad)(uri ${KISYSMODS}/passives.pretty))\n" @@ -124,29 +121,35 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) DisplayError( this, ioe.errorText ); break; } -#else - 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" ) ) ); -#endif int r = InvokePcbLibTableEditor( this, &gbl, &prj ); if( r & 1 ) { +#if defined(DEBUG) + printf( "changed global:\n" );) + + STRING_FORMATTER sf; + + gbl.Format( &sf, 0 ); + + printf( "%s\n", sf.GetString().c_str() ); +#endif // save global table to disk and apply it - D( printf( "global has changed\n" );) } if( r & 2 ) { +#if defined(DEBUG) + D( printf( "changed project:n" );) + + STRING_FORMATTER sf; + + prj.Format( &sf, 0 ); + + printf( "%s\n", sf.GetString().c_str() ); +#endif // save project table to disk and apply it - D( printf( "project has changed\n" );) } } break;