From 77e1a4c03c7ce01176ade55b833edc83d001724c Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Sun, 14 Oct 2012 21:38:32 -0400 Subject: [PATCH 1/9] Initial commit of footprint library table code. --- .bzrignore | 2 + CMakeLists.txt | 6 +- common/CMakeLists.txt | 11 +- common/fp_lib_id.cpp | 413 +++++++++++++++++++++++++++++++++++ common/fp_lib_table.cpp | 312 ++++++++++++++++++++++++++ common/fp_lib_table.keywords | 9 + include/fp_lib_id.h | 220 +++++++++++++++++++ include/fp_lib_table.h | 379 ++++++++++++++++++++++++++++++++ pcbnew/pcb_parser.h | 2 +- 9 files changed, 1348 insertions(+), 6 deletions(-) create mode 100644 common/fp_lib_id.cpp create mode 100644 common/fp_lib_table.cpp create mode 100644 common/fp_lib_table.keywords create mode 100644 include/fp_lib_id.h create mode 100644 include/fp_lib_table.h diff --git a/.bzrignore b/.bzrignore index de41d5eea9..4c6cf92eed 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,6 +1,8 @@ common/netlist_keywords.* common/netlist_lexer.h common/pcb_plot_params_lexer.h +common/fp_lib_table_keywords.* +include/fp_lib_table_lexer.h include/netlist_lexer.h eeschema/cmp_library_lexer.h eeschema/cmp_library_keywords.* diff --git a/CMakeLists.txt b/CMakeLists.txt index 40e19d6b4b..7d16569f10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules) # KiCad build options should be added below. # # If you add a new build option, please add it's state to the CopyVersionInfoToClipboard() -# function in common/basicframe.cpp so that build option settings can be includeed in bug +# function in common/basicframe.cpp so that build option settings can be included in bug # reports. # @@ -162,8 +162,6 @@ endif(KICAD_SCRIPTING_MODULES) if(KICAD_SCRIPTING_WXPYTHON) add_definitions(-DKICAD_SCRIPTING_WXPYTHON) - - endif(KICAD_SCRIPTING_WXPYTHON) if(USE_WX_GRAPHICS_CONTEXT) @@ -171,7 +169,7 @@ if(USE_WX_GRAPHICS_CONTEXT) endif(USE_WX_GRAPHICS_CONTEXT) # Allow user to override the default settings for adding images to menu items. By default -# images in menu items are enabled on all plaforms except OSX. This can be over ridden by +# images in menu items are enabled on all platforms except OSX. This can be over ridden by # defining -DUSE_IMAGES_IN_MENUS=ON/OFF to force the preferred behavior. if(NOT DEFINED USE_IMAGES_IN_MENUS) if(NOT APPLE) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index befdb20510..517791a9a4 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -124,6 +124,9 @@ set(PCB_COMMON_SRCS pcb_plot_params_keywords.cpp pcb_keywords.cpp ../pcbnew/pcb_parser.cpp + fp_lib_table_keywords.cpp + fp_lib_id.cpp + fp_lib_table.cpp ) @@ -155,9 +158,15 @@ make_lexer( make_lexer( ${CMAKE_CURRENT_SOURCE_DIR}/pcb.keywords ${PROJECT_SOURCE_DIR}/include/pcb_lexer.h ${CMAKE_CURRENT_SOURCE_DIR}/pcb_keywords.cpp - PCB + PCB_FILE_T ) +# auto-generate pcbnew s-expression footprint library table code. +make_lexer( ${CMAKE_CURRENT_SOURCE_DIR}/fp_lib_table.keywords + ${PROJECT_SOURCE_DIR}/include/fp_lib_table_lexer.h + ${CMAKE_CURRENT_SOURCE_DIR}/fp_lib_table_keywords.cpp + FP_LIB_TABLE_T + ) # The dsntest may not build properly using MS Visual Studio. if(NOT MSVC) diff --git a/common/fp_lib_id.cpp b/common/fp_lib_id.cpp new file mode 100644 index 0000000000..33dd229306 --- /dev/null +++ b/common/fp_lib_id.cpp @@ -0,0 +1,413 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include // _() + +#include + + +static inline bool isDigit( char c ) +{ + return c >= '0' && c <= '9'; +} + + +const char* EndsWithRev( const char* start, const char* tail, char separator ) +{ + bool sawDigit = false; + + while( tail > start && isDigit( *--tail ) ) + { + sawDigit = true; + } + + // if sawDigit, tail points to the 'v' here. + + if( sawDigit && tail-3 >= start ) + { + tail -= 3; + + if( tail[0]==separator && tail[1]=='r' && tail[2]=='e' && tail[3]=='v' ) + { + return tail+1; // omit separator, return "revN[N..]" + } + } + + return 0; +} + + +int RevCmp( const char* s1, const char* s2 ) +{ + int r = strncmp( s1, s2, 3 ); + + if( r || strlen(s1)<4 || strlen(s2)<4 ) + { + return r; + } + + int rnum1 = atoi( s1+3 ); + int rnum2 = atoi( s2+3 ); + + return -(rnum1 - rnum2); // swap the sign, higher revs first +} + +//----------------------------------------- + +// These all return -1 on success, or >= 0 if there is an error at a +// particular character offset into their respective arguments. If >=0, +// then that return value gives the character offset of the error. + + +static inline int okLogical( const std::string& aField ) +{ + // std::string::npos is largest positive number, casting to int makes it -1. + // Returning that means success. + return int( aField.find_first_of( ":/" ) ); +} + + +static inline int okBase( const std::string& aField ) +{ + int offset = int( aField.find_first_of( ":/" ) ); + + if( offset != -1 ) + return offset; + + // cannot be empty + if( !aField.size() ) + return 0; + + return offset; // ie. -1 +} + + +static int okRevision( const std::string& aField ) +{ + char rev[32]; // C string for speed + + if( aField.size() >= 4 ) + { + strcpy( rev, "x/" ); + strcat( rev, aField.c_str() ); + + if( EndsWithRev( rev, rev + strlen(rev) ) == rev+2 ) + return -1; // success + } + + return 0; // first character position "is in error", is best we can do. +} + +//----------------------------------------- + + +void FP_LIB_ID::clear() +{ + logical.clear(); + baseName.clear(); + footprintName.clear(); + revision.clear(); +} + + +int FP_LIB_ID::Parse( const std::string& aId ) +{ + clear(); + + const char* rev = EndsWithRev( aId ); + size_t revNdx; + size_t partNdx; + size_t baseNdx; + int offset; + + //============================================== + if( rev ) + { + revNdx = rev - aId.c_str(); + + // no need to check revision, EndsWithRev did that. + revision = aId.substr( revNdx ); + --revNdx; // back up to omit the '/' which preceeds the rev + } + else + revNdx = aId.size(); + + //=============================================== + if( ( partNdx = aId.find( ':' ) ) != aId.npos ) + { + offset = SetLogicalLib( aId.substr( 0, partNdx ) ); + if( offset > -1 ) + { + return offset; + } + ++partNdx; // skip ':' + } + else + partNdx = 0; + + //=============================================== + offset = SetBaseName( aId.substr( baseNdx, revNdx - baseNdx ) ); + + if( offset > -1 ) + { + return offset + baseNdx; + } + + return -1; +} + + +FP_LIB_ID::FP_LIB_ID( const std::string& aId ) throw( PARSE_ERROR ) +{ + int offset = Parse( aId ); + + if( offset != -1 ) + { + THROW_PARSE_ERROR( _( "Illegal character found in FP_LIB_ID string" ), + wxString::FromUTF8( aId.c_str() ), + aId.c_str(), + 0, + offset ); + } +} + + +int FP_LIB_ID::SetLogicalLib( const std::string& aLogical ) +{ + int offset = okLogical( aLogical ); + + if( offset == -1 ) + { + logical = aLogical; + } + + return offset; +} + + +int FP_LIB_ID::SetBaseName( const std::string& aBaseName ) +{ + int offset = okBase( aBaseName ); + + if( offset == -1 ) + { + baseName = aBaseName; + } + + return offset; +} + + +int FP_LIB_ID::SetFootprintName( const std::string& aFootprintName ) +{ + std::string base; + int offset; + int separation = int( aFootprintName.find_first_of( "/" ) ); + + if( separation != -1 ) + { + base = aFootprintName.substr( separation+1 ); + } + else + { + base = aFootprintName; + } + + if( (offset = SetBaseName( base )) != -1 ) + { + return offset + separation + 1; + } + + return -1; +} + + +int FP_LIB_ID::SetRevision( const std::string& aRevision ) +{ + int offset = okRevision( aRevision ); + + if( offset == -1 ) + { + revision = aRevision; + } + + return offset; +} + + +std::string FP_LIB_ID::Format() const +{ + std::string ret; + + if( logical.size() ) + { + ret += logical; + ret += ':'; + } + + ret += baseName; + + if( revision.size() ) + { + ret += '/'; + ret += revision; + } + + return ret; +} + + +std::string FP_LIB_ID::GetFootprintNameAndRev() const +{ + std::string ret; + + ret += baseName; + + if( revision.size() ) + { + ret += '/'; + ret += revision; + } + + return ret; +} + + +std::string FP_LIB_ID::Format( const std::string& aLogicalLib, const std::string& aFootprintName, + const std::string& aRevision ) + throw( PARSE_ERROR ) +{ + std::string ret; + int offset; + + if( aLogicalLib.size() ) + { + offset = okLogical( aLogicalLib ); + + if( offset != -1 ) + { + THROW_PARSE_ERROR( _( "Illegal character found in logical lib name" ), + wxString::FromUTF8( aLogicalLib.c_str() ), + aLogicalLib.c_str(), + 0, + offset ); + } + + ret += aLogicalLib; + ret += ':'; + } + + { + std::string base; + + int separation = int( aFootprintName.find_first_of( "/" ) ); + + if( separation != -1 ) + { + base = aFootprintName.substr( separation+1 ); + } + else + { + base = aFootprintName; + } + + + if( (offset = okBase( base )) != -1 ) + { + THROW_PARSE_ERROR( _( "Illegal character found in base name" ), + wxString::FromUTF8( aRevision.c_str() ), + aRevision.c_str(), + 0, + offset + separation + 1 ); + } + + ret += base; + } + + if( aRevision.size() ) + { + offset = okRevision( aRevision ); + + if( offset != -1 ) + { + THROW_PARSE_ERROR( _( "Illegal character found in revision" ), + wxString::FromUTF8( aRevision.c_str() ), + aRevision.c_str(), + 0, + offset ); + } + + ret += '/'; + ret += aRevision; + } + + return ret; +} + + +#if 0 && defined(DEBUG) + +// build this with Debug CMAKE_BUILD_TYPE + +void FP_LIB_ID::Test() +{ + static const char* lpids[] = { + "/R/rev0", + "passives/R/rev2", + ":passives/R/rev3", + "C/rev22", + "passives/C22", + "R", + "me:R", + // most difficult: + "me:/R/rev0", + "me:R/rev0", + }; + + for( unsigned i=0; i + * Copyright (C) 2012 Wayne Stambaugh + * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include + +#include + +#include +#include + + +using namespace FP_LIB_TABLE_T; + + +FP_LIB_TABLE::FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable ) : + fallBack( aFallBackTable ) +{ + // not copying fall back, simply search aFallBackTable separately + // if "logicalName not found". +} + + +void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR ) +{ + T tok; + + while( ( tok = in->NextTok() ) != T_RIGHT ) + { + // (lib (name "LOGICAL")(type "TYPE")(full_uri "FULL_URI")(options "OPTIONS")) + + if( tok == T_EOF ) + in->Expecting( T_RIGHT ); + + if( tok != T_LEFT ) + in->Expecting( T_LEFT ); + + if( ( tok = in->NextTok() ) != T_fp_lib ) + in->Expecting( T_fp_lib ); + + // (name "LOGICAL_NAME") + in->NeedLEFT(); + + if( ( tok = in->NextTok() ) != T_name ) + in->Expecting( T_name ); + + in->NeedSYMBOLorNUMBER(); + + std::auto_ptr row( new ROW( this ) ); + + row->SetLogicalName( in->CurText() ); + + in->NeedRIGHT(); + + // (type "TYPE") + in->NeedLEFT(); + + if( ( tok = in->NextTok() ) != T_type ) + in->Expecting( T_type ); + + in->NeedSYMBOLorNUMBER(); + + row->SetType( in->CurText() ); + + in->NeedRIGHT(); + + // (uri "FULL_URI") + in->NeedLEFT(); + + if( ( tok = in->NextTok() ) != T_full_uri ) + in->Expecting( T_full_uri ); + + in->NeedSYMBOLorNUMBER(); + + row->SetFullURI( in->CurText() ); + + in->NeedRIGHT(); + + // (options "OPTIONS") + in->NeedLEFT(); + + if( ( tok = in->NextTok() ) != T_options ) + in->Expecting( T_options ); + + in->NeedSYMBOLorNUMBER(); + + row->SetOptions( in->CurText() ); + + in->NeedRIGHT(); + in->NeedRIGHT(); // terminate the (lib..) + + // all logicalNames within this table fragment must be unique, so we do not + // use doReplace in InsertRow(). However a fallBack table can have a + // conflicting logicalName and ours will supercede that one since in + // FindLib() we search this table before any fall back. + if( !InsertRow( row ) ) + { + std::string msg; + + msg += '\''; + msg += row->logicalName; + msg += '\''; + msg += " is a duplicate logical footprint library name"; + THROW_IO_ERROR( msg ); + } + } +} + + +void FP_LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const + throw( IO_ERROR ) +{ + out->Print( nestLevel, "(fp_lib_table\n" ); + + for( ROWS_CITER it = rows.begin(); it != rows.end(); ++it ) + it->second->Format( out, nestLevel+1 ); + + out->Print( nestLevel, ")\n" ); +} + + +void FP_LIB_TABLE::ROW::Format( OUTPUTFORMATTER* out, int nestLevel ) const + throw( IO_ERROR ) +{ + out->Print( nestLevel, "(lib (logical %s)(type %s)(full_uri %s)(options %s))\n", + out->Quotes( logicalName ).c_str(), + out->Quotes( type ).c_str(), + out->Quotes( uri ).c_str(), + out->Quotes( options ).c_str() ); +} + + +std::vector FP_LIB_TABLE::GetLogicalLibs() +{ + // Only return unique logical library names. Use std::set::insert() to + // quietly reject any duplicates, which can happen when encountering a duplicate + // logical lib name from one of the fall back table(s). + + std::set unique; + std::vector ret; + const FP_LIB_TABLE* cur = this; + + do + { + for( ROWS_CITER it = cur->rows.begin(); it!=cur->rows.end(); ++it ) + { + unique.insert( it->second->logicalName ); + } + + } while( ( cur = cur->fallBack ) != 0 ); + + // return a sorted, unique set of logical lib name std::vector to caller + for( std::set::const_iterator it = unique.begin(); it!=unique.end(); ++it ) + ret.push_back( *it ); + + return ret; +} + + +MODULE* FP_LIB_TABLE::LookupFootprint( const FP_LIB_ID& aFootprintId ) + throw( IO_ERROR ) +{ + PLUGIN* plugin = lookupLib( aFootprintId ); + + return plugin->FootprintLoad( wxString( aFootprintId.GetBaseName().c_str() ), + wxString( aFootprintId.GetLogicalLib().c_str() ) ); +} + + +PLUGIN* FP_LIB_TABLE::lookupLib( const FP_LIB_ID& aFootprintId ) + throw( IO_ERROR ) +{ + if( aFootprintId.GetLogicalLib().size() ) + { + ROW* row = FindRow( aFootprintId.GetLogicalLib() ); + + 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 ); + } +} + + +FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const std::string& aLogicalName ) const +{ + // this function must be *super* fast, so therefore should not instantiate + // anything which would require using the heap. This function is the reason + // ptr_map<> was used instead of ptr_set<>, which would have required + // instantiating a ROW just to find a ROW. + const FP_LIB_TABLE* cur = this; + + do + { + ROWS_CITER it = cur->rows.find( aLogicalName ); + + if( it != cur->rows.end() ) + { + // reference: http://myitcorner.com/blog/?p=361 + return (FP_LIB_TABLE::ROW*) it->second; // found + } + + // not found, search fall back table(s), if any + } while( ( cur = cur->fallBack ) != 0 ); + + return 0; // not found +} + + +bool FP_LIB_TABLE::InsertRow( std::auto_ptr& aRow, bool doReplace ) +{ + // this does not need to be super fast. + + ROWS_CITER it = rows.find( aRow->logicalName ); + + if( it == rows.end() ) + { + // be careful here, key is needed because aRow can be + // release()ed before logicalName is captured. + const std::string& key = aRow->logicalName; + rows.insert( key, aRow ); + return true; + } + + if( doReplace ) + { + rows.erase( aRow->logicalName ); + + // be careful here, key is needed because aRow can be + // release()ed before logicalName is captured. + const std::string& key = aRow->logicalName; + rows.insert( key, aRow ); + return true; + } + + return false; +} + diff --git a/common/fp_lib_table.keywords b/common/fp_lib_table.keywords new file mode 100644 index 0000000000..6a678ed707 --- /dev/null +++ b/common/fp_lib_table.keywords @@ -0,0 +1,9 @@ +fp_lib_table +name +type +kicad +legacy +eagle +full_uri +options +fp_lib diff --git a/include/fp_lib_id.h b/include/fp_lib_id.h new file mode 100644 index 0000000000..f12bde097a --- /dev/null +++ b/include/fp_lib_id.h @@ -0,0 +1,220 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _FP_LIB_ID_H_ +#define _FP_LIB_ID_H_ + +#include + + +/** + * Class FP_LIB_ID + * (aka GUID) is a Logical Part ID and consists of various portions much like a URI. + * It is a container for the separated portions of a logical part id std::string so they + * can be accessed individually. The various portions of an FP_LIB_ID are: + * logicalLibraryName, category, baseName, and revision. Only the baseName is + * mandatory. There is another construct called "footprintName" which consists of + * [category/]baseName. That is the category followed by a slash, but only if + * the category is not empty. + *

+ * footprintName = [category/]baseName + *

+ * Example FP_LIB_ID string: + * "smt:R_0805". + *

+ *

    + *
  • "smt" is the logical library name. + *
  • "R" is the footprint name. + *
  • "rev6" is the revision, which is optional. If missing then its + * / delimiter should also not be present. A revision must begin with + * "rev" and be followed by at least one or more decimal digits. + *
+ * @author Dick Hollenbeck + */ +class FP_LIB_ID // aka GUID +{ +public: + + FP_LIB_ID() {} + + /** + * Constructor FP_LIB_ID + * takes \a aId string and parses it. A typical FP_LIB_ID string uses a logical + * library name followed by a footprint name. + * e.g.: "smt:R_0805", or + * e.g.: "mylib:R_0805" + */ + FP_LIB_ID( const std::string& aId ) throw( PARSE_ERROR ); + + /** + * Function Parse + * [re-]stuffs this FP_LIB_ID with the information from @a aId. + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the + * character offset into aId at which an error was detected. + */ + int Parse( const std::string& aId ); + + /** + * Function GetLogicalLib + * returns the logical library portion of a FP_LIB_ID. There is not Set accessor + * for this portion since it comes from the library table and is considered + * read only here. + */ + const std::string& GetLogicalLib() const + { + return logical; + } + + /** + * Function SetCategory + * overrides the logical lib name portion of the FP_LIB_ID to @a aLogical, and can be empty. + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the + * character offset into the parameter at which an error was detected, usually + * because it contained '/' or ':'. + */ + int SetLogicalLib( const std::string& aLogical ); + + /** + * Function GetBaseName + * returns the part name without the category. + */ + const std::string& GetBaseName() const + { + return baseName; + } + + /** + * Function SetBaseName + * overrides the base name portion of the FP_LIB_ID to @a aBaseName + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the + * character offset into the parameter at which an error was detected, usually + * because it contained '/' or ':', or is blank. + */ + int SetBaseName( const std::string& aBaseName ); + + /** + * Function GetFootprintName + * returns the part name, i.e. category/baseName without revision. + */ + const std::string& GetFootprintName() const + { + return footprintName; + } + + /** + * Function GetFootprintNameAndRev + * returns the part name with revision if any, i.e. baseName[/revN..] + */ + std::string GetFootprintNameAndRev() const; + + /** + * Function SetFootprintName + * overrides the part name portion of the FP_LIB_ID to @a aFootprintName + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the + * character offset into the parameter at which an error was detected, usually + * because it contained more than one '/', or one or more ':', or is blank. + * A single '/' is allowed, since that is used to separate the category from the + * base name. + */ + int SetFootprintName( const std::string& aFootprintName ); + + /** + * Function GetRevision + * returns the revision portion of the FP_LIB_ID. + */ + const std::string& GetRevision() const + { + return revision; + } + + /** + * Function SetRevision + * overrides the revision portion of the FP_LIB_ID to @a aRevision and must + * be in the form "rev" where "" is "1", "2", etc. + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the + * character offset into the parameter at which an error was detected, + * because it did not look like "rev23" + */ + int SetRevision( const std::string& aRevision ); + + /** + * Function Format + * returns the full text of the FP_LIB_ID. + */ + std::string Format() const; + + /** + * Function Format + * returns a std::string in the proper format as an FP_LIB_ID for a combination of + * aLogicalLib, aFootprintName, and aRevision. + * @throw PARSE_ERROR if any of the pieces are illegal. + */ + static std::string Format( const std::string& aLogicalLib, const std::string& aFootprintName, + const std::string& aRevision="" ) + throw( PARSE_ERROR ); + + void clear(); + +#if defined(DEBUG) + static void Test(); +#endif + +protected: + std::string logical; ///< logical lib name or empty + std::string baseName; ///< without category + std::string revision; ///< "revN[N..]" or empty + std::string footprintName; ///< cannot be set directory, set via SetBaseName() & SetCategory() +}; + +/** + * Function EndsWithRev + * returns a pointer to the final string segment: "revN[N..]" or NULL if none. + * @param start is the beginning of string segment to test, the partname or + * any middle portion of it. + * @param tail is a pointer to the terminating nul, or one past inclusive end of + * segment, i.e. the string segment of interest is [start,tail) + * @param separator is the separating byte, expected: '.' or '/', depending on context. + */ +const char* EndsWithRev( const char* start, const char* tail, char separator = '/' ); + +static inline const char* EndsWithRev( const std::string& aFootprintName, char separator = '/' ) +{ + return EndsWithRev( aFootprintName.c_str(), aFootprintName.c_str()+aFootprintName.size(), + separator ); +} + + +/** + * Function RevCmp + * compares two rev strings in a way like strcmp() except that the highest numbered + * revision is considered first in the sort order. The function probably won't work + * unless you give it two rev strings. + * @param s1 is a rev string like "rev10" + * @param s2 is a rev string like "rev1". + * @return int - either negative, zero, or positive depending on whether the revision + * is greater, equal, or less on the left hand side. + */ +int RevCmp( const char* s1, const char* s2 ); + +#endif // _FP_LIB_ID_H_ diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h new file mode 100644 index 0000000000..c304864da1 --- /dev/null +++ b/include/fp_lib_table.h @@ -0,0 +1,379 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2012 Wayne Stambaugh + * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef _FP_LIB_TABLE_H_ +#define _FP_LIB_TABLE_H_ + + +#include + +#include + + +class OUTPUTFORMATTER; + + +class MODULE; + +/** + * Class FP_LIB_TABLE + * holds FP_LIB_TABLE::ROW records, and can be searched based on logical library name. + *

+ * 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 + * parser work done by Dick Hollenbeck and can be seen in new/sch_lib_table.h. A footprint + * library table had the following columns: + *

    + *
  • Logical Library Name (Nickname) + *
  • Library Type, used to determine which plugin to load to access the library. + *
  • Library URI. The full URI to the library source, form dependent on Type. + *
  • Options, used for as yet to be defined information such as user names or passwords + *
+ *

+ * The Library Type can be one of: + *

    + *
  • "file" + *
  • "ftp" + *
  • "http" + *
+ *

+ * For now, the Library URI types needed to support the various types can be one of those + * shown below, which are typical of each type: + *

    + *
  • "file://C:/mylibdir" + *
  • "ftp://kicad.org/partlib/trunk" + *
  • "http://kicad.org/partlib" + *
+ *

+ * The footprint library table is built up from several additive entries (table fragments), + * and the final table is a (conceptual) merging of the table fragments. Two + * anticipated sources of the entries are a personal table saved in the KiCad configuration + * and a project resident table that resides in project file. The project footprint table + * entries are considered a higher priority in the final dynamically assembled library table. + * An row in the project file contribution to the library table takes precedence over the + * personal table if there is a collision of logical library names. Otherwise, the entries + * simply combine without issue to make up the applicable library table. + * + * @author Wayne Stambaugh + */ +class FP_LIB_TABLE +{ +public: + + /** + * Class ROW + * holds a record identifying a footprint library accessed by the appropriate #PLUGIN + * object in the #FP_LIB_TABLE. + */ + class ROW + { + friend class FP_LIB_TABLE; + + public: + + /** + * Function GetLogicalName + * returns the logical name of this library table row. + */ + const std::string& GetLogicalName() const + { + return logicalName; + } + + /** + * Function GetType + * returns the type of LIB represented by this record. + */ + const std::string& GetType() const + { + return type; + } + + /** + * Function GetFullURI + * returns the full location specifying URI for the LIB. + */ + const std::string& GetFullURI() const + { + return uri; + } + + /** + * Function GetOptions + * returns the options string, which may hold a password or anything else needed to + * instantiate the underlying LIB_SOURCE. + */ + const std::string& GetOptions() const + { + return options; + } + + ~ROW() + { + delete lib; + } + + /** + * Function Format + * serializes this object as utf8 text to an OUTPUTFORMATTER, and tries to + * make it look good using multiple lines and indentation. + * @param out is an #OUTPUTFORMATTER + * @param nestLevel is the indentation level to base all lines of the output. + * Actual indentation will be 2 spaces for each nestLevel. + */ + void Format( OUTPUTFORMATTER* out, int nestLevel ) const + throw( IO_ERROR ); + + protected: + + ROW( FP_LIB_TABLE* aOwner ) : + owner( aOwner ), + lib( 0 ) + {} + + /** + * Function SetLogicalName + * changes the logical name of this library, useful for an editor. + */ + void SetLogicalName( const std::string& aLogicalName ) + { + logicalName = aLogicalName; + } + + /** + * Function SetType + * changes the type represented by this record. + */ + void SetType( const std::string& aType ) + { + type = aType; + } + + /** + * Function SetFullURI + * changes the full URI for the library, useful from a library table editor. + */ + void SetFullURI( const std::string& aFullURI ) + { + uri = aFullURI; + } + + /** + * Function SetOptions + * changes the options string for this record, and is useful from + * the library table editor. + */ + void SetOptions( const std::string& aOptions ) + { + options = aOptions; + } + + private: + FP_LIB_TABLE* owner; + std::string logicalName; + std::string type; + std::string uri; + std::string options; + + PLUGIN* lib; ///< ownership of the loaded LIB is here + }; + + /** + * Constructor FP_LIB_TABLE + * builds a library table by pre-pending this table fragment in front of + * @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 + * taken of aFallBackTable. + */ + FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable = NULL ); + + /** + * Function Parse + * fills this table fragment from information in the input stream \a aParser, which + * is a DSNLEXER customized for the grammar needed to describe instances of this object. + * The entire textual element spec is
+ * + *

+     * (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))
+     *  )
+     * 
+ * + * When this function is called, the input token stream given by \a aParser + * is assumed to be positioned at the '^' in the following example, i.e. just + * after the identifying keyword and before the content specifying stuff. + *
+ * (lib_table ^ (....) ) + * + * @param aParser is the input token stream of keywords and symbols. + */ + void Parse( FP_LIB_TABLE_LEXER* aParser ) throw( IO_ERROR, PARSE_ERROR ); + + /** + * Function Format + * serializes this object as utf8 text to an #OUTPUTFORMATTER, and tries to + * make it look good using multiple lines and indentation. + * + * @param out is an #OUTPUTFORMATTER + * @param nestLevel is the indentation level to base all lines of the output. + * Actual indentation will be 2 spaces for each nestLevel. + */ + void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ); + + /** + * 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 ); + + /** + * Function GetLogicalLibs + * returns the logical library names, all of them that are pertinent to + * a lookup done on this FP_LIB_TABLE. + */ + std::vector GetLogicalLibs(); + + //-------------------------------------------------------- + // the returning of a const std::string* tells if not found, but might be too + // promiscuous? + + /** + * Function GetURI + * returns the full library path from a logical library name. + * @param aLogicalLibraryName is the short name for the library of interest. + * @return const std::string* - or NULL if not found. + */ + const std::string* GetURI( const std::string& aLogicalLibraryName ) const + { + const ROW* row = FindRow( aLogicalLibraryName ); + return row ? &row->uri : 0; + } + + /** + * Function GetType + * returns the type of a logical library. + * @param aLogicalLibraryName is the short name for the library of interest. + * @return const std::string* - or NULL if not found. + */ + const std::string* GetType( const std::string& aLogicalLibraryName ) const + { + const ROW* row = FindRow( aLogicalLibraryName ); + return row ? &row->type : 0; + } + + /** + * Function GetLibOptions + * returns the options string for \a aLogicalLibraryName. + * @param aLogicalLibraryName is the short name for the library of interest. + * @return const std::string* - or NULL if not found. + */ + const std::string* GetLibOptions( const std::string& aLogicalLibraryName ) const + { + const ROW* row = FindRow( aLogicalLibraryName ); + return row ? &row->options : 0; + } + + //------------------------------------------------------- + +#if 1 || defined(DEBUG) + /// implement the tests in here so we can honor the privilege levels of the + /// accessors, something difficult to do from int main(int, char**) + 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 + * is not true and the key for aRow already exists, the function fails and returns false. + * The key for the table is the logicalName, and all in this table must be unique. + * @param aRow is the new row to insert, or to forcibly add if doReplace is true. + * @param doReplace if true, means insert regardless of whether aRow's key already + * exists. If false, then fail if the key already exists. + * @return bool - true if the operation succeeded. + */ + bool InsertRow( std::auto_ptr& aRow, bool doReplace = false ); + + /** + * Function FindRow + * returns a #ROW* if aLogicalName is found in this table or in any chained + * fallBack table fragment, else NULL. + */ + ROW* FindRow( const std::string& aLogicalName ) const; + +private: + + /** + * 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 ); + + /** + * Function loadLib + * loads a LIB using information in @a aRow. Call only if LIB not + * already loaded. + */ + void loadLib( ROW* aRow ) throw( IO_ERROR ); + + typedef boost::ptr_map ROWS; + typedef ROWS::iterator ROWS_ITER; + typedef ROWS::const_iterator ROWS_CITER; + + ROWS rows; + FP_LIB_TABLE* fallBack; +}; + +#endif // _FP_LIB_TABLE_H_ diff --git a/pcbnew/pcb_parser.h b/pcbnew/pcb_parser.h index e9ad61f4eb..91f8c13e86 100644 --- a/pcbnew/pcb_parser.h +++ b/pcbnew/pcb_parser.h @@ -34,7 +34,7 @@ #include -using namespace PCB; +using namespace PCB_FILE_T; class BOARD; From 0dc4d9c19e37792469c1f284e318f7994e8403ec Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Mon, 15 Oct 2012 12:19:42 -0400 Subject: [PATCH 2/9] Commit Dick's changes to the FP_LIB_TABLE object. --- common/fp_lib_table.cpp | 97 ++++++++++++------------- include/fp_lib_table.h | 153 +++++++++++++++++++++++++++++----------- 2 files changed, 158 insertions(+), 92 deletions(-) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 9b619004a4..0516e3568c 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010-12 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors. * @@ -39,7 +39,7 @@ FP_LIB_TABLE::FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable ) : fallBack( aFallBackTable ) { // not copying fall back, simply search aFallBackTable separately - // if "logicalName not found". + // if "nickName not found". } @@ -68,9 +68,9 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - std::auto_ptr row( new ROW( this ) ); + ROW row( this ); - row->SetLogicalName( in->CurText() ); + row.SetNickName( in->FromUTF8() ); in->NeedRIGHT(); @@ -82,7 +82,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - row->SetType( in->CurText() ); + row.SetType( in->FromUTF8() ); in->NeedRIGHT(); @@ -94,7 +94,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - row->SetFullURI( in->CurText() ); + row.SetFullURI( in->FromUTF8() ); in->NeedRIGHT(); @@ -106,23 +106,21 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - row->SetOptions( in->CurText() ); + row.SetOptions( in->FromUTF8() ); in->NeedRIGHT(); in->NeedRIGHT(); // terminate the (lib..) - // all logicalNames within this table fragment must be unique, so we do not + // all nickNames within this table fragment must be unique, so we do not // use doReplace in InsertRow(). However a fallBack table can have a - // conflicting logicalName and ours will supercede that one since in + // conflicting nickName and ours will supercede that one since in // FindLib() we search this table before any fall back. if( !InsertRow( row ) ) { - std::string msg; - - msg += '\''; - msg += row->logicalName; - msg += '\''; - msg += " is a duplicate logical footprint library name"; + wxString msg = wxString::Format( + _( "'%s' is a duplicate footprint library nickName" ), + GetChars( row.nickName ) + ); THROW_IO_ERROR( msg ); } } @@ -135,7 +133,7 @@ void FP_LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const out->Print( nestLevel, "(fp_lib_table\n" ); for( ROWS_CITER it = rows.begin(); it != rows.end(); ++it ) - it->second->Format( out, nestLevel+1 ); + it->Format( out, nestLevel+1 ); out->Print( nestLevel, ")\n" ); } @@ -144,48 +142,50 @@ 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 (logical %s)(type %s)(full_uri %s)(options %s))\n", - out->Quotes( logicalName ).c_str(), - out->Quotes( type ).c_str(), - out->Quotes( uri ).c_str(), - out->Quotes( options ).c_str() ); + 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() + ); } -std::vector FP_LIB_TABLE::GetLogicalLibs() +std::vector FP_LIB_TABLE::GetLogicalLibs() { // Only return unique logical library names. Use std::set::insert() to // quietly reject any duplicates, which can happen when encountering a duplicate - // logical lib name from one of the fall back table(s). + // nickname from one of the fall back table(s). - std::set unique; - std::vector ret; - const FP_LIB_TABLE* cur = this; + std::set unique; + std::vector ret; + const FP_LIB_TABLE* cur = this; do { for( ROWS_CITER it = cur->rows.begin(); it!=cur->rows.end(); ++it ) { - unique.insert( it->second->logicalName ); + unique.insert( it->nickName ); } } while( ( cur = cur->fallBack ) != 0 ); - // return a sorted, unique set of logical lib name std::vector to caller - for( std::set::const_iterator it = unique.begin(); it!=unique.end(); ++it ) + // return a sorted, unique set of nicknames in a std::vector to caller + for( std::set::const_iterator it = unique.begin(); it!=unique.end(); ++it ) ret.push_back( *it ); return ret; } +#if 0 // will need PLUGIN_RELEASER. MODULE* FP_LIB_TABLE::LookupFootprint( const FP_LIB_ID& aFootprintId ) throw( IO_ERROR ) { PLUGIN* plugin = lookupLib( aFootprintId ); - return plugin->FootprintLoad( wxString( aFootprintId.GetBaseName().c_str() ), - wxString( aFootprintId.GetLogicalLib().c_str() ) ); + return plugin->FootprintLoad( FROM_UTF8( aFootprintId.GetBaseName().c_str() ), + FROM_UTF8( aFootprintId.GetLogicalLib().c_str() ) ); } @@ -254,24 +254,22 @@ void FP_LIB_TABLE::loadLib( ROW* aRow ) throw( IO_ERROR ) THROW_IO_ERROR( msg ); } } +#endif -FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const std::string& aLogicalName ) const +FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aNickName ) const { // this function must be *super* fast, so therefore should not instantiate - // anything which would require using the heap. This function is the reason - // ptr_map<> was used instead of ptr_set<>, which would have required - // instantiating a ROW just to find a ROW. + // anything which would require using the heap. const FP_LIB_TABLE* cur = this; do { - ROWS_CITER it = cur->rows.find( aLogicalName ); + INDEX_CITER it = cur->nickIndex.find( aNickName ); - if( it != cur->rows.end() ) + if( it != cur->nickIndex.end() ) { - // reference: http://myitcorner.com/blog/?p=361 - return (FP_LIB_TABLE::ROW*) it->second; // found + return (FP_LIB_TABLE::ROW*) &cur->rows[it->second]; // found } // not found, search fall back table(s), if any @@ -281,29 +279,26 @@ FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const std::string& aLogicalName ) cons } -bool FP_LIB_TABLE::InsertRow( std::auto_ptr& aRow, bool doReplace ) +bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace ) { // this does not need to be super fast. - ROWS_CITER it = rows.find( aRow->logicalName ); + INDEX_CITER it = nickIndex.find( aRow.nickName ); - if( it == rows.end() ) + if( it == nickIndex.end() ) { - // be careful here, key is needed because aRow can be - // release()ed before logicalName is captured. - const std::string& key = aRow->logicalName; - rows.insert( key, aRow ); + rows.push_back( aRow ); + nickIndex.insert( INDEX_VALUE( aRow.nickName, rows.size() - 1 ) ); return true; } if( doReplace ) { - rows.erase( aRow->logicalName ); + int ndx = it->second; - // be careful here, key is needed because aRow can be - // release()ed before logicalName is captured. - const std::string& key = aRow->logicalName; - rows.insert( key, aRow ); + rows[ndx] = aRow; + nickIndex.erase( aRow.nickName ); + nickIndex.insert( INDEX_VALUE( aRow.nickName, ndx ) ); return true; } diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index c304864da1..4d5c270c3e 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010-12 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors. * @@ -26,11 +26,14 @@ #ifndef _FP_LIB_TABLE_H_ #define _FP_LIB_TABLE_H_ +#include +#include +#include + +#include #include -#include - class OUTPUTFORMATTER; @@ -78,7 +81,7 @@ class MODULE; * * @author Wayne Stambaugh */ -class FP_LIB_TABLE +class FP_LIB_TABLE : public wxGridTableBase { public: @@ -94,19 +97,19 @@ public: public: /** - * Function GetLogicalName - * returns the logical name of this library table row. + * Function GetNickName + * returns the short name of this library table row. */ - const std::string& GetLogicalName() const + const wxString& GetNickName() const { - return logicalName; + return nickName; } /** * Function GetType * returns the type of LIB represented by this record. */ - const std::string& GetType() const + const wxString& GetType() const { return type; } @@ -115,7 +118,7 @@ public: * Function GetFullURI * returns the full location specifying URI for the LIB. */ - const std::string& GetFullURI() const + const wxString& GetFullURI() const { return uri; } @@ -125,14 +128,14 @@ public: * returns the options string, which may hold a password or anything else needed to * instantiate the underlying LIB_SOURCE. */ - const std::string& GetOptions() const + const wxString& GetOptions() const { return options; } ~ROW() { - delete lib; + // delete lib; } /** @@ -149,24 +152,24 @@ public: protected: ROW( FP_LIB_TABLE* aOwner ) : - owner( aOwner ), - lib( 0 ) + owner( aOwner ) + // lib( 0 ) {} /** - * Function SetLogicalName + * Function SetNickName * changes the logical name of this library, useful for an editor. */ - void SetLogicalName( const std::string& aLogicalName ) + void SetNickName( const wxString& aNickName ) { - logicalName = aLogicalName; + nickName = aNickName; } /** * Function SetType * changes the type represented by this record. */ - void SetType( const std::string& aType ) + void SetType( const wxString& aType ) { type = aType; } @@ -175,7 +178,7 @@ public: * Function SetFullURI * changes the full URI for the library, useful from a library table editor. */ - void SetFullURI( const std::string& aFullURI ) + void SetFullURI( const wxString& aFullURI ) { uri = aFullURI; } @@ -185,21 +188,24 @@ public: * changes the options string for this record, and is useful from * the library table editor. */ - void SetOptions( const std::string& aOptions ) + void SetOptions( const wxString& aOptions ) { options = aOptions; } private: - FP_LIB_TABLE* owner; - std::string logicalName; - std::string type; - std::string uri; - std::string options; + FP_LIB_TABLE* owner; + wxString nickName; + wxString type; + wxString uri; + wxString options; - PLUGIN* lib; ///< ownership of the loaded LIB is here + /* + PLUGIN* lib; ///< ownership of the loaded LIB is here + */ }; + /** * Constructor FP_LIB_TABLE * builds a library table by pre-pending this table fragment in front of @@ -246,6 +252,7 @@ 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 @@ -262,25 +269,76 @@ public: * @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 * returns the logical library names, all of them that are pertinent to * a lookup done on this FP_LIB_TABLE. */ - std::vector GetLogicalLibs(); + std::vector GetLogicalLibs(); + + + //------------------------------------------------ + + int GetNumberRows () { return rows.size(); } + int GetNumberCols () { return 4; } + + wxString GetValue( int aRow, int aCol ) + { + if( unsigned( aRow ) < rows.size() ) + { + const ROW& r = rows[aRow]; + + switch( aCol ) + { + case 0: return r.GetNickName(); + case 1: return r.GetType(); + case 2: return r.GetFullURI(); + case 3: return r.GetOptions(); + default: + ; // fall thru to wxEmptyString + } + } + + return wxEmptyString; + } + + void SetValue( int aRow, int aCol, const wxString &aValue ) + { + if( aCol == 0 ) + { + // when the nickname is changed, there's careful work to do, including + // ensuring uniqueness of the nickname. + } + else if( unsigned( aRow ) < rows.size() ) + { + ROW& r = rows[aRow]; + + switch( aCol ) + { + case 1: return r.SetType( aValue ); + case 2: return r.SetFullURI( aValue ); + case 3: return r.SetOptions( aValue ); + } + } + } + + //----------------------------------------------- + //-------------------------------------------------------- - // the returning of a const std::string* tells if not found, but might be too + // the returning of a const wxString* tells if not found, but might be too // promiscuous? /** * Function GetURI * returns the full library path from a logical library name. * @param aLogicalLibraryName is the short name for the library of interest. - * @return const std::string* - or NULL if not found. + * @return const wxString* - or NULL if not found. */ - const std::string* GetURI( const std::string& aLogicalLibraryName ) const + const wxString* GetURI( const wxString& aLogicalLibraryName ) const { const ROW* row = FindRow( aLogicalLibraryName ); return row ? &row->uri : 0; @@ -290,9 +348,9 @@ public: * Function GetType * returns the type of a logical library. * @param aLogicalLibraryName is the short name for the library of interest. - * @return const std::string* - or NULL if not found. + * @return const wxString* - or NULL if not found. */ - const std::string* GetType( const std::string& aLogicalLibraryName ) const + const wxString* GetType( const wxString& aLogicalLibraryName ) const { const ROW* row = FindRow( aLogicalLibraryName ); return row ? &row->type : 0; @@ -302,9 +360,9 @@ public: * Function GetLibOptions * returns the options string for \a aLogicalLibraryName. * @param aLogicalLibraryName is the short name for the library of interest. - * @return const std::string* - or NULL if not found. + * @return const wxString* - or NULL if not found. */ - const std::string* GetLibOptions( const std::string& aLogicalLibraryName ) const + const wxString* GetLibOptions( const wxString& aLogicalLibraryName ) const { const ROW* row = FindRow( aLogicalLibraryName ); return row ? &row->options : 0; @@ -324,23 +382,24 @@ 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 * is not true and the key for aRow already exists, the function fails and returns false. - * The key for the table is the logicalName, and all in this table must be unique. + * The key for the table is the nickName, and all in this table must be unique. * @param aRow is the new row to insert, or to forcibly add if doReplace is true. * @param doReplace if true, means insert regardless of whether aRow's key already * exists. If false, then fail if the key already exists. * @return bool - true if the operation succeeded. */ - bool InsertRow( std::auto_ptr& aRow, bool doReplace = false ); + bool InsertRow( const ROW& aRow, bool doReplace = false ); /** * Function FindRow - * returns a #ROW* if aLogicalName is found in this table or in any chained + * returns a #ROW* if aNickName is found in this table or in any chained * fallBack table fragment, else NULL. */ - ROW* FindRow( const std::string& aLogicalName ) const; + ROW* FindRow( const wxString& aNickName ) const; private: +#if 0 // lets see what we need. /** * Function lookupLib * finds or loads a LIB based on @a aLogicalPartID or @a aFallBackLib. @@ -367,12 +426,24 @@ private: * already loaded. */ void loadLib( ROW* aRow ) throw( IO_ERROR ); +#endif - typedef boost::ptr_map ROWS; - typedef ROWS::iterator ROWS_ITER; - typedef ROWS::const_iterator ROWS_CITER; + typedef std::vector ROWS; + typedef ROWS::iterator ROWS_ITER; + typedef ROWS::const_iterator ROWS_CITER; ROWS rows; + + /// this is a non-owning index into the ROWS table + typedef std::map INDEX; // "int" is std::vector array index + typedef INDEX::iterator INDEX_ITER; + typedef INDEX::const_iterator INDEX_CITER; + typedef INDEX::value_type INDEX_VALUE; + + + /// the particular key is the nickName within each row. + INDEX nickIndex; + FP_LIB_TABLE* fallBack; }; From b1ea9d0eb50c7d9bd6d4d08738bf23c7214206fe Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Mon, 15 Oct 2012 16:48:01 -0400 Subject: [PATCH 3/9] Minor FP_LIB_ID object changes. --- common/fp_lib_id.cpp | 114 +++++++--------------------------------- common/fp_lib_table.cpp | 1 - include/fp_lib_id.h | 107 ++++++++++++++++--------------------- 3 files changed, 64 insertions(+), 158 deletions(-) diff --git a/common/fp_lib_id.cpp b/common/fp_lib_id.cpp index 33dd229306..e22df47d20 100644 --- a/common/fp_lib_id.cpp +++ b/common/fp_lib_id.cpp @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2012 Wayne Stambaugh * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors. * * This program is free software; you can redistribute it and/or @@ -76,31 +77,12 @@ int RevCmp( const char* s1, const char* s2 ) //----------------------------------------- -// These all return -1 on success, or >= 0 if there is an error at a -// particular character offset into their respective arguments. If >=0, -// then that return value gives the character offset of the error. - static inline int okLogical( const std::string& aField ) { // std::string::npos is largest positive number, casting to int makes it -1. // Returning that means success. - return int( aField.find_first_of( ":/" ) ); -} - - -static inline int okBase( const std::string& aField ) -{ - int offset = int( aField.find_first_of( ":/" ) ); - - if( offset != -1 ) - return offset; - - // cannot be empty - if( !aField.size() ) - return 0; - - return offset; // ie. -1 + return int( aField.find_first_of( ":" ) ); } @@ -120,13 +102,13 @@ static int okRevision( const std::string& aField ) return 0; // first character position "is in error", is best we can do. } + //----------------------------------------- void FP_LIB_ID::clear() { logical.clear(); - baseName.clear(); footprintName.clear(); revision.clear(); } @@ -139,7 +121,6 @@ int FP_LIB_ID::Parse( const std::string& aId ) const char* rev = EndsWithRev( aId ); size_t revNdx; size_t partNdx; - size_t baseNdx; int offset; //============================================== @@ -149,30 +130,28 @@ int FP_LIB_ID::Parse( const std::string& aId ) // no need to check revision, EndsWithRev did that. revision = aId.substr( revNdx ); - --revNdx; // back up to omit the '/' which preceeds the rev + --revNdx; // back up to omit the '/' which precedes the rev } else + { revNdx = aId.size(); + } //=============================================== if( ( partNdx = aId.find( ':' ) ) != aId.npos ) { offset = SetLogicalLib( aId.substr( 0, partNdx ) ); + if( offset > -1 ) { return offset; } + ++partNdx; // skip ':' } else - partNdx = 0; - - //=============================================== - offset = SetBaseName( aId.substr( baseNdx, revNdx - baseNdx ) ); - - if( offset > -1 ) { - return offset + baseNdx; + partNdx = 0; } return -1; @@ -207,37 +186,18 @@ int FP_LIB_ID::SetLogicalLib( const std::string& aLogical ) } -int FP_LIB_ID::SetBaseName( const std::string& aBaseName ) -{ - int offset = okBase( aBaseName ); - - if( offset == -1 ) - { - baseName = aBaseName; - } - - return offset; -} - - int FP_LIB_ID::SetFootprintName( const std::string& aFootprintName ) { - std::string base; - int offset; int separation = int( aFootprintName.find_first_of( "/" ) ); if( separation != -1 ) { - base = aFootprintName.substr( separation+1 ); + logical = aFootprintName.substr( separation+1 ); + return separation + (int) logical.size() + 1; } else { - base = aFootprintName; - } - - if( (offset = SetBaseName( base )) != -1 ) - { - return offset + separation + 1; + footprintName = aFootprintName; } return -1; @@ -267,8 +227,6 @@ std::string FP_LIB_ID::Format() const ret += ':'; } - ret += baseName; - if( revision.size() ) { ret += '/'; @@ -283,8 +241,6 @@ std::string FP_LIB_ID::GetFootprintNameAndRev() const { std::string ret; - ret += baseName; - if( revision.size() ) { ret += '/'; @@ -308,7 +264,7 @@ std::string FP_LIB_ID::Format( const std::string& aLogicalLib, const std::string if( offset != -1 ) { - THROW_PARSE_ERROR( _( "Illegal character found in logical lib name" ), + THROW_PARSE_ERROR( _( "Illegal character found in logical library name" ), wxString::FromUTF8( aLogicalLib.c_str() ), aLogicalLib.c_str(), 0, @@ -319,33 +275,6 @@ std::string FP_LIB_ID::Format( const std::string& aLogicalLib, const std::string ret += ':'; } - { - std::string base; - - int separation = int( aFootprintName.find_first_of( "/" ) ); - - if( separation != -1 ) - { - base = aFootprintName.substr( separation+1 ); - } - else - { - base = aFootprintName; - } - - - if( (offset = okBase( base )) != -1 ) - { - THROW_PARSE_ERROR( _( "Illegal character found in base name" ), - wxString::FromUTF8( aRevision.c_str() ), - aRevision.c_str(), - 0, - offset + separation + 1 ); - } - - ret += base; - } - if( aRevision.size() ) { offset = okRevision( aRevision ); @@ -374,16 +303,9 @@ std::string FP_LIB_ID::Format( const std::string& aLogicalLib, const std::string void FP_LIB_ID::Test() { static const char* lpids[] = { - "/R/rev0", - "passives/R/rev2", - ":passives/R/rev3", - "C/rev22", - "passives/C22", - "R", - "me:R", - // most difficult: - "me:/R/rev0", - "me:R/rev0", + "smt:R_0805/rev0", + "mysmt:R_0805/rev2", + "device:AXIAL-0500", }; for( unsigned i=0; i + * Copyright (C) 2010-2012 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2012 Wayne Stambaugh * Copyright (C) 2010 KiCad Developers, see change_log.txt for contributors. * * This program is free software; you can redistribute it and/or @@ -30,26 +31,26 @@ /** * Class FP_LIB_ID - * (aka GUID) is a Logical Part ID and consists of various portions much like a URI. - * It is a container for the separated portions of a logical part id std::string so they + * is a Logical Footprint ID and consists of various portions much like a URI. + * It is a container for the separated portions of a logical footprint id so they * can be accessed individually. The various portions of an FP_LIB_ID are: - * logicalLibraryName, category, baseName, and revision. Only the baseName is - * mandatory. There is another construct called "footprintName" which consists of - * [category/]baseName. That is the category followed by a slash, but only if - * the category is not empty. - *

- * footprintName = [category/]baseName - *

+ * logicalLibraryName (nick name), footprint name, and revision. The logical library + * name and the footprint name are mandatory. The revision is optional and currently is + * not used. + * * Example FP_LIB_ID string: - * "smt:R_0805". + * "smt:R_0805/rev0". + * *

*

    - *
  • "smt" is the logical library name. - *
  • "R" is the footprint name. - *
  • "rev6" is the revision, which is optional. If missing then its + *
  • "smt" is the logical library name used to look up library information saved in the + * #FP_LIB_TABLE. + *
  • "R" is the name of the footprint within the library. + *
  • "rev0" is the revision, which is optional. If missing then its * / delimiter should also not be present. A revision must begin with * "rev" and be followed by at least one or more decimal digits. *
+ * * @author Dick Hollenbeck */ class FP_LIB_ID // aka GUID @@ -60,26 +61,28 @@ public: /** * Constructor FP_LIB_ID - * takes \a aId string and parses it. A typical FP_LIB_ID string uses a logical + * takes \a aId string and parses it. A typical FP_LIB_ID string consists of a logical * library name followed by a footprint name. * e.g.: "smt:R_0805", or * e.g.: "mylib:R_0805" + * + * @param aId is a string to be parsed into the FP_LIB_ID object. */ FP_LIB_ID( const std::string& aId ) throw( PARSE_ERROR ); /** * Function Parse * [re-]stuffs this FP_LIB_ID with the information from @a aId. - * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the - * character offset into aId at which an error was detected. + * + * @param aId is the string to populate the #FP_LIB_ID object. + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the character offset into + * aId at which an error was detected. */ int Parse( const std::string& aId ); /** * Function GetLogicalLib - * returns the logical library portion of a FP_LIB_ID. There is not Set accessor - * for this portion since it comes from the library table and is considered - * read only here. + * returns the logical library name portion of a FP_LIB_ID. */ const std::string& GetLogicalLib() const { @@ -87,35 +90,17 @@ public: } /** - * Function SetCategory - * overrides the logical lib name portion of the FP_LIB_ID to @a aLogical, and can be empty. - * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the - * character offset into the parameter at which an error was detected, usually - * because it contained '/' or ':'. + * Function SetLogicalLib + * overrides the logical footprint library name portion of the FP_LIB_ID to @a aLogical. + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the character offset + * into the parameter at which an error was detected, usually because it + * contained '/' or ':'. */ int SetLogicalLib( const std::string& aLogical ); - /** - * Function GetBaseName - * returns the part name without the category. - */ - const std::string& GetBaseName() const - { - return baseName; - } - - /** - * Function SetBaseName - * overrides the base name portion of the FP_LIB_ID to @a aBaseName - * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the - * character offset into the parameter at which an error was detected, usually - * because it contained '/' or ':', or is blank. - */ - int SetBaseName( const std::string& aBaseName ); - /** * Function GetFootprintName - * returns the part name, i.e. category/baseName without revision. + * returns the footprint name, i.e. footprintName part without revision. */ const std::string& GetFootprintName() const { @@ -124,18 +109,17 @@ public: /** * Function GetFootprintNameAndRev - * returns the part name with revision if any, i.e. baseName[/revN..] + * returns the part name with revision if any, i.e. footprintName[/revN..] */ std::string GetFootprintNameAndRev() const; /** * Function SetFootprintName - * overrides the part name portion of the FP_LIB_ID to @a aFootprintName - * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the - * character offset into the parameter at which an error was detected, usually - * because it contained more than one '/', or one or more ':', or is blank. - * A single '/' is allowed, since that is used to separate the category from the - * base name. + * overrides the footprint name portion of the FP_LIB_ID to @a aFootprintName + * + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the character offset + * into the parameter at which an error was detected, usually because it contained + * more than one '/', or one or more ':', or is blank. */ int SetFootprintName( const std::string& aFootprintName ); @@ -152,15 +136,16 @@ public: * Function SetRevision * overrides the revision portion of the FP_LIB_ID to @a aRevision and must * be in the form "rev" where "" is "1", "2", etc. - * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the - * character offset into the parameter at which an error was detected, - * because it did not look like "rev23" + * + * @return int - minus 1 (i.e. -1) means success, >= 0 indicates the character offset* + * into the parameter at which an error was detected,because it did not + * look like "rev23" */ int SetRevision( const std::string& aRevision ); /** * Function Format - * returns the full text of the FP_LIB_ID. + * returns the fully formatted text of the FP_LIB_ID. */ std::string Format() const; @@ -168,6 +153,7 @@ public: * Function Format * returns a std::string in the proper format as an FP_LIB_ID for a combination of * aLogicalLib, aFootprintName, and aRevision. + * * @throw PARSE_ERROR if any of the pieces are illegal. */ static std::string Format( const std::string& aLogicalLib, const std::string& aFootprintName, @@ -182,25 +168,24 @@ public: protected: std::string logical; ///< logical lib name or empty - std::string baseName; ///< without category std::string revision; ///< "revN[N..]" or empty - std::string footprintName; ///< cannot be set directory, set via SetBaseName() & SetCategory() + std::string footprintName; ///< The name of the footprint in the logical library. }; /** * Function EndsWithRev * returns a pointer to the final string segment: "revN[N..]" or NULL if none. * @param start is the beginning of string segment to test, the partname or - * any middle portion of it. + * any middle portion of it. * @param tail is a pointer to the terminating nul, or one past inclusive end of - * segment, i.e. the string segment of interest is [start,tail) + * segment, i.e. the string segment of interest is [start,tail) * @param separator is the separating byte, expected: '.' or '/', depending on context. */ const char* EndsWithRev( const char* start, const char* tail, char separator = '/' ); static inline const char* EndsWithRev( const std::string& aFootprintName, char separator = '/' ) { - return EndsWithRev( aFootprintName.c_str(), aFootprintName.c_str()+aFootprintName.size(), + return EndsWithRev( aFootprintName.c_str(), aFootprintName.c_str()+aFootprintName.size(), separator ); } @@ -213,7 +198,7 @@ static inline const char* EndsWithRev( const std::string& aFootprintName, char s * @param s1 is a rev string like "rev10" * @param s2 is a rev string like "rev1". * @return int - either negative, zero, or positive depending on whether the revision - * is greater, equal, or less on the left hand side. + * is greater, equal, or less on the left hand side. */ int RevCmp( const char* s1, const char* s2 ); From ae19bbfa331a7f43409ad90ac7a3dbff4b80fd3a Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Mon, 15 Oct 2012 17:30:01 -0500 Subject: [PATCH 4/9] add dialog for fp_lib_table --- common/fp_lib_table.cpp | 95 +- include/dlist.h | 9 +- include/fp_lib_table.h | 163 ++- include/wxPcbStruct.h | 18 +- pcbnew/CMakeLists.txt | 62 +- pcbnew/dialogs/dialog_fp_lib_table.cpp | 56 + pcbnew/dialogs/dialog_fp_lib_table_base.cpp | 213 +++ pcbnew/dialogs/dialog_fp_lib_table_base.fbp | 1451 +++++++++++++++++++ pcbnew/dialogs/dialog_fp_lib_table_base.h | 75 + pcbnew/menubar_pcbframe.cpp | 4 + pcbnew/pcbframe.cpp | 1 + pcbnew/pcbnew_config.cpp | 24 +- pcbnew/pcbnew_id.h | 5 +- 13 files changed, 2038 insertions(+), 138 deletions(-) create mode 100644 pcbnew/dialogs/dialog_fp_lib_table.cpp create mode 100644 pcbnew/dialogs/dialog_fp_lib_table_base.cpp create mode 100644 pcbnew/dialogs/dialog_fp_lib_table_base.fbp create mode 100644 pcbnew/dialogs/dialog_fp_lib_table_base.h diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 9b619004a4..0ce214f9ef 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010-12 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors. * @@ -39,7 +39,7 @@ FP_LIB_TABLE::FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable ) : fallBack( aFallBackTable ) { // not copying fall back, simply search aFallBackTable separately - // if "logicalName not found". + // if "nickName not found". } @@ -68,9 +68,9 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - std::auto_ptr row( new ROW( this ) ); + ROW row( this ); - row->SetLogicalName( in->CurText() ); + row.SetNickName( in->FromUTF8() ); in->NeedRIGHT(); @@ -82,7 +82,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - row->SetType( in->CurText() ); + row.SetType( in->FromUTF8() ); in->NeedRIGHT(); @@ -94,7 +94,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - row->SetFullURI( in->CurText() ); + row.SetFullURI( in->FromUTF8() ); in->NeedRIGHT(); @@ -106,23 +106,21 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - row->SetOptions( in->CurText() ); + row.SetOptions( in->FromUTF8() ); in->NeedRIGHT(); in->NeedRIGHT(); // terminate the (lib..) - // all logicalNames within this table fragment must be unique, so we do not + // all nickNames within this table fragment must be unique, so we do not // use doReplace in InsertRow(). However a fallBack table can have a - // conflicting logicalName and ours will supercede that one since in + // conflicting nickName and ours will supercede that one since in // FindLib() we search this table before any fall back. if( !InsertRow( row ) ) { - std::string msg; - - msg += '\''; - msg += row->logicalName; - msg += '\''; - msg += " is a duplicate logical footprint library name"; + wxString msg = wxString::Format( + _( "'%s' is a duplicate footprint library nickName" ), + GetChars( row.nickName ) + ); THROW_IO_ERROR( msg ); } } @@ -135,7 +133,7 @@ void FP_LIB_TABLE::Format( OUTPUTFORMATTER* out, int nestLevel ) const out->Print( nestLevel, "(fp_lib_table\n" ); for( ROWS_CITER it = rows.begin(); it != rows.end(); ++it ) - it->second->Format( out, nestLevel+1 ); + it->Format( out, nestLevel+1 ); out->Print( nestLevel, ")\n" ); } @@ -144,48 +142,50 @@ 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 (logical %s)(type %s)(full_uri %s)(options %s))\n", - out->Quotes( logicalName ).c_str(), - out->Quotes( type ).c_str(), - out->Quotes( uri ).c_str(), - out->Quotes( options ).c_str() ); + 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() + ); } -std::vector FP_LIB_TABLE::GetLogicalLibs() +std::vector FP_LIB_TABLE::GetLogicalLibs() { // Only return unique logical library names. Use std::set::insert() to // quietly reject any duplicates, which can happen when encountering a duplicate - // logical lib name from one of the fall back table(s). + // nickname from one of the fall back table(s). - std::set unique; - std::vector ret; - const FP_LIB_TABLE* cur = this; + std::set unique; + std::vector ret; + const FP_LIB_TABLE* cur = this; do { for( ROWS_CITER it = cur->rows.begin(); it!=cur->rows.end(); ++it ) { - unique.insert( it->second->logicalName ); + unique.insert( it->nickName ); } } while( ( cur = cur->fallBack ) != 0 ); - // return a sorted, unique set of logical lib name std::vector to caller - for( std::set::const_iterator it = unique.begin(); it!=unique.end(); ++it ) + // return a sorted, unique set of nicknames in a std::vector to caller + for( std::set::const_iterator it = unique.begin(); it!=unique.end(); ++it ) ret.push_back( *it ); return ret; } +#if 0 // will need PLUGIN_RELEASER. MODULE* FP_LIB_TABLE::LookupFootprint( const FP_LIB_ID& aFootprintId ) throw( IO_ERROR ) { PLUGIN* plugin = lookupLib( aFootprintId ); - return plugin->FootprintLoad( wxString( aFootprintId.GetBaseName().c_str() ), - wxString( aFootprintId.GetLogicalLib().c_str() ) ); + return plugin->FootprintLoad( FROM_UTF8( aFootprintId.GetBaseName().c_str() ), + FROM_UTF8( aFootprintId.GetLogicalLib().c_str() ) ); } @@ -254,24 +254,22 @@ void FP_LIB_TABLE::loadLib( ROW* aRow ) throw( IO_ERROR ) THROW_IO_ERROR( msg ); } } +#endif -FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const std::string& aLogicalName ) const +FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aNickName ) const { // this function must be *super* fast, so therefore should not instantiate - // anything which would require using the heap. This function is the reason - // ptr_map<> was used instead of ptr_set<>, which would have required - // instantiating a ROW just to find a ROW. + // anything which would require using the heap. const FP_LIB_TABLE* cur = this; do { - ROWS_CITER it = cur->rows.find( aLogicalName ); + INDEX_CITER it = cur->nickIndex.find( aNickName ); - if( it != cur->rows.end() ) + if( it != cur->nickIndex.end() ) { - // reference: http://myitcorner.com/blog/?p=361 - return (FP_LIB_TABLE::ROW*) it->second; // found + return (FP_LIB_TABLE::ROW*) &cur->rows[it->second]; // found } // not found, search fall back table(s), if any @@ -281,29 +279,22 @@ FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const std::string& aLogicalName ) cons } -bool FP_LIB_TABLE::InsertRow( std::auto_ptr& aRow, bool doReplace ) +bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace ) { // this does not need to be super fast. - ROWS_CITER it = rows.find( aRow->logicalName ); + INDEX_CITER it = nickIndex.find( aRow.nickName ); - if( it == rows.end() ) + if( it == nickIndex.end() ) { - // be careful here, key is needed because aRow can be - // release()ed before logicalName is captured. - const std::string& key = aRow->logicalName; - rows.insert( key, aRow ); + rows.push_back( aRow ); + nickIndex.insert( INDEX_VALUE( aRow.nickName, rows.size() - 1 ) ); return true; } if( doReplace ) { - rows.erase( aRow->logicalName ); - - // be careful here, key is needed because aRow can be - // release()ed before logicalName is captured. - const std::string& key = aRow->logicalName; - rows.insert( key, aRow ); + rows[it->second] = aRow; return true; } diff --git a/include/dlist.h b/include/dlist.h index 2acf80271c..b3f7284074 100644 --- a/include/dlist.h +++ b/include/dlist.h @@ -27,9 +27,6 @@ #define DLIST_H_ -#include // NULL definition. - - class EDA_ITEM; @@ -216,20 +213,20 @@ public: //-----< STL like functions >--------------------------------------- T* begin() const { return GetFirst(); } - T* end() const { return NULL; } + T* end() const { return 0; } T* PopFront() { if( GetFirst() ) return Remove( GetFirst() ); - return NULL; + return 0; } T* PopBack() { if( GetLast() ) return Remove( GetLast() ); - return NULL; + return 0; } /** diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index c304864da1..70ced4838f 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2010-12 SoftPLC Corporation, Dick Hollenbeck * Copyright (C) 2012 Wayne Stambaugh * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors. * @@ -26,16 +26,18 @@ #ifndef _FP_LIB_TABLE_H_ #define _FP_LIB_TABLE_H_ +#include +#include +#include + +#include #include -#include - class OUTPUTFORMATTER; - - class MODULE; +class FP_LIB_TABLE_LEXER; /** * Class FP_LIB_TABLE @@ -78,7 +80,7 @@ class MODULE; * * @author Wayne Stambaugh */ -class FP_LIB_TABLE +class FP_LIB_TABLE : public wxGridTableBase { public: @@ -94,19 +96,19 @@ public: public: /** - * Function GetLogicalName - * returns the logical name of this library table row. + * Function GetNickName + * returns the short name of this library table row. */ - const std::string& GetLogicalName() const + const wxString& GetNickName() const { - return logicalName; + return nickName; } /** * Function GetType * returns the type of LIB represented by this record. */ - const std::string& GetType() const + const wxString& GetType() const { return type; } @@ -115,7 +117,7 @@ public: * Function GetFullURI * returns the full location specifying URI for the LIB. */ - const std::string& GetFullURI() const + const wxString& GetFullURI() const { return uri; } @@ -125,14 +127,14 @@ public: * returns the options string, which may hold a password or anything else needed to * instantiate the underlying LIB_SOURCE. */ - const std::string& GetOptions() const + const wxString& GetOptions() const { return options; } ~ROW() { - delete lib; + // delete lib; } /** @@ -149,24 +151,24 @@ public: protected: ROW( FP_LIB_TABLE* aOwner ) : - owner( aOwner ), - lib( 0 ) + owner( aOwner ) + // lib( 0 ) {} /** - * Function SetLogicalName + * Function SetNickName * changes the logical name of this library, useful for an editor. */ - void SetLogicalName( const std::string& aLogicalName ) + void SetNickName( const wxString& aNickName ) { - logicalName = aLogicalName; + nickName = aNickName; } /** * Function SetType * changes the type represented by this record. */ - void SetType( const std::string& aType ) + void SetType( const wxString& aType ) { type = aType; } @@ -175,7 +177,7 @@ public: * Function SetFullURI * changes the full URI for the library, useful from a library table editor. */ - void SetFullURI( const std::string& aFullURI ) + void SetFullURI( const wxString& aFullURI ) { uri = aFullURI; } @@ -185,21 +187,24 @@ public: * changes the options string for this record, and is useful from * the library table editor. */ - void SetOptions( const std::string& aOptions ) + void SetOptions( const wxString& aOptions ) { options = aOptions; } private: - FP_LIB_TABLE* owner; - std::string logicalName; - std::string type; - std::string uri; - std::string options; + FP_LIB_TABLE* owner; + wxString nickName; + wxString type; + wxString uri; + wxString options; - PLUGIN* lib; ///< ownership of the loaded LIB is here + /* + PLUGIN* lib; ///< ownership of the loaded LIB is here + */ }; + /** * Constructor FP_LIB_TABLE * builds a library table by pre-pending this table fragment in front of @@ -246,6 +251,7 @@ 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 @@ -262,25 +268,83 @@ public: * @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 * returns the logical library names, all of them that are pertinent to * a lookup done on this FP_LIB_TABLE. */ - std::vector GetLogicalLibs(); + std::vector GetLogicalLibs(); + + + //------------------------------------------------ + + int GetNumberRows () { return rows.size(); } + int GetNumberCols () { return 4; } + + wxString GetValue( int aRow, int aCol ) + { + if( unsigned( aRow ) < rows.size() ) + { + const ROW& r = rows[aRow]; + + switch( aCol ) + { + case 0: return r.GetNickName(); + case 1: return r.GetType(); + case 2: return r.GetFullURI(); + case 3: return r.GetOptions(); + default: + ; // fall thru to wxEmptyString + } + } + + return wxEmptyString; + } + + void SetValue( int aRow, int aCol, const wxString &aValue ) + { + if( aCol == 0 ) + { + // when the nickname is changed, there's careful work to do, including + // ensuring uniqueness of the nickname. + } + else if( unsigned( aRow ) < rows.size() ) + { + ROW& r = rows[aRow]; + + switch( aCol ) + { + case 1: r.SetType( aValue ); + case 2: r.SetFullURI( aValue ); + case 3: r.SetOptions( aValue ); + } + } + } + + bool IsEmptyCell( int aRow, int aCol ) + { + if( unsigned( aRow ) < rows.size() ) + return false; + return true; + } + + //----------------------------------------------- + //-------------------------------------------------------- - // the returning of a const std::string* tells if not found, but might be too + // the returning of a const wxString* tells if not found, but might be too // promiscuous? /** * Function GetURI * returns the full library path from a logical library name. * @param aLogicalLibraryName is the short name for the library of interest. - * @return const std::string* - or NULL if not found. + * @return const wxString* - or NULL if not found. */ - const std::string* GetURI( const std::string& aLogicalLibraryName ) const + const wxString* GetURI( const wxString& aLogicalLibraryName ) const { const ROW* row = FindRow( aLogicalLibraryName ); return row ? &row->uri : 0; @@ -290,9 +354,9 @@ public: * Function GetType * returns the type of a logical library. * @param aLogicalLibraryName is the short name for the library of interest. - * @return const std::string* - or NULL if not found. + * @return const wxString* - or NULL if not found. */ - const std::string* GetType( const std::string& aLogicalLibraryName ) const + const wxString* GetType( const wxString& aLogicalLibraryName ) const { const ROW* row = FindRow( aLogicalLibraryName ); return row ? &row->type : 0; @@ -302,9 +366,9 @@ public: * Function GetLibOptions * returns the options string for \a aLogicalLibraryName. * @param aLogicalLibraryName is the short name for the library of interest. - * @return const std::string* - or NULL if not found. + * @return const wxString* - or NULL if not found. */ - const std::string* GetLibOptions( const std::string& aLogicalLibraryName ) const + const wxString* GetLibOptions( const wxString& aLogicalLibraryName ) const { const ROW* row = FindRow( aLogicalLibraryName ); return row ? &row->options : 0; @@ -324,23 +388,24 @@ 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 * is not true and the key for aRow already exists, the function fails and returns false. - * The key for the table is the logicalName, and all in this table must be unique. + * The key for the table is the nickName, and all in this table must be unique. * @param aRow is the new row to insert, or to forcibly add if doReplace is true. * @param doReplace if true, means insert regardless of whether aRow's key already * exists. If false, then fail if the key already exists. * @return bool - true if the operation succeeded. */ - bool InsertRow( std::auto_ptr& aRow, bool doReplace = false ); + bool InsertRow( const ROW& aRow, bool doReplace = false ); /** * Function FindRow - * returns a #ROW* if aLogicalName is found in this table or in any chained + * returns a #ROW* if aNickName is found in this table or in any chained * fallBack table fragment, else NULL. */ - ROW* FindRow( const std::string& aLogicalName ) const; + ROW* FindRow( const wxString& aNickName ) const; private: +#if 0 // lets see what we need. /** * Function lookupLib * finds or loads a LIB based on @a aLogicalPartID or @a aFallBackLib. @@ -367,12 +432,24 @@ private: * already loaded. */ void loadLib( ROW* aRow ) throw( IO_ERROR ); +#endif - typedef boost::ptr_map ROWS; - typedef ROWS::iterator ROWS_ITER; - typedef ROWS::const_iterator ROWS_CITER; + typedef std::vector ROWS; + typedef ROWS::iterator ROWS_ITER; + typedef ROWS::const_iterator ROWS_CITER; ROWS rows; + + /// this is a non-owning index into the ROWS table + typedef std::map INDEX; // "int" is std::vector array index + typedef INDEX::iterator INDEX_ITER; + typedef INDEX::const_iterator INDEX_CITER; + typedef INDEX::value_type INDEX_VALUE; + + + /// the particular key is the nickName within each row. + INDEX nickIndex; + FP_LIB_TABLE* fallBack; }; diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 58d859d5fa..a398f68c2a 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -26,8 +26,8 @@ * @file wxPcbStruct.h */ -#ifndef WXPCB_STRUCT_H -#define WXPCB_STRUCT_H +#ifndef WXPCB_STRUCT_H_ +#define WXPCB_STRUCT_H_ #include @@ -1604,4 +1604,16 @@ public: }; -#endif /* WXPCB_STRUCT_H */ +class FP_LIB_TABLE; + +/** + * Function InvokePcbLibTableEditor + * shows the modal DIALOG_FP_LIB_TABLE for purposes of editing two lib tables. + * + * @return int - bits 0 and 1 tell whether a change was made to the @a aGlobal + * and/or the @a aProject table, respectively. If set, table was modified. + */ +int InvokePcbLibTableEditor( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ); + + +#endif // WXPCB_STRUCT_H_ diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index ffc56cdfde..02814ff9e7 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -50,6 +50,8 @@ set(PCBNEW_DIALOGS dialogs/dialog_export_3Dfiles_base.cpp dialogs/dialog_find_base.cpp dialogs/dialog_find.cpp + dialogs/dialog_fp_lib_table_base.cpp + dialogs/dialog_fp_lib_table.cpp dialogs/dialog_freeroute_exchange.cpp dialogs/dialog_freeroute_exchange_base.cpp dialogs/dialog_gendrill.cpp @@ -247,11 +249,11 @@ set(PCBNEW_SCRIPTING_PYTHON_HELPERS ) if (KICAD_SCRIPTING) - set(PCBNEW_SCRIPTING_SRCS - ${PCBNEW_SCRIPTING_DIALOGS} - pcbnew_wrap.cxx - ${PCBNEW_SCRIPTING_PYTHON_HELPERS} - ) + set(PCBNEW_SCRIPTING_SRCS + ${PCBNEW_SCRIPTING_DIALOGS} + pcbnew_wrap.cxx + ${PCBNEW_SCRIPTING_PYTHON_HELPERS} + ) endif(KICAD_SCRIPTING) ## @@ -260,34 +262,34 @@ endif(KICAD_SCRIPTING) if (KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES) - set(SWIG_FLAGS -I${CMAKE_CURRENT_SOURCE_DIR}/../.. -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_CURRENT_SOURCE_DIR}/../include -I${CMAKE_CURRENT_SOURCE_DIR}/../scripting ) - if (DEBUG) - set(SWIG_FLAGS ${SWIG_FLAGS} -DDEBUG) - endif(DEBUG) - # collect CFLAGS , and pass them to swig later + set(SWIG_FLAGS -I${CMAKE_CURRENT_SOURCE_DIR}/../.. -I${CMAKE_CURRENT_SOURCE_DIR} -I${CMAKE_CURRENT_SOURCE_DIR}/../include -I${CMAKE_CURRENT_SOURCE_DIR}/../scripting ) + if (DEBUG) + set(SWIG_FLAGS ${SWIG_FLAGS} -DDEBUG) + endif(DEBUG) + # collect CFLAGS , and pass them to swig later - get_directory_property( DirDefs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS ) - foreach( d ${DirDefs} ) - SET(SWIG_FLAGS ${SWIG_FLAGS} -D${d} ) - endforeach() + get_directory_property( DirDefs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS ) + foreach( d ${DirDefs} ) + SET(SWIG_FLAGS ${SWIG_FLAGS} -D${d} ) + endforeach() - # check if we have IO_MGR and KICAD_PLUGIN available - if ( USE_NEW_PCBNEW_LOAD OR USE_NEW_PCBNEW_SAVE ) - SET(SWIG_FLAGS ${SWIG_FLAGS} -DBUILD_WITH_PLUGIN) - endif(USE_NEW_PCBNEW_LOAD OR USE_NEW_PCBNEW_SAVE) + # check if we have IO_MGR and KICAD_PLUGIN available + if ( USE_NEW_PCBNEW_LOAD OR USE_NEW_PCBNEW_SAVE ) + SET(SWIG_FLAGS ${SWIG_FLAGS} -DBUILD_WITH_PLUGIN) + endif(USE_NEW_PCBNEW_LOAD OR USE_NEW_PCBNEW_SAVE) - if ( USE_PCBNEW_NANOMETRES ) - SET(SWIG_FLAGS ${SWIG_FLAGS} -DUSE_PCBNEW_NANOMETRES) - endif( USE_PCBNEW_NANOMETRES ) + if ( USE_PCBNEW_NANOMETRES ) + SET(SWIG_FLAGS ${SWIG_FLAGS} -DUSE_PCBNEW_NANOMETRES) + endif( USE_PCBNEW_NANOMETRES ) endif(KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES) if (KICAD_SCRIPTING) - SET(SWIG_OPTS -python -c++ -outdir ${CMAKE_CURRENT_BINARY_DIR} ${SWIG_FLAGS} ) + SET(SWIG_OPTS -python -c++ -outdir ${CMAKE_CURRENT_BINARY_DIR} ${SWIG_FLAGS} ) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx DEPENDS scripting/pcbnew.i DEPENDS scripting/board.i DEPENDS scripting/board_item.i @@ -299,10 +301,10 @@ if (KICAD_SCRIPTING) DEPENDS ../scripting/wx.i DEPENDS ../scripting/kicadplugins.i - COMMAND ${SWIG_EXECUTABLE} ${SWIG_OPTS} -o ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx scripting/pcbnew.i - COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../scripting/fixswigimports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) + COMMAND ${SWIG_EXECUTABLE} ${SWIG_OPTS} -o ${CMAKE_CURRENT_BINARY_DIR}/pcbnew_wrap.cxx scripting/pcbnew.i + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../scripting/fixswigimports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) endif(KICAD_SCRIPTING) @@ -430,7 +432,7 @@ install(TARGETS pcbnew COMPONENT binary) if(KICAD_SCRIPTING) - add_custom_target(FixSwigImportsScripting ALL + add_custom_target(FixSwigImportsScripting ALL COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../scripting/fixswigimports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/pcbnew COMMENT "Fixing swig_import_helper in Kicad scripting" @@ -442,7 +444,7 @@ if(KICAD_SCRIPTING) endif(KICAD_SCRIPTING) if (KICAD_SCRIPTING_MODULES) - add_custom_target(FixSwigImportsModuleScripting ALL + add_custom_target(FixSwigImportsModuleScripting ALL COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../scripting/fixswigimports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_pcbnew COMMENT "Fixing swig_import_helper in Kicad scripting modules" diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp new file mode 100644 index 0000000000..08978ea663 --- /dev/null +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -0,0 +1,56 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck + * Copyright (C) 2012 Wayne Stambaugh + * Copyright (C) 2012 KiCad Developers, see change_log.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + + +#include +#include + +/** + * Class DIALOG_FP_LIB_TABLE + * shows and edits the PCB library tables. Two tables are expected, one global + * and one project specific. + */ +class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE +{ + +public: + DIALOG_FP_LIB_TABLE( wxFrame* aParent ) : + DIALOG_FP_LIB_TABLE_BASE( aParent ) + { + } +}; + + + +int InvokePcbLibTableEditor( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) +{ + DIALOG_FP_LIB_TABLE dlg( aParent ); + + dlg.Show( true ); + + return 0; +} + diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp new file mode 100644 index 0000000000..dd5d8226d2 --- /dev/null +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp @@ -0,0 +1,213 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Oct 8 2012) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#include "dialog_fp_lib_table_base.h" + +/////////////////////////////////////////////////////////////////////////// + +DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxDefaultSize, wxDefaultSize ); + + wxBoxSizer* bSizer1; + bSizer1 = new wxBoxSizer( wxVERTICAL ); + + m_splitter1 = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_3DBORDER ); + m_splitter1->Connect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FP_LIB_TABLE_BASE::m_splitter1OnIdle ), NULL, this ); + m_splitter1->SetMinimumPaneSize( 10 ); + + m_top = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxStaticBoxSizer* sbSizer3; + sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_top, wxID_ANY, _("Global and Project Scope") ), wxVERTICAL ); + + m_auinotebook2 = new wxAuiNotebook( m_top, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_DEFAULT_STYLE ); + m_panel4 = new wxPanel( m_auinotebook2, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_panel4->SetToolTip( _("Module libraries which are visible for all projects") ); + + wxBoxSizer* bSizer4; + bSizer4 = new wxBoxSizer( wxVERTICAL ); + + m_grid1 = new wxGrid( m_panel4, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + m_grid1->CreateGrid( 1, 4 ); + m_grid1->EnableEditing( true ); + m_grid1->EnableGridLines( true ); + m_grid1->EnableDragGridSize( false ); + m_grid1->SetMargins( 0, 0 ); + + // Columns + m_grid1->AutoSizeColumns(); + m_grid1->EnableDragColMove( false ); + m_grid1->EnableDragColSize( true ); + m_grid1->SetColLabelSize( 30 ); + m_grid1->SetColLabelValue( 0, _("Nickname") ); + m_grid1->SetColLabelValue( 1, _("Library Path") ); + m_grid1->SetColLabelValue( 2, _("Plugin") ); + m_grid1->SetColLabelValue( 3, _("Options") ); + m_grid1->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_grid1->AutoSizeRows(); + m_grid1->EnableDragRowSize( true ); + m_grid1->SetRowLabelSize( 80 ); + m_grid1->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_grid1->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + bSizer4->Add( m_grid1, 1, wxALL|wxEXPAND, 5 ); + + + m_panel4->SetSizer( bSizer4 ); + m_panel4->Layout(); + bSizer4->Fit( m_panel4 ); + m_auinotebook2->AddPage( m_panel4, _("Global Libraries"), false, wxNullBitmap ); + m_panel5 = new wxPanel( m_auinotebook2, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizer5; + bSizer5 = new wxBoxSizer( wxVERTICAL ); + + m_grid11 = new wxGrid( m_panel5, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + m_grid11->CreateGrid( 1, 4 ); + m_grid11->EnableEditing( true ); + m_grid11->EnableGridLines( true ); + m_grid11->EnableDragGridSize( false ); + m_grid11->SetMargins( 0, 0 ); + + // Columns + m_grid11->AutoSizeColumns(); + m_grid11->EnableDragColMove( false ); + m_grid11->EnableDragColSize( true ); + m_grid11->SetColLabelSize( 30 ); + m_grid11->SetColLabelValue( 0, _("Nickname") ); + m_grid11->SetColLabelValue( 1, _("Library Path") ); + m_grid11->SetColLabelValue( 2, _("Plugin") ); + m_grid11->SetColLabelValue( 3, _("Options") ); + m_grid11->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_grid11->AutoSizeRows(); + m_grid11->EnableDragRowSize( true ); + m_grid11->SetRowLabelSize( 80 ); + m_grid11->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_grid11->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + bSizer5->Add( m_grid11, 0, wxALL, 5 ); + + + m_panel5->SetSizer( bSizer5 ); + m_panel5->Layout(); + bSizer5->Fit( m_panel5 ); + m_auinotebook2->AddPage( m_panel5, _("Project Specific Libraries"), true, wxNullBitmap ); + + sbSizer3->Add( m_auinotebook2, 1, wxEXPAND | wxALL, 5 ); + + wxBoxSizer* bSizer51; + bSizer51 = new wxBoxSizer( wxHORIZONTAL ); + + m_button1 = new wxButton( m_top, wxID_ANY, _("Append Row"), wxDefaultPosition, wxDefaultSize, 0 ); + m_button1->SetToolTip( _("Add a pcb library row to this table") ); + + bSizer51->Add( m_button1, 0, wxALL, 5 ); + + m_button2 = new wxButton( m_top, wxID_ANY, _("Delete Row"), wxDefaultPosition, wxDefaultSize, 0 ); + m_button2->SetToolTip( _("Remove a PCB library from this library table") ); + + bSizer51->Add( m_button2, 0, wxALL, 5 ); + + m_button3 = new wxButton( m_top, wxID_ANY, _("Move Up"), wxDefaultPosition, wxDefaultSize, 0 ); + m_button3->SetToolTip( _("Move the currently selected row up one position") ); + + bSizer51->Add( m_button3, 0, wxALL, 5 ); + + m_button4 = new wxButton( m_top, wxID_ANY, _("Move Down"), wxDefaultPosition, wxDefaultSize, 0 ); + m_button4->SetToolTip( _("Move the currently selected row down one position") ); + + bSizer51->Add( m_button4, 0, wxALL, 5 ); + + + sbSizer3->Add( bSizer51, 0, wxALIGN_CENTER, 5 ); + + + m_top->SetSizer( sbSizer3 ); + m_top->Layout(); + sbSizer3->Fit( m_top ); + m_bottom = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizer8; + bSizer8 = new wxBoxSizer( wxVERTICAL ); + + wxStaticBoxSizer* sbSizer1; + sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( m_bottom, wxID_ANY, _("Path Substitutions") ), wxVERTICAL ); + + m_grid2 = new wxGrid( m_bottom, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + m_grid2->CreateGrid( 2, 2 ); + m_grid2->EnableEditing( true ); + m_grid2->EnableGridLines( true ); + m_grid2->EnableDragGridSize( false ); + m_grid2->SetMargins( 0, 0 ); + + // Columns + m_grid2->SetColSize( 0, 150 ); + m_grid2->SetColSize( 1, 500 ); + m_grid2->EnableDragColMove( false ); + m_grid2->EnableDragColSize( true ); + m_grid2->SetColLabelSize( 30 ); + m_grid2->SetColLabelValue( 0, _("Category") ); + m_grid2->SetColLabelValue( 1, _("Path Segment") ); + m_grid2->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_grid2->EnableDragRowSize( true ); + m_grid2->SetRowLabelSize( 40 ); + m_grid2->SetRowLabelValue( 0, _("%S") ); + m_grid2->SetRowLabelValue( 1, _("%P") ); + m_grid2->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_grid2->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + sbSizer1->Add( m_grid2, 0, wxALL, 5 ); + + + bSizer8->Add( sbSizer1, 1, wxALL|wxEXPAND, 5 ); + + m_sdbSizer1 = new wxStdDialogButtonSizer(); + m_sdbSizer1OK = new wxButton( m_bottom, wxID_OK ); + m_sdbSizer1->AddButton( m_sdbSizer1OK ); + m_sdbSizer1Cancel = new wxButton( m_bottom, wxID_CANCEL ); + m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); + m_sdbSizer1->Realize(); + + bSizer8->Add( m_sdbSizer1, 0, wxALL|wxEXPAND, 5 ); + + + m_bottom->SetSizer( bSizer8 ); + m_bottom->Layout(); + bSizer8->Fit( m_bottom ); + m_splitter1->SplitHorizontally( m_top, m_bottom, 254 ); + bSizer1->Add( m_splitter1, 2, wxEXPAND, 5 ); + + + this->SetSizer( bSizer1 ); + this->Layout(); + bSizer1->Fit( this ); + + this->Centre( wxBOTH ); +} + +DIALOG_FP_LIB_TABLE_BASE::~DIALOG_FP_LIB_TABLE_BASE() +{ +} diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp new file mode 100644 index 0000000000..5b9038d16a --- /dev/null +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp @@ -0,0 +1,1451 @@ + + + + + + C++ + 1 + source_name + 0 + 0 + res + UTF-8 + connect + dialog_fp_lib_table_base + 1000 + none + 1 + MyProject1 + + . + + 1 + 1 + 1 + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + DIALOG_FP_LIB_TABLE_BASE + + -1,-1 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + PCB Library Tables + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer1 + wxVERTICAL + none + + 5 + wxEXPAND + 2 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 10 + + 0 + + 1 + m_splitter1 + 1 + + + protected + 1 + + Resizable + 0.0 + 254 + -1 + 1 + + wxSPLIT_HORIZONTAL + wxSP_3D|wxSP_3DBORDER + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_top + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + wxID_ANY + Global and Project Scope + + sbSizer3 + wxVERTICAL + none + + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_auinotebook2 + 1 + + + protected + 1 + + Resizable + 1 + + wxAUI_NB_DEFAULT_STYLE + + -1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Global Libraries + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panel4 + 1 + + + protected + 0 + + Resizable + 1 + + + 0 + Module libraries which are visible for all projects + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer4 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + 1 + 1 + + + + 1 + + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 30 + "Nickname" "Library Path" "Plugin" "Options" + wxALIGN_CENTRE + 4 + + + 1 + 0 + Dock + 0 + Left + 0 + 1 + 0 + 1 + 1 + 1 + + 1 + + + 1 + 0 + 0 + wxID_ANY + + + + 0 + 0 + + 0 + + + 0 + + 1 + m_grid1 + 1 + + + protected + 1 + + Fixed + wxALIGN_CENTRE + 80 + + wxALIGN_CENTRE + + 1 + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Project Specific Libraries + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panel5 + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer5 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + 1 + 1 + + + + 1 + + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 30 + "Nickname" "Library Path" "Plugin" "Options" + wxALIGN_CENTRE + 4 + + + 1 + 0 + Dock + 0 + Left + 0 + 1 + 0 + 1 + 1 + 1 + + 1 + + + 1 + 0 + 0 + wxID_ANY + + + + 0 + 0 + + 0 + + + 0 + + 1 + m_grid11 + 1 + + + protected + 1 + + Fixed + wxALIGN_CENTRE + 80 + + wxALIGN_CENTRE + + 1 + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER + 0 + + + bSizer51 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Append Row + + 0 + + + 0 + + 1 + m_button1 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Add a pcb library row to this table + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Delete Row + + 0 + + + 0 + + 1 + m_button2 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Remove a PCB library from this library table + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Move Up + + 0 + + + 0 + + 1 + m_button3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Move the currently selected row up one position + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Move Down + + 0 + + + 0 + + 1 + m_button4 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Move the currently selected row down one position + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_bottom + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + bSizer8 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + wxID_ANY + Path Substitutions + + sbSizer1 + wxVERTICAL + none + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + 0 + + + + 1 + + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 30 + "Category" "Path Segment" + wxALIGN_CENTRE + 2 + 150,500 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + 0 + 1 + 1 + 1 + + 1 + + + 1 + 0 + 0 + wxID_ANY + + + + 0 + 0 + + 0 + + + 0 + + 1 + m_grid2 + 1 + + + protected + 1 + + Resizable + wxALIGN_CENTRE + 40 + "%S" "%P" + wxALIGN_CENTRE + + 2 + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxEXPAND + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer1 + protected + + + + + + + + + + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.h b/pcbnew/dialogs/dialog_fp_lib_table_base.h new file mode 100644 index 0000000000..f65b923c2a --- /dev/null +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.h @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////// +// C++ code generated with wxFormBuilder (version Oct 8 2012) +// http://www.wxformbuilder.org/ +// +// PLEASE DO "NOT" EDIT THIS FILE! +/////////////////////////////////////////////////////////////////////////// + +#ifndef __DIALOG_FP_LIB_TABLE_BASE_H__ +#define __DIALOG_FP_LIB_TABLE_BASE_H__ + +#include +#include +#include +class DIALOG_SHIM; + +#include "dialog_shim.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_FP_LIB_TABLE_BASE +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_FP_LIB_TABLE_BASE : public DIALOG_SHIM +{ + private: + + protected: + wxSplitterWindow* m_splitter1; + wxPanel* m_top; + wxAuiNotebook* m_auinotebook2; + wxPanel* m_panel4; + wxGrid* m_grid1; + wxPanel* m_panel5; + wxGrid* m_grid11; + wxButton* m_button1; + wxButton* m_button2; + wxButton* m_button3; + wxButton* m_button4; + wxPanel* m_bottom; + wxGrid* m_grid2; + wxStdDialogButtonSizer* m_sdbSizer1; + wxButton* m_sdbSizer1OK; + wxButton* m_sdbSizer1Cancel; + + 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( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_FP_LIB_TABLE_BASE(); + + void m_splitter1OnIdle( wxIdleEvent& ) + { + m_splitter1->SetSashPosition( 254 ); + m_splitter1->Disconnect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FP_LIB_TABLE_BASE::m_splitter1OnIdle ), NULL, this ); + } + +}; + +#endif //__DIALOG_FP_LIB_TABLE_BASE_H__ diff --git a/pcbnew/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index 6b36d1a269..c0a4b9979b 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -428,6 +428,10 @@ void PCB_EDIT_FRAME::ReCreateMenuBar() _( "Li&brary" ), _( "Setting libraries, directories and others..." ), KiBitmap( library_xpm ) ); + AddMenuItem( configmenu, ID_PCB_LIB_TABLE_EDIT, + _( "Li&brary Tables" ), _( "Setup footprint libraries" ), + KiBitmap( library_xpm ) ); + // Colors and Visibility are also handled by the layers manager toolbar AddMenuItem( configmenu, ID_MENU_PCB_SHOW_HIDE_LAYERS_MANAGER_DIALOG, m_show_layer_manager_tools ? diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index f89084eae5..c4658a3b3f 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -109,6 +109,7 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) // menu Config EVT_MENU( ID_PCB_DRAWINGS_WIDTHS_SETUP, PCB_EDIT_FRAME::OnConfigurePcbOptions ) EVT_MENU( ID_CONFIG_REQ, PCB_EDIT_FRAME::Process_Config ) + EVT_MENU( ID_PCB_LIB_TABLE_EDIT, PCB_EDIT_FRAME::Process_Config ) EVT_MENU( ID_CONFIG_SAVE, PCB_EDIT_FRAME::Process_Config ) EVT_MENU( ID_CONFIG_READ, PCB_EDIT_FRAME::Process_Config ) EVT_MENU_RANGE( ID_PREFERENCES_HOTKEY_START, ID_PREFERENCES_HOTKEY_END, diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index 808a24056c..3051347cb6 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -58,8 +59,8 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) { - int id = event.GetId(); - wxFileName fn; + int id = event.GetId(); + wxFileName fn; switch( id ) { @@ -81,6 +82,25 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) InstallConfigFrame(); break; + case ID_PCB_LIB_TABLE_EDIT: + { + FP_LIB_TABLE gbl; + FP_LIB_TABLE prj; + + int r = InvokePcbLibTableEditor( this, &gbl, &prj ); + + if( r & 1 ) + { + // save global table to disk and apply it + } + + if( r & 2 ) + { + // save project table to disk and apply it + } + } + break; + case ID_PCB_MASK_CLEARANCE: { DIALOG_PADS_MASK_CLEARANCE dlg( this ); diff --git a/pcbnew/pcbnew_id.h b/pcbnew/pcbnew_id.h index c78a27462a..eae9ab32ea 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -250,6 +250,7 @@ enum pcbnew_ids ID_MENU_PCB_SHOW_3D_FRAME, ID_PCB_USER_GRID_SETUP, ID_PCB_GEN_BOM_FILE_FROM_BOARD, + ID_PCB_LIB_TABLE_EDIT, ID_MENU_PCB_SHOW_DESIGN_RULES_DIALOG, ID_MENU_PCB_SHOW_HIDE_LAYERS_MANAGER_DIALOG, @@ -330,7 +331,7 @@ enum pcbnew_ids ID_MODVIEW_NEXT, ID_MODVIEW_SHOW_3D_VIEW, ID_MODVIEW_FOOTPRINT_EXPORT_TO_BOARD, - ID_FOOTPRINT_WIZARD_WINDOW, + ID_FOOTPRINT_WIZARD_WINDOW, ID_FOOTPRINT_WIZARD_PAGES, ID_FOOTPRINT_WIZARD_PARAMETERS, ID_FOOTPRINT_WIZARD_NEXT, @@ -343,7 +344,7 @@ enum pcbnew_ids ID_FOOTPRINT_WIZARD_PARAMETERS_WINDOW, ID_FOOTPRINT_WIZARD_SELECT_WIZARD, ID_FOOTPRINT_WIZARD_EXPORT_TO_BOARD, - + }; #endif /* __PCBNEW_IDS_H__ */ From fb43f4ad6fadc52e7bae1dad06dcaaa792420ff9 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Tue, 16 Oct 2012 01:56:57 -0500 Subject: [PATCH 5/9] fp_lib_table dialog work --- common/fp_lib_table.cpp | 90 ++++---- include/fp_lib_table.h | 56 ++++- pcbnew/dialogs/dialog_fp_lib_table.cpp | 120 +++++++++- pcbnew/dialogs/dialog_fp_lib_table_base.cpp | 230 ++++++++++---------- pcbnew/dialogs/dialog_fp_lib_table_base.fbp | 120 +++++----- pcbnew/dialogs/dialog_fp_lib_table_base.h | 40 ++-- 6 files changed, 416 insertions(+), 240 deletions(-) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index cab2481320..2e5ca3bf98 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -178,6 +178,52 @@ std::vector FP_LIB_TABLE::GetLogicalLibs() } +FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aNickName ) const +{ + // this function must be *super* fast, so therefore should not instantiate + // anything which would require using the heap. + const FP_LIB_TABLE* cur = this; + + do + { + INDEX_CITER it = cur->nickIndex.find( aNickName ); + + if( it != cur->nickIndex.end() ) + { + return (FP_LIB_TABLE::ROW*) &cur->rows[it->second]; // found + } + + // not found, search fall back table(s), if any + } while( ( cur = cur->fallBack ) != 0 ); + + return 0; // not found +} + + +bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace ) +{ + // this does not need to be super fast. + + INDEX_CITER it = nickIndex.find( aRow.nickName ); + + if( it == nickIndex.end() ) + { + rows.push_back( aRow ); + nickIndex.insert( INDEX_VALUE( aRow.nickName, rows.size() - 1 ) ); + return true; + } + + if( doReplace ) + { + rows[it->second] = aRow; + return true; + } + + return false; +} + + + #if 0 // will need PLUGIN_RELEASER. MODULE* FP_LIB_TABLE::LookupFootprint( const FP_LIB_ID& aFootprintId ) throw( IO_ERROR ) @@ -256,47 +302,3 @@ void FP_LIB_TABLE::loadLib( ROW* aRow ) throw( IO_ERROR ) } #endif - -FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aNickName ) const -{ - // this function must be *super* fast, so therefore should not instantiate - // anything which would require using the heap. - const FP_LIB_TABLE* cur = this; - - do - { - INDEX_CITER it = cur->nickIndex.find( aNickName ); - - if( it != cur->nickIndex.end() ) - { - return (FP_LIB_TABLE::ROW*) &cur->rows[it->second]; // found - } - - // not found, search fall back table(s), if any - } while( ( cur = cur->fallBack ) != 0 ); - - return 0; // not found -} - - -bool FP_LIB_TABLE::InsertRow( const ROW& aRow, bool doReplace ) -{ - // this does not need to be super fast. - - INDEX_CITER it = nickIndex.find( aRow.nickName ); - - if( it == nickIndex.end() ) - { - rows.push_back( aRow ); - nickIndex.insert( INDEX_VALUE( aRow.nickName, rows.size() - 1 ) ); - return true; - } - - if( doReplace ) - { - rows[it->second] = aRow; - return true; - } - - return false; -} diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index 97a512e6af..990b69c064 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -82,6 +82,8 @@ class FP_LIB_TABLE_LEXER; */ class FP_LIB_TABLE : public wxGridTableBase { + friend class DIALOG_FP_LIB_TABLE; + public: /** @@ -92,6 +94,7 @@ public: class ROW { friend class FP_LIB_TABLE; + friend class DIALOG_FP_LIB_TABLE; public: @@ -148,8 +151,6 @@ public: void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ); - protected: - ROW( FP_LIB_TABLE* aOwner ) : owner( aOwner ) // lib( 0 ) @@ -316,9 +317,9 @@ public: switch( aCol ) { - case 1: r.SetType( aValue ); - case 2: r.SetFullURI( aValue ); - case 3: r.SetOptions( aValue ); + case 1: r.SetType( aValue ); break; + case 2: r.SetFullURI( aValue ); break; + case 3: r.SetOptions( aValue ); break; } } } @@ -330,6 +331,51 @@ public: return true; } + bool InsertRows( size_t aPos = 0, size_t aNumRows = 1 ) + { + if( aPos < rows.size() ) + { + rows.insert( rows.begin() + aPos, aNumRows, ROW( this ) ); + return true; + } + return false; + } + + bool AppendRows( size_t aNumRows = 1 ) + { + while( aNumRows-- ) + rows.push_back( ROW( this ) ); + return true; + } + + bool DeleteRows( size_t aPos, size_t aNumRows ) + { + if( aPos + aNumRows <= rows.size() ) + { + ROWS_ITER start = rows.begin() + aPos; + rows.erase( start, start + aNumRows ); + return true; + } + return false; + } + + void Clear() + { + rows.clear(); + } + + wxString GetColLabelValue( int aCol ) + { + switch( aCol ) + { + case 0: return _( "Nickname" ); + case 1: return _( "Plugin" ); + case 2: return _( "Library Path" ); + case 3: return _( "Options" ); + default: return wxEmptyString; + } + } + //----------------------------------------------- diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index 08978ea663..57e36a5cc1 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -24,7 +24,7 @@ */ - +#include #include #include @@ -35,11 +35,113 @@ */ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE { + //--------------------------------------- + + void pageChangedHandler( wxAuiNotebookEvent& event ) + { + int pageNdx = m_auinotebook->GetSelection(); + + m_cur_grid = pageNdx ? m_global_grid : m_project_grid; + } + + void appendRowHandler( wxMouseEvent& event ) + { + D(printf("%s\n", __func__);) + } + + void deleteRowHandler( wxMouseEvent& event ) + { + D(printf("%s\n", __func__);) + } + + void moveUpHandler( wxMouseEvent& event ) + { + D(printf("%s\n", __func__);) + } + + void moveDownHandler( wxMouseEvent& event ) + { + D(printf("%s\n", __func__);) + } + + void onCancelButtonClick( wxCommandEvent& event ) + { + m_global->rows = m_orig_global; + m_project->rows = m_orig_project; + + // @todo reindex, or add member function for wholesale row replacement + + EndModal( wxID_CANCEL ); + } + + void onOKButtonClick( wxCommandEvent& event ) + { + EndModal( wxID_OK ); + } + + + //-------------------------------------- + + + // caller's tables are modified only on OK button. + FP_LIB_TABLE* m_global; + FP_LIB_TABLE* m_project; + + // local copies are saved and restored if Cancel button. + FP_LIB_TABLE::ROWS m_orig_global; + FP_LIB_TABLE::ROWS m_orig_project; + + wxGrid* m_cur_grid; ///< changed based on tab choice + public: - DIALOG_FP_LIB_TABLE( wxFrame* aParent ) : - DIALOG_FP_LIB_TABLE_BASE( aParent ) + DIALOG_FP_LIB_TABLE( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) : + DIALOG_FP_LIB_TABLE_BASE( aParent ), + m_global( aGlobal ), + m_project( aProject ), + m_orig_global( aGlobal->rows ), + m_orig_project( aProject->rows ) { + /* + GetSizer()->SetSizeHints( this ); + Centre(); + SetAutoLayout( true ); + Layout(); + */ + +#if 1 && defined(DEBUG) + // put some dummy data into table(s) + FP_LIB_TABLE::ROW row( m_global ); + + row.SetNickName( wxT( "passives" ) ); + row.SetType( wxT( "kicad" ) ); + row.SetFullURI( wxT( "%G/passives" ) ); + row.SetOptions( wxT( "speed=fast,purpose=testing" ) ); + m_global->InsertRow( row ); + + row.SetNickName( wxT( "micros" ) ); + row.SetType( wxT( "legacy" ) ); + row.SetFullURI( wxT( "%P/micros" ) ); + row.SetOptions( wxT( "speed=fast,purpose=testing" ) ); + m_global->InsertRow( row ); + + row.owner = m_project; + row.SetFullURI( wxT( "%P/chips" ) ); + m_project->InsertRow( row ); + +#endif + + m_global_grid->SetTable( m_global ); + m_project_grid->SetTable( m_project ); + + //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 ); } }; @@ -47,9 +149,17 @@ public: int InvokePcbLibTableEditor( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) { - DIALOG_FP_LIB_TABLE dlg( aParent ); + DIALOG_FP_LIB_TABLE dlg( aParent, aGlobal, aProject ); - dlg.Show( true ); + int ret = dlg.ShowModal(); + switch( ret ) + { + case wxID_OK: + break; + + case wxID_CANCEL: + break; + } return 0; } diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp index dd5d8226d2..91d371aab9 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp @@ -16,173 +16,164 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID wxBoxSizer* bSizer1; bSizer1 = new wxBoxSizer( wxVERTICAL ); - m_splitter1 = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_3DBORDER ); - m_splitter1->Connect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FP_LIB_TABLE_BASE::m_splitter1OnIdle ), NULL, this ); - m_splitter1->SetMinimumPaneSize( 10 ); + m_splitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3DSASH ); + m_splitter->Connect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FP_LIB_TABLE_BASE::m_splitterOnIdle ), NULL, this ); + m_splitter->SetMinimumPaneSize( 10 ); - m_top = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); - wxStaticBoxSizer* sbSizer3; - sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( m_top, wxID_ANY, _("Global and Project Scope") ), wxVERTICAL ); + m_top = new wxPanel( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxStaticBoxSizer* m_top_sizer; + m_top_sizer = new wxStaticBoxSizer( new wxStaticBox( m_top, wxID_ANY, _("Library Tables by Scope") ), wxVERTICAL ); - m_auinotebook2 = new wxAuiNotebook( m_top, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_DEFAULT_STYLE ); - m_panel4 = new wxPanel( m_auinotebook2, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); - m_panel4->SetToolTip( _("Module libraries which are visible for all projects") ); + m_auinotebook = new wxAuiNotebook( m_top, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_BOTTOM ); + m_global_panel = new wxPanel( m_auinotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + m_global_panel->SetToolTip( _("Module libraries which are visible for all projects") ); - wxBoxSizer* bSizer4; - bSizer4 = new wxBoxSizer( wxVERTICAL ); + wxBoxSizer* m_global_box_sizer; + m_global_box_sizer = new wxBoxSizer( wxVERTICAL ); - m_grid1 = new wxGrid( m_panel4, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_global_grid = new wxGrid( m_global_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid - m_grid1->CreateGrid( 1, 4 ); - m_grid1->EnableEditing( true ); - m_grid1->EnableGridLines( true ); - m_grid1->EnableDragGridSize( false ); - m_grid1->SetMargins( 0, 0 ); + m_global_grid->CreateGrid( 1, 4 ); + m_global_grid->EnableEditing( true ); + m_global_grid->EnableGridLines( true ); + m_global_grid->EnableDragGridSize( true ); + m_global_grid->SetMargins( 0, 0 ); // Columns - m_grid1->AutoSizeColumns(); - m_grid1->EnableDragColMove( false ); - m_grid1->EnableDragColSize( true ); - m_grid1->SetColLabelSize( 30 ); - m_grid1->SetColLabelValue( 0, _("Nickname") ); - m_grid1->SetColLabelValue( 1, _("Library Path") ); - m_grid1->SetColLabelValue( 2, _("Plugin") ); - m_grid1->SetColLabelValue( 3, _("Options") ); - m_grid1->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + m_global_grid->AutoSizeColumns(); + m_global_grid->EnableDragColMove( false ); + m_global_grid->EnableDragColSize( true ); + m_global_grid->SetColLabelSize( 30 ); + m_global_grid->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Rows - m_grid1->AutoSizeRows(); - m_grid1->EnableDragRowSize( true ); - m_grid1->SetRowLabelSize( 80 ); - m_grid1->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + m_global_grid->EnableDragRowSize( true ); + m_global_grid->SetRowLabelSize( 40 ); + m_global_grid->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Label Appearance // Cell Defaults - m_grid1->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); - bSizer4->Add( m_grid1, 1, wxALL|wxEXPAND, 5 ); + m_global_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + m_global_box_sizer->Add( m_global_grid, 1, wxALL|wxEXPAND, 5 ); - m_panel4->SetSizer( bSizer4 ); - m_panel4->Layout(); - bSizer4->Fit( m_panel4 ); - m_auinotebook2->AddPage( m_panel4, _("Global Libraries"), false, wxNullBitmap ); - m_panel5 = new wxPanel( m_auinotebook2, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); - wxBoxSizer* bSizer5; - bSizer5 = new wxBoxSizer( wxVERTICAL ); + m_global_panel->SetSizer( m_global_box_sizer ); + m_global_panel->Layout(); + m_global_box_sizer->Fit( m_global_panel ); + m_auinotebook->AddPage( m_global_panel, _("Global Libraries"), true, wxNullBitmap ); + m_project_panel = new wxPanel( m_auinotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* m_project_sizer; + m_project_sizer = new wxBoxSizer( wxVERTICAL ); - m_grid11 = new wxGrid( m_panel5, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_project_grid = new wxGrid( m_project_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid - m_grid11->CreateGrid( 1, 4 ); - m_grid11->EnableEditing( true ); - m_grid11->EnableGridLines( true ); - m_grid11->EnableDragGridSize( false ); - m_grid11->SetMargins( 0, 0 ); + m_project_grid->CreateGrid( 1, 4 ); + m_project_grid->EnableEditing( true ); + m_project_grid->EnableGridLines( true ); + m_project_grid->EnableDragGridSize( true ); + m_project_grid->SetMargins( 0, 0 ); // Columns - m_grid11->AutoSizeColumns(); - m_grid11->EnableDragColMove( false ); - m_grid11->EnableDragColSize( true ); - m_grid11->SetColLabelSize( 30 ); - m_grid11->SetColLabelValue( 0, _("Nickname") ); - m_grid11->SetColLabelValue( 1, _("Library Path") ); - m_grid11->SetColLabelValue( 2, _("Plugin") ); - m_grid11->SetColLabelValue( 3, _("Options") ); - m_grid11->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + m_project_grid->AutoSizeColumns(); + m_project_grid->EnableDragColMove( false ); + m_project_grid->EnableDragColSize( true ); + m_project_grid->SetColLabelSize( 30 ); + m_project_grid->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Rows - m_grid11->AutoSizeRows(); - m_grid11->EnableDragRowSize( true ); - m_grid11->SetRowLabelSize( 80 ); - m_grid11->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + m_project_grid->EnableDragRowSize( true ); + m_project_grid->SetRowLabelSize( 40 ); + m_project_grid->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Label Appearance // Cell Defaults - m_grid11->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); - bSizer5->Add( m_grid11, 0, wxALL, 5 ); + m_project_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + m_project_sizer->Add( m_project_grid, 0, wxALL, 5 ); - m_panel5->SetSizer( bSizer5 ); - m_panel5->Layout(); - bSizer5->Fit( m_panel5 ); - m_auinotebook2->AddPage( m_panel5, _("Project Specific Libraries"), true, wxNullBitmap ); + m_project_panel->SetSizer( m_project_sizer ); + m_project_panel->Layout(); + m_project_sizer->Fit( m_project_panel ); + m_auinotebook->AddPage( m_project_panel, _("Project Specific Libraries"), false, wxNullBitmap ); - sbSizer3->Add( m_auinotebook2, 1, wxEXPAND | wxALL, 5 ); + m_top_sizer->Add( m_auinotebook, 1, wxEXPAND | wxALL, 5 ); wxBoxSizer* bSizer51; bSizer51 = new wxBoxSizer( wxHORIZONTAL ); - m_button1 = new wxButton( m_top, wxID_ANY, _("Append Row"), wxDefaultPosition, wxDefaultSize, 0 ); - m_button1->SetToolTip( _("Add a pcb library row to this table") ); + m_append_button = new wxButton( m_top, wxID_ANY, _("Append Row"), wxDefaultPosition, wxDefaultSize, 0 ); + m_append_button->SetToolTip( _("Add a pcb library row to this table") ); - bSizer51->Add( m_button1, 0, wxALL, 5 ); + bSizer51->Add( m_append_button, 0, wxALL, 5 ); - m_button2 = new wxButton( m_top, wxID_ANY, _("Delete Row"), wxDefaultPosition, wxDefaultSize, 0 ); - m_button2->SetToolTip( _("Remove a PCB library from this library table") ); + m_delete_button = new wxButton( m_top, wxID_ANY, _("Delete Row"), wxDefaultPosition, wxDefaultSize, 0 ); + m_delete_button->SetToolTip( _("Remove a PCB library from this library table") ); - bSizer51->Add( m_button2, 0, wxALL, 5 ); + bSizer51->Add( m_delete_button, 0, wxALL, 5 ); - m_button3 = new wxButton( m_top, wxID_ANY, _("Move Up"), wxDefaultPosition, wxDefaultSize, 0 ); - m_button3->SetToolTip( _("Move the currently selected row up one position") ); + m_move_up_button = new wxButton( m_top, wxID_ANY, _("Move Up"), wxDefaultPosition, wxDefaultSize, 0 ); + m_move_up_button->SetToolTip( _("Move the currently selected row up one position") ); - bSizer51->Add( m_button3, 0, wxALL, 5 ); + bSizer51->Add( m_move_up_button, 0, wxALL, 5 ); - m_button4 = new wxButton( m_top, wxID_ANY, _("Move Down"), wxDefaultPosition, wxDefaultSize, 0 ); - m_button4->SetToolTip( _("Move the currently selected row down one position") ); + m_move_down_button = new wxButton( m_top, wxID_ANY, _("Move Down"), wxDefaultPosition, wxDefaultSize, 0 ); + m_move_down_button->SetToolTip( _("Move the currently selected row down one position") ); - bSizer51->Add( m_button4, 0, wxALL, 5 ); + bSizer51->Add( m_move_down_button, 0, wxALL, 5 ); - sbSizer3->Add( bSizer51, 0, wxALIGN_CENTER, 5 ); + m_top_sizer->Add( bSizer51, 0, wxALIGN_CENTER|wxBOTTOM, 8 ); - m_top->SetSizer( sbSizer3 ); + m_top->SetSizer( m_top_sizer ); m_top->Layout(); - sbSizer3->Fit( m_top ); - m_bottom = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); - wxBoxSizer* bSizer8; - bSizer8 = new wxBoxSizer( wxVERTICAL ); + m_top_sizer->Fit( m_top ); + m_bottom = new wxPanel( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* m_bottom_sizer; + m_bottom_sizer = new wxBoxSizer( wxVERTICAL ); wxStaticBoxSizer* sbSizer1; sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( m_bottom, wxID_ANY, _("Path Substitutions") ), wxVERTICAL ); - m_grid2 = new wxGrid( m_bottom, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_path_subs_grid = new wxGrid( m_bottom, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); // Grid - m_grid2->CreateGrid( 2, 2 ); - m_grid2->EnableEditing( true ); - m_grid2->EnableGridLines( true ); - m_grid2->EnableDragGridSize( false ); - m_grid2->SetMargins( 0, 0 ); + m_path_subs_grid->CreateGrid( 2, 2 ); + m_path_subs_grid->EnableEditing( true ); + m_path_subs_grid->EnableGridLines( true ); + m_path_subs_grid->EnableDragGridSize( false ); + m_path_subs_grid->SetMargins( 0, 0 ); // Columns - m_grid2->SetColSize( 0, 150 ); - m_grid2->SetColSize( 1, 500 ); - m_grid2->EnableDragColMove( false ); - m_grid2->EnableDragColSize( true ); - m_grid2->SetColLabelSize( 30 ); - m_grid2->SetColLabelValue( 0, _("Category") ); - m_grid2->SetColLabelValue( 1, _("Path Segment") ); - m_grid2->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + m_path_subs_grid->SetColSize( 0, 150 ); + m_path_subs_grid->SetColSize( 1, 500 ); + m_path_subs_grid->AutoSizeColumns(); + 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( 1, _("Path Segment") ); + m_path_subs_grid->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); // Rows - m_grid2->EnableDragRowSize( true ); - m_grid2->SetRowLabelSize( 40 ); - m_grid2->SetRowLabelValue( 0, _("%S") ); - m_grid2->SetRowLabelValue( 1, _("%P") ); - m_grid2->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + 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 // Cell Defaults - m_grid2->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); - sbSizer1->Add( m_grid2, 0, wxALL, 5 ); + m_path_subs_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + sbSizer1->Add( m_path_subs_grid, 1, wxALL|wxEXPAND, 5 ); - bSizer8->Add( sbSizer1, 1, wxALL|wxEXPAND, 5 ); + m_bottom_sizer->Add( sbSizer1, 1, wxALL|wxEXPAND, 5 ); m_sdbSizer1 = new wxStdDialogButtonSizer(); m_sdbSizer1OK = new wxButton( m_bottom, wxID_OK ); @@ -191,23 +182,40 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); m_sdbSizer1->Realize(); - bSizer8->Add( m_sdbSizer1, 0, wxALL|wxEXPAND, 5 ); + m_bottom_sizer->Add( m_sdbSizer1, 0, wxALL|wxEXPAND, 5 ); - m_bottom->SetSizer( bSizer8 ); + m_bottom->SetSizer( m_bottom_sizer ); m_bottom->Layout(); - bSizer8->Fit( m_bottom ); - m_splitter1->SplitHorizontally( m_top, m_bottom, 254 ); - bSizer1->Add( m_splitter1, 2, wxEXPAND, 5 ); + m_bottom_sizer->Fit( m_bottom ); + m_splitter->SplitHorizontally( m_top, m_bottom, 343 ); + bSizer1->Add( m_splitter, 2, wxEXPAND, 5 ); this->SetSizer( bSizer1 ); this->Layout(); - bSizer1->Fit( this ); this->Centre( wxBOTH ); + + // Connect Events + m_auinotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( DIALOG_FP_LIB_TABLE_BASE::pageChangedHandler ), 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 ); + m_move_down_button->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::moveDownHandler ), NULL, this ); + m_sdbSizer1Cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FP_LIB_TABLE_BASE::onCancelButtonClick ), NULL, this ); + m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FP_LIB_TABLE_BASE::onOKButtonClick ), NULL, this ); } 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_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 ); + m_move_down_button->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( DIALOG_FP_LIB_TABLE_BASE::moveDownHandler ), NULL, this ); + m_sdbSizer1Cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FP_LIB_TABLE_BASE::onCancelButtonClick ), NULL, this ); + m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FP_LIB_TABLE_BASE::onOKButtonClick ), NULL, this ); + } diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp index 5b9038d16a..e4b71d5f77 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 - -1,-1 + 864,652 wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER DIALOG_SHIM; dialog_shim.h PCB Library Tables @@ -131,7 +131,7 @@ 0 1 - m_splitter1 + m_splitter 1 @@ -140,12 +140,12 @@ Resizable 0.0 - 254 + 343 -1 1 wxSPLIT_HORIZONTAL - wxSP_3D|wxSP_3DBORDER + wxSP_3DSASH 0 @@ -254,19 +254,19 @@ - + wxID_ANY - Global and Project Scope + Library Tables by Scope - sbSizer3 + m_top_sizer wxVERTICAL none - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -301,7 +301,7 @@ 0 1 - m_auinotebook2 + m_auinotebook 1 @@ -311,7 +311,7 @@ Resizable 1 - wxAUI_NB_DEFAULT_STYLE + wxAUI_NB_BOTTOM -1 0 @@ -325,7 +325,7 @@ - + pageChangedHandler @@ -351,11 +351,11 @@ - + Global Libraries - 0 - + 1 + 1 1 1 @@ -390,7 +390,7 @@ 0 1 - m_panel4 + m_global_panel 1 @@ -429,9 +429,9 @@ - + - bSizer4 + m_global_box_sizer wxVERTICAL none @@ -448,7 +448,7 @@ 1 - 1 + 0 @@ -462,7 +462,7 @@ 1 wxALIGN_CENTRE 30 - "Nickname" "Library Path" "Plugin" "Options" + wxALIGN_CENTRE 4 @@ -470,16 +470,16 @@ 1 0 Dock - 0 + 1 Left 0 1 - 0 + 1 1 1 1 - 1 + 0 1 @@ -497,8 +497,8 @@ 0 - 1 - m_grid1 + 0 + m_global_grid 1 @@ -507,7 +507,7 @@ Fixed wxALIGN_CENTRE - 80 + 40 wxALIGN_CENTRE @@ -580,11 +580,11 @@ - + Project Specific Libraries - 1 - + 0 + 1 1 1 @@ -619,7 +619,7 @@ 0 1 - m_panel5 + m_project_panel 1 @@ -658,9 +658,9 @@ - + - bSizer5 + m_project_sizer wxVERTICAL none @@ -677,7 +677,7 @@ 1 - 1 + 0 @@ -691,7 +691,7 @@ 1 wxALIGN_CENTRE 30 - "Nickname" "Library Path" "Plugin" "Options" + wxALIGN_CENTRE 4 @@ -699,16 +699,16 @@ 1 0 Dock - 0 + 1 Left 0 1 - 0 + 1 1 1 1 - 1 + 0 1 @@ -726,8 +726,8 @@ 0 - 1 - m_grid11 + 0 + m_project_grid 1 @@ -736,7 +736,7 @@ Fixed wxALIGN_CENTRE - 80 + 40 wxALIGN_CENTRE @@ -812,8 +812,8 @@ - 5 - wxALIGN_CENTER + 8 + wxALIGN_CENTER|wxBOTTOM 0 @@ -861,7 +861,7 @@ 0 1 - m_button1 + m_append_button 1 @@ -891,7 +891,7 @@ - + appendRowHandler @@ -949,7 +949,7 @@ 0 1 - m_button2 + m_delete_button 1 @@ -979,7 +979,7 @@ - + deleteRowHandler @@ -1037,7 +1037,7 @@ 0 1 - m_button3 + m_move_up_button 1 @@ -1067,7 +1067,7 @@ - + moveUpHandler @@ -1125,7 +1125,7 @@ 0 1 - m_button4 + m_move_down_button 1 @@ -1155,7 +1155,7 @@ - + moveDownHandler @@ -1252,16 +1252,16 @@ - + - bSizer8 + m_bottom_sizer wxVERTICAL none - + 5 wxALL|wxEXPAND 1 - + wxID_ANY Path Substitutions @@ -1271,8 +1271,8 @@ 5 - wxALL - 0 + wxALL|wxEXPAND + 1 1 1 @@ -1282,7 +1282,7 @@ - 0 + 1 0 @@ -1333,7 +1333,7 @@ 0 1 - m_grid2 + m_path_subs_grid 1 @@ -1431,11 +1431,11 @@ m_sdbSizer1 protected - + onCancelButtonClick - + onOKButtonClick diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.h b/pcbnew/dialogs/dialog_fp_lib_table_base.h index f65b923c2a..3156b1cdf5 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.h +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.h @@ -42,32 +42,42 @@ class DIALOG_FP_LIB_TABLE_BASE : public DIALOG_SHIM private: protected: - wxSplitterWindow* m_splitter1; + wxSplitterWindow* m_splitter; wxPanel* m_top; - wxAuiNotebook* m_auinotebook2; - wxPanel* m_panel4; - wxGrid* m_grid1; - wxPanel* m_panel5; - wxGrid* m_grid11; - wxButton* m_button1; - wxButton* m_button2; - wxButton* m_button3; - wxButton* m_button4; + wxAuiNotebook* m_auinotebook; + wxPanel* m_global_panel; + wxGrid* m_global_grid; + wxPanel* m_project_panel; + wxGrid* m_project_grid; + wxButton* m_append_button; + wxButton* m_delete_button; + wxButton* m_move_up_button; + wxButton* m_move_down_button; wxPanel* m_bottom; - wxGrid* m_grid2; + wxGrid* m_path_subs_grid; wxStdDialogButtonSizer* m_sdbSizer1; wxButton* m_sdbSizer1OK; wxButton* m_sdbSizer1Cancel; + + // Virtual event handlers, overide them in your derived class + virtual void pageChangedHandler( wxAuiNotebookEvent& event ) { event.Skip(); } + virtual void appendRowHandler( wxMouseEvent& event ) { event.Skip(); } + virtual void deleteRowHandler( wxMouseEvent& event ) { event.Skip(); } + virtual void moveUpHandler( wxMouseEvent& event ) { event.Skip(); } + virtual void moveDownHandler( wxMouseEvent& event ) { event.Skip(); } + virtual void onCancelButtonClick( wxCommandEvent& event ) { event.Skip(); } + virtual void onOKButtonClick( wxCommandEvent& event ) { event.Skip(); } + 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( -1,-1 ), 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( 864,652 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); ~DIALOG_FP_LIB_TABLE_BASE(); - void m_splitter1OnIdle( wxIdleEvent& ) + void m_splitterOnIdle( wxIdleEvent& ) { - m_splitter1->SetSashPosition( 254 ); - m_splitter1->Disconnect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FP_LIB_TABLE_BASE::m_splitter1OnIdle ), NULL, this ); + m_splitter->SetSashPosition( 343 ); + m_splitter->Disconnect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FP_LIB_TABLE_BASE::m_splitterOnIdle ), NULL, this ); } }; From 69dbeab90fcf10d85997602bcada3a20578e452d Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Tue, 16 Oct 2012 20:00:25 -0500 Subject: [PATCH 6/9] decouple wxGridTableBase from FP_LIB_TABLE, this was poor information hiding --- common/fp_lib_table.cpp | 6 +- include/fp_lib_table.h | 161 ++++--------------- pcbnew/dialogs/dialog_fp_lib_table.cpp | 169 ++++++++++++++++++-- pcbnew/dialogs/dialog_fp_lib_table_base.cpp | 12 +- pcbnew/dialogs/dialog_fp_lib_table_base.fbp | 6 +- 5 files changed, 193 insertions(+), 161 deletions(-) diff --git a/common/fp_lib_table.cpp b/common/fp_lib_table.cpp index 2e5ca3bf98..2c79b21ee6 100644 --- a/common/fp_lib_table.cpp +++ b/common/fp_lib_table.cpp @@ -68,7 +68,7 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedSYMBOLorNUMBER(); - ROW row( this ); + ROW row; row.SetNickName( in->FromUTF8() ); @@ -112,9 +112,9 @@ void FP_LIB_TABLE::Parse( FP_LIB_TABLE_LEXER* in ) throw( IO_ERROR, PARSE_ERROR in->NeedRIGHT(); // terminate the (lib..) // all nickNames within this table fragment must be unique, so we do not - // use doReplace in InsertRow(). However a fallBack table can have a + // use doReplace in InsertRow(). (However a fallBack table can have a // conflicting nickName and ours will supercede that one since in - // FindLib() we search this table before any fall back. + // FindLib() we search this table before any fall back.) if( !InsertRow( row ) ) { wxString msg = wxString::Format( diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index 990b69c064..0d4904e3b2 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -31,7 +31,6 @@ #include #include -#include #include @@ -80,7 +79,7 @@ class FP_LIB_TABLE_LEXER; * * @author Wayne Stambaugh */ -class FP_LIB_TABLE : public wxGridTableBase +class FP_LIB_TABLE { friend class DIALOG_FP_LIB_TABLE; @@ -135,11 +134,6 @@ public: return options; } - ~ROW() - { - // delete lib; - } - /** * Function Format * serializes this object as utf8 text to an OUTPUTFORMATTER, and tries to @@ -151,11 +145,6 @@ public: void Format( OUTPUTFORMATTER* out, int nestLevel ) const throw( IO_ERROR ); - ROW( FP_LIB_TABLE* aOwner ) : - owner( aOwner ) - // lib( 0 ) - {} - /** * Function SetNickName * changes the logical name of this library, useful for an editor. @@ -194,7 +183,6 @@ public: } private: - FP_LIB_TABLE* owner; wxString nickName; wxString type; wxString uri; @@ -279,106 +267,6 @@ public: */ std::vector GetLogicalLibs(); - //------------------------------------------------ - - int GetNumberRows () { return rows.size(); } - int GetNumberCols () { return 4; } - - wxString GetValue( int aRow, int aCol ) - { - if( unsigned( aRow ) < rows.size() ) - { - const ROW& r = rows[aRow]; - - switch( aCol ) - { - case 0: return r.GetNickName(); - case 1: return r.GetType(); - case 2: return r.GetFullURI(); - case 3: return r.GetOptions(); - default: - ; // fall thru to wxEmptyString - } - } - - return wxEmptyString; - } - - void SetValue( int aRow, int aCol, const wxString &aValue ) - { - if( aCol == 0 ) - { - // when the nickname is changed, there's careful work to do, including - // ensuring uniqueness of the nickname. - } - else if( unsigned( aRow ) < rows.size() ) - { - ROW& r = rows[aRow]; - - switch( aCol ) - { - case 1: r.SetType( aValue ); break; - case 2: r.SetFullURI( aValue ); break; - case 3: r.SetOptions( aValue ); break; - } - } - } - - bool IsEmptyCell( int aRow, int aCol ) - { - if( unsigned( aRow ) < rows.size() ) - return false; - return true; - } - - bool InsertRows( size_t aPos = 0, size_t aNumRows = 1 ) - { - if( aPos < rows.size() ) - { - rows.insert( rows.begin() + aPos, aNumRows, ROW( this ) ); - return true; - } - return false; - } - - bool AppendRows( size_t aNumRows = 1 ) - { - while( aNumRows-- ) - rows.push_back( ROW( this ) ); - return true; - } - - bool DeleteRows( size_t aPos, size_t aNumRows ) - { - if( aPos + aNumRows <= rows.size() ) - { - ROWS_ITER start = rows.begin() + aPos; - rows.erase( start, start + aNumRows ); - return true; - } - return false; - } - - void Clear() - { - rows.clear(); - } - - wxString GetColLabelValue( int aCol ) - { - switch( aCol ) - { - case 0: return _( "Nickname" ); - case 1: return _( "Plugin" ); - case 2: return _( "Library Path" ); - case 3: return _( "Options" ); - default: return wxEmptyString; - } - } - - //----------------------------------------------- - - //-------------------------------------------------------- // the returning of a const wxString* tells if not found, but might be too // promiscuous? @@ -427,6 +315,7 @@ public: void Test(); #endif + protected: // only a table editor can use these /** @@ -448,7 +337,33 @@ protected: // only a table editor can use these */ ROW* FindRow( const wxString& aNickName ) const; -private: + void reindex() + { + nickIndex.clear(); + + for( ROWS_CITER it = rows.begin(); it != rows.end(); ++it ) + nickIndex.insert( INDEX_VALUE( it->nickName, it - rows.begin() ) ); + } + + typedef std::vector ROWS; + typedef ROWS::iterator ROWS_ITER; + typedef ROWS::const_iterator ROWS_CITER; + + ROWS rows; + + /// this is a non-owning index into the ROWS table + typedef std::map INDEX; // "int" is std::vector array index + typedef INDEX::iterator INDEX_ITER; + typedef INDEX::const_iterator INDEX_CITER; + typedef INDEX::value_type INDEX_VALUE; + + /// this particular key is the nickName within each row. + INDEX nickIndex; + + FP_LIB_TABLE* fallBack; +}; + + #if 0 // lets see what we need. /** @@ -479,23 +394,5 @@ private: void loadLib( ROW* aRow ) throw( IO_ERROR ); #endif - typedef std::vector ROWS; - typedef ROWS::iterator ROWS_ITER; - typedef ROWS::const_iterator ROWS_CITER; - - ROWS rows; - - /// this is a non-owning index into the ROWS table - typedef std::map INDEX; // "int" is std::vector array index - typedef INDEX::iterator INDEX_ITER; - typedef INDEX::const_iterator INDEX_CITER; - typedef INDEX::value_type INDEX_VALUE; - - - /// the particular key is the nickName within each row. - INDEX nickIndex; - - FP_LIB_TABLE* fallBack; -}; #endif // _FP_LIB_TABLE_H_ diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index 57e36a5cc1..5eef41e731 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -27,6 +27,132 @@ #include #include #include +#include +#include + + +class FP_TBL_MODEL : public wxGridTableBase, public FP_LIB_TABLE +{ +public: + + /** + * Constructor FP_TBL_MODEL + * builds a wxGridTableBase (table model) by wrapping an FP_LIB_TABLE. + * @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 + * taken of aFallBackTable. + */ + FP_TBL_MODEL( const FP_LIB_TABLE& aTableToEdit ) : + FP_LIB_TABLE( aTableToEdit ) // copy constructor + { + } + + ~FP_TBL_MODEL() + { + D(printf("%s\n", __func__ );) + } + + //------------------------------------------------ + + int GetNumberRows () { return rows.size(); } + int GetNumberCols () { return 4; } + + wxString GetValue( int aRow, int aCol ) + { + if( unsigned( aRow ) < rows.size() ) + { + const ROW& r = rows[aRow]; + + switch( aCol ) + { + case 0: return r.GetNickName(); + case 1: return r.GetFullURI(); + case 2: return r.GetType(); + case 3: return r.GetOptions(); + default: + ; // fall thru to wxEmptyString + } + } + + return wxEmptyString; + } + + void SetValue( int aRow, int aCol, const wxString &aValue ) + { + if( unsigned( aRow ) < rows.size() ) + { + ROW& r = rows[aRow]; + + switch( aCol ) + { + case 0: r.SetNickName( aValue ); break; + case 1: r.SetType( aValue ); break; + case 2: r.SetFullURI( aValue ); break; + case 3: r.SetOptions( aValue ); break; + } + } + } + + bool IsEmptyCell( int aRow, int aCol ) + { + if( unsigned( aRow ) < rows.size() ) + return false; + return true; + } + + bool InsertRows( size_t aPos = 0, size_t aNumRows = 1 ) + { + if( aPos < rows.size() ) + { + rows.insert( rows.begin() + aPos, aNumRows, ROW() ); + return true; + } + return false; + } + + bool AppendRows( size_t aNumRows = 1 ) + { + while( aNumRows-- ) + rows.push_back( ROW() ); + return true; + } + + bool DeleteRows( size_t aPos, size_t aNumRows ) + { + if( aPos + aNumRows <= rows.size() ) + { + ROWS_ITER start = rows.begin() + aPos; + rows.erase( start, start + aNumRows ); + return true; + } + return false; + } + + void Clear() + { + rows.clear(); + nickIndex.clear(); + } + + wxString GetColLabelValue( int aCol ) + { + switch( aCol ) + { + case 0: return _( "Nickname" ); + case 1: return _( "Library Path" ); + case 2: return _( "Plugin" ); + case 3: return _( "Options" ); + default: return wxEmptyString; + } + } + + //----------------------------------------------- + +}; + + /** * Class DIALOG_FP_LIB_TABLE @@ -66,16 +192,16 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE void onCancelButtonClick( wxCommandEvent& event ) { - m_global->rows = m_orig_global; - m_project->rows = m_orig_project; - - // @todo reindex, or add member function for wholesale row replacement - EndModal( wxID_CANCEL ); } void onOKButtonClick( wxCommandEvent& event ) { + *m_global = m_global_model; + *m_project = m_project_model; + + // @todo reindex, or add member function for wholesale row replacement + EndModal( wxID_OK ); } @@ -87,9 +213,9 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE FP_LIB_TABLE* m_global; FP_LIB_TABLE* m_project; - // local copies are saved and restored if Cancel button. - FP_LIB_TABLE::ROWS m_orig_global; - FP_LIB_TABLE::ROWS m_orig_project; + // local copies which are edited, but aborted if Cancel button. + FP_TBL_MODEL m_global_model; + FP_TBL_MODEL m_project_model; wxGrid* m_cur_grid; ///< changed based on tab choice @@ -99,8 +225,8 @@ public: DIALOG_FP_LIB_TABLE_BASE( aParent ), m_global( aGlobal ), m_project( aProject ), - m_orig_global( aGlobal->rows ), - m_orig_project( aProject->rows ) + m_global_model( *aGlobal ), + m_project_model( *aProject ) { /* GetSizer()->SetSizeHints( this ); @@ -111,28 +237,27 @@ public: #if 1 && defined(DEBUG) // put some dummy data into table(s) - FP_LIB_TABLE::ROW row( m_global ); + 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->InsertRow( row ); + 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->InsertRow( row ); + m_global_model.InsertRow( row ); - row.owner = m_project; row.SetFullURI( wxT( "%P/chips" ) ); - m_project->InsertRow( row ); + m_project_model.InsertRow( row ); #endif - m_global_grid->SetTable( m_global ); - m_project_grid->SetTable( m_project ); + 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 ); @@ -143,6 +268,16 @@ public: //m_path_subs_grid->AutoSize(); m_path_subs_grid->AutoSizeColumns( false ); } + + ~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. + DestroyChildren(); + } }; diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp index 91d371aab9..6844652cf5 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp @@ -28,8 +28,8 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID m_global_panel = new wxPanel( m_auinotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_global_panel->SetToolTip( _("Module libraries which are visible for all projects") ); - wxBoxSizer* m_global_box_sizer; - m_global_box_sizer = new wxBoxSizer( wxVERTICAL ); + wxBoxSizer* m_global_sizer; + m_global_sizer = new wxBoxSizer( wxVERTICAL ); m_global_grid = new wxGrid( m_global_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); @@ -56,12 +56,12 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID // Cell Defaults m_global_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); - m_global_box_sizer->Add( m_global_grid, 1, wxALL|wxEXPAND, 5 ); + m_global_sizer->Add( m_global_grid, 1, wxALL|wxEXPAND, 5 ); - m_global_panel->SetSizer( m_global_box_sizer ); + m_global_panel->SetSizer( m_global_sizer ); m_global_panel->Layout(); - m_global_box_sizer->Fit( m_global_panel ); + m_global_sizer->Fit( m_global_panel ); m_auinotebook->AddPage( m_global_panel, _("Global Libraries"), true, wxNullBitmap ); m_project_panel = new wxPanel( m_auinotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* m_project_sizer; @@ -92,7 +92,7 @@ DIALOG_FP_LIB_TABLE_BASE::DIALOG_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID // Cell Defaults m_project_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); - m_project_sizer->Add( m_project_grid, 0, wxALL, 5 ); + m_project_sizer->Add( m_project_grid, 1, wxALL|wxEXPAND, 5 ); m_project_panel->SetSizer( m_project_sizer ); diff --git a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp index e4b71d5f77..be77cf4205 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table_base.fbp +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.fbp @@ -431,7 +431,7 @@ - m_global_box_sizer + m_global_sizer wxVERTICAL none @@ -665,8 +665,8 @@ none 5 - wxALL - 0 + wxALL|wxEXPAND + 1 1 1 From 58299fc9213b3d2894cd5eb133bf56ef584a5de2 Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Wed, 17 Oct 2012 10:12:17 -0500 Subject: [PATCH 7/9] 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 ) From 9e41a8127dc65ef66d0702f70f54969b94d9691b Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Thu, 18 Oct 2012 10:28:50 -0500 Subject: [PATCH 8/9] more fp_lib_table work --- include/fp_lib_table.h | 21 +++- pcbnew/dialogs/dialog_fp_lib_table.cpp | 163 +++++++++++++++++++------ pcbnew/pcbnew_config.cpp | 4 +- 3 files changed, 152 insertions(+), 36 deletions(-) diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h index ba5d6482e5..2d23bee00e 100644 --- a/include/fp_lib_table.h +++ b/include/fp_lib_table.h @@ -100,7 +100,9 @@ public: typedef IO_MGR::PCB_FILE_T LIB_T; - ROW(){} + ROW() : type( IO_MGR::KICAD ) + { + } ROW( const wxString& aNick, const wxString& aURI, const wxString& aType, const wxString& aOptions ) : nickName( aNick ), @@ -222,6 +224,23 @@ public: */ FP_LIB_TABLE( FP_LIB_TABLE* aFallBackTable = NULL ); + bool operator==( const FP_LIB_TABLE& r ) const + { + if( rows.size() == r.rows.size() ) + { + unsigned i; + for( i = 0; i < rows.size() && rows[i] == r.rows[i]; ++i ) + ; + + if( i == rows.size() ) + return true; + } + + return false; + } + + bool operator!=( const FP_LIB_TABLE& r ) const { return !( *this == r ); } + /** * Function Parse * fills this table fragment from information in the input stream \a aParser, which diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index f02f0f9c1b..b78e9ff883 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -28,13 +28,12 @@ #include #include #include -#include /** * Class FP_TBL_MODEL * mixes in wxGridTableBase into FP_LIB_TABLE so that the latter can be used - * as table within wxGrid. + * as a table within wxGrid. */ class FP_TBL_MODEL : public wxGridTableBase, public FP_LIB_TABLE { @@ -42,23 +41,14 @@ public: /** * Constructor FP_TBL_MODEL - * builds a wxGridTableBase (table model) by wrapping an FP_LIB_TABLE. - * @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 - * taken of aFallBackTable. + * is a copy constructor that builds a wxGridTableBase (table model) by wrapping + * an FP_LIB_TABLE. */ FP_TBL_MODEL( const FP_LIB_TABLE& aTableToEdit ) : FP_LIB_TABLE( aTableToEdit ) // copy constructor { } - ~FP_TBL_MODEL() - { - D(printf("%s\n", __func__ );) - } - //------------------------------------------------ int GetNumberRows () { return rows.size(); } @@ -93,8 +83,8 @@ public: switch( aCol ) { case 0: r.SetNickName( aValue ); break; - case 1: r.SetType( aValue ); break; - case 2: r.SetFullURI( aValue ); break; + case 1: r.SetFullURI( aValue ); break; + case 2: r.SetType( aValue ); break; case 3: r.SetOptions( aValue ); break; } } @@ -112,6 +102,18 @@ public: if( aPos < rows.size() ) { rows.insert( rows.begin() + aPos, aNumRows, ROW() ); + + // use the (wxGridStringTable) source Luke. + if( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + aPos, + aNumRows ); + + GetView()->ProcessTableMessage( msg ); + } + return true; } return false; @@ -119,8 +121,19 @@ public: bool AppendRows( size_t aNumRows = 1 ) { - while( aNumRows-- ) + // do not modify aNumRows, original value needed for wxGridTableMessage below + for( int i = aNumRows; i; --i ) rows.push_back( ROW() ); + + if( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_APPENDED, + aNumRows ); + + GetView()->ProcessTableMessage( msg ); + } + return true; } @@ -130,6 +143,17 @@ public: { ROWS_ITER start = rows.begin() + aPos; rows.erase( start, start + aNumRows ); + + if( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + aPos, + aNumRows ); + + GetView()->ProcessTableMessage( msg ); + } + return true; } return false; @@ -168,6 +192,39 @@ 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. + // 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. + void getSelectedArea() + { + wxGridCellCoordsArray topLeft = m_cur_grid->GetSelectionBlockTopLeft(); + wxGridCellCoordsArray botRight = m_cur_grid->GetSelectionBlockBottomRight(); + + if( topLeft.Count() && botRight.Count() ) + { + selRowStart = topLeft[0].GetRow(); + selColStart = topLeft[0].GetCol(); + + selRowCount = botRight[0].GetRow() - selRowStart + 1; + selColCount = botRight[0].GetCol() - selColStart + 1; + } + else + { + selRowStart = -1; + selColStart = -1; + selRowCount = 0; + selColCount = 0; + } + + D(printf("selRowStart:%d selColStart:%d selRowCount:%d selColCount:%d\n", + selRowStart, selColStart, selRowCount, selColCount );) + } + */ //--------------------------------------- @@ -175,22 +232,52 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE { int pageNdx = m_auinotebook->GetSelection(); - m_cur_grid = pageNdx ? m_global_grid : m_project_grid; + m_cur_grid = pageNdx==0 ? m_global_grid : m_project_grid; + + D(printf("%s cur_grid is %s\n", __func__, pageNdx==0 ? "global" : "project" );) } void appendRowHandler( wxMouseEvent& event ) { D(printf("%s\n", __func__);) + m_cur_grid->AppendRows( 1 ); } void deleteRowHandler( wxMouseEvent& event ) { D(printf("%s\n", __func__);) + + int curRow = m_cur_grid->GetGridCursorRow(); + + m_cur_grid->DeleteRows( curRow ); } void moveUpHandler( wxMouseEvent& event ) { D(printf("%s\n", __func__);) + + int curRow = m_cur_grid->GetGridCursorRow(); + if( curRow >= 1 ) + { + FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); + + ROW save = tbl->rows[curRow]; + + tbl->DeleteRows( curRow, 1 ); + tbl->InsertRows( --curRow, 1 ); + + tbl->rows[curRow] = save; + + if( tbl->GetView() ) + { + wxGridTableMessage msg( tbl, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + curRow, + 0 ); + + tbl->GetView()->ProcessTableMessage( msg ); + } + } } void moveDownHandler( wxMouseEvent& event ) @@ -200,20 +287,32 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE void onCancelButtonClick( wxCommandEvent& event ) { - EndModal( wxID_CANCEL ); + EndModal( 0 ); } void onOKButtonClick( wxCommandEvent& event ) { - *m_global = m_global_model; - *m_project = m_project_model; + int dialogRet = 0; - // @todo reindex, or add member function for wholesale row replacement + if( m_global_model != *m_global ) + { + dialogRet |= 1; - EndModal( wxID_OK ); + *m_global = m_global_model; + m_global->reindex(); + } + + if( m_project_model != *m_project ) + { + dialogRet |= 2; + + *m_project = m_project_model; + m_project->reindex(); + } + + EndModal( dialogRet ); } - //-------------------------------------- @@ -244,6 +343,10 @@ public: m_project_grid->AutoSizeColumns( false ); m_path_subs_grid->AutoSizeColumns( false ); + + // fire pageChangedHandler() so m_cur_grid gets set + wxAuiNotebookEvent uneventful; + pageChangedHandler( uneventful ); } ~DIALOG_FP_LIB_TABLE() @@ -262,18 +365,10 @@ public: int InvokePcbLibTableEditor( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) { - DIALOG_FP_LIB_TABLE dlg( aParent, aGlobal, aProject ); + DIALOG_FP_LIB_TABLE dlg( aParent, aGlobal, aProject ); - int ret = dlg.ShowModal(); - switch( ret ) - { - case wxID_OK: - break; + int dialogRet = dlg.ShowModal(); // returns value passed to EndModal() above - case wxID_CANCEL: - break; - } - - return 0; + return dialogRet; } diff --git a/pcbnew/pcbnew_config.cpp b/pcbnew/pcbnew_config.cpp index ce528a3df1..8930e593dc 100644 --- a/pcbnew/pcbnew_config.cpp +++ b/pcbnew/pcbnew_config.cpp @@ -102,11 +102,13 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) if( r & 1 ) { // save global table to disk and apply it + D( printf( "global has changed\n" );) } if( r & 2 ) { - // save project table to disk and apply it + // save project table to disk and apply it + D( printf( "project has changed\n" );) } } break; From e0cc8a2f11b4c4a264a0c541bc79a6e7c227f2dc Mon Sep 17 00:00:00 2001 From: Dick Hollenbeck Date: Wed, 31 Oct 2012 09:41:47 -0500 Subject: [PATCH 9/9] implement move up, move down in lib table editor --- pcbnew/dialogs/dialog_fp_lib_table.cpp | 47 +++++++++++++++++++------- pcbnew/kicad_plugin.cpp | 3 +- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/pcbnew/dialogs/dialog_fp_lib_table.cpp b/pcbnew/dialogs/dialog_fp_lib_table.cpp index b78e9ff883..b8fadde2c3 100644 --- a/pcbnew/dialogs/dialog_fp_lib_table.cpp +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -231,7 +231,6 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE 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" );) @@ -239,37 +238,33 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE void appendRowHandler( wxMouseEvent& event ) { - D(printf("%s\n", __func__);) m_cur_grid->AppendRows( 1 ); } void deleteRowHandler( wxMouseEvent& event ) { - D(printf("%s\n", __func__);) - int curRow = m_cur_grid->GetGridCursorRow(); - m_cur_grid->DeleteRows( curRow ); } void moveUpHandler( wxMouseEvent& event ) { - D(printf("%s\n", __func__);) - int curRow = m_cur_grid->GetGridCursorRow(); if( curRow >= 1 ) { + int curCol = m_cur_grid->GetGridCursorCol(); + FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); - ROW save = tbl->rows[curRow]; + ROW move_me = tbl->rows[curRow]; - tbl->DeleteRows( curRow, 1 ); - tbl->InsertRows( --curRow, 1 ); - - tbl->rows[curRow] = save; + tbl->rows.erase( tbl->rows.begin() + curRow ); + --curRow; + tbl->rows.insert( tbl->rows.begin() + curRow, move_me ); if( tbl->GetView() ) { + // fire a msg to cause redrawing wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, curRow, @@ -277,11 +272,39 @@ class DIALOG_FP_LIB_TABLE : public DIALOG_FP_LIB_TABLE_BASE tbl->GetView()->ProcessTableMessage( msg ); } + + m_cur_grid->SetGridCursor( curRow, curCol ); } } void moveDownHandler( wxMouseEvent& event ) { + FP_TBL_MODEL* tbl = (FP_TBL_MODEL*) m_cur_grid->GetTable(); + + int curRow = m_cur_grid->GetGridCursorRow(); + if( unsigned( curRow + 1 ) < tbl->rows.size() ) + { + int curCol = m_cur_grid->GetGridCursorCol(); + + ROW move_me = tbl->rows[curRow]; + + tbl->rows.erase( tbl->rows.begin() + curRow ); + ++curRow; + tbl->rows.insert( tbl->rows.begin() + curRow, move_me ); + + if( tbl->GetView() ) + { + // fire a msg to cause redrawing + wxGridTableMessage msg( tbl, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + curRow - 1, + 0 ); + + tbl->GetView()->ProcessTableMessage( msg ); + } + + m_cur_grid->SetGridCursor( curRow, curCol ); + } D(printf("%s\n", __func__);) } diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 6fcfa699ef..b52507060a 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -240,7 +240,8 @@ void FP_CACHE::Load() } // reader now owns fp, will close on exception or return - PCB_PARSER parser( new FILE_LINE_READER( fp, fpFileName ) ); + FILE_LINE_READER reader( fp, fpFileName ); + PCB_PARSER parser( &reader ); std::string name = TO_UTF8( fpFileName );