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/common/CMakeLists.txt b/common/CMakeLists.txt index befdb20510..dee8dfa568 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_KEYS_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..e22df47d20 --- /dev/null +++ b/common/fp_lib_id.cpp @@ -0,0 +1,335 @@ +/* + * 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 + * 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 +} + +//----------------------------------------- + + +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 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(); + 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; + 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 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; + } + + 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::SetFootprintName( const std::string& aFootprintName ) +{ + int separation = int( aFootprintName.find_first_of( "/" ) ); + + if( separation != -1 ) + { + logical = aFootprintName.substr( separation+1 ); + return separation + (int) logical.size() + 1; + } + else + { + footprintName = aFootprintName; + } + + 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 += ':'; + } + + if( revision.size() ) + { + ret += '/'; + ret += revision; + } + + return ret; +} + + +std::string FP_LIB_ID::GetFootprintNameAndRev() const +{ + std::string ret; + + 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 library name" ), + wxString::FromUTF8( aLogicalLib.c_str() ), + aLogicalLib.c_str(), + 0, + offset ); + } + + ret += aLogicalLib; + ret += ':'; + } + + 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[] = { + "smt:R_0805/rev0", + "mysmt:R_0805/rev2", + "device:AXIAL-0500", + }; + + 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 "nickName 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(); + + ROW row; + + row.SetNickName( in->FromUTF8() ); + + in->NeedRIGHT(); + + // (uri "FULL_URI") + in->NeedLEFT(); + + if( ( tok = in->NextTok() ) != T_full_uri ) + in->Expecting( T_full_uri ); + + in->NeedSYMBOLorNUMBER(); + + row.SetFullURI( in->FromUTF8() ); + + 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(); + + if( ( tok = in->NextTok() ) != T_options ) + in->Expecting( T_options ); + + in->NeedSYMBOLorNUMBER(); + + row.SetOptions( in->FromUTF8() ); + + in->NeedRIGHT(); + 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 + // conflicting nickName and ours will supercede that one since in + // FindLib() we search this table before any fall back.) + if( !InsertRow( row ) ) + { + wxString msg = wxString::Format( + _( "'%s' is a duplicate footprint library nickName" ), + GetChars( row.nickName ) + ); + 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->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 (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() + ); +} + + +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 + // nickname 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->nickName ); + } + + } while( ( cur = cur->fallBack ) != 0 ); + + // 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; +} + + +const FP_LIB_TABLE::ROW* FP_LIB_TABLE::findRow( const wxString& aNickName ) +{ + FP_LIB_TABLE* cur = this; + + do + { + cur->ensureIndex(); + + INDEX_CITER it = cur->nickIndex.find( aNickName ); + + if( it != cur->nickIndex.end() ) + { + return &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 ) +{ + ensureIndex(); + + 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; +} + + +const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aLibraryNickName ) + throw( IO_ERROR ) +{ + const ROW* row = findRow( aLibraryNickName ); + + 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 ) +{ + const ROW* row = FindRow( aFootprintId.GetLibraryNickName() ); + + // row will never be NULL here. + + PLUGIN::RELEASER pi( PluginFind( row->type ) ); + + return pi->FootprintLoad( aLibraryPath->GetFullURI() ), + aFootprintId.GetFootprintName(), + + // fetch a PROPERTIES instance on stack here + row->GetPropertiesFromOptions() + ); +} +#endif 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/cvpcb/class_components_listbox.cpp b/cvpcb/class_components_listbox.cpp index a183c81bd3..7f9b9a6e21 100644 --- a/cvpcb/class_components_listbox.cpp +++ b/cvpcb/class_components_listbox.cpp @@ -17,7 +17,7 @@ COMPONENTS_LISTBOX::COMPONENTS_LISTBOX( CVPCB_MAINFRAME* parent, wxWindowID id, const wxPoint& loc, const wxSize& size, int nbitems, wxString choice[] ) : - ITEMS_LISTBOX_BASE( parent, id, loc, size, LISTB_STYLE&(~wxLC_SINGLE_SEL)) + ITEMS_LISTBOX_BASE( parent, id, loc, size, LISTB_STYLE & ~wxLC_SINGLE_SEL ) { } diff --git a/cvpcb/cvpcb.h b/cvpcb/cvpcb.h index 738a0143b6..5399a555e1 100644 --- a/cvpcb/cvpcb.h +++ b/cvpcb/cvpcb.h @@ -19,8 +19,7 @@ #define FILTERFOOTPRINTKEY "FilterFootprint" -#define LISTB_STYLE wxSUNKEN_BORDER | wxLC_NO_HEADER | \ - wxLC_REPORT | wxLC_VIRTUAL +#define LISTB_STYLE (wxSUNKEN_BORDER | wxLC_NO_HEADER | wxLC_REPORT | wxLC_VIRTUAL) #include diff --git a/include/fp_lib_id.h b/include/fp_lib_id.h new file mode 100644 index 0000000000..97fd2a1d1d --- /dev/null +++ b/include/fp_lib_id.h @@ -0,0 +1,205 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * 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 + * 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 + * 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 (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/rev0". + * + *

+ *

    + *
  • "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 +{ +public: + + FP_LIB_ID() {} + + /** + * Constructor FP_LIB_ID + * 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. + * + * @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 name portion of a FP_LIB_ID. + */ + const std::string& GetLogicalLib() const + { + return logical; + } + + /** + * 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 GetFootprintName + * returns the footprint name, i.e. footprintName part without revision. + */ + const std::string& GetFootprintName() const + { + return footprintName; + } + + /** + * Function GetFootprintNameAndRev + * returns the part name with revision if any, i.e. footprintName[/revN..] + */ + std::string GetFootprintNameAndRev() const; + + /** + * Function SetFootprintName + * 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 ); + + /** + * 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 fully formatted 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 revision; ///< "revN[N..]" or empty + 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. + * @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..2d23bee00e --- /dev/null +++ b/include/fp_lib_table.h @@ -0,0 +1,432 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2010-12 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 +#include + +#include +#include + + +class OUTPUTFORMATTER; +class MODULE; +class FP_LIB_TABLE_LEXER; + +/** + * 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 +{ + friend class DIALOG_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; + friend class DIALOG_FP_LIB_TABLE; + + public: + + typedef IO_MGR::PCB_FILE_T LIB_T; + + ROW() : type( IO_MGR::KICAD ) + { + } + + 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. + */ + const wxString& GetNickName() const + { + return nickName; + } + + /** + * Function GetType + * returns the type of LIB represented by this record. + */ + const wxString GetType() const + { + return IO_MGR::ShowType( type ); + } + + /** + * Function GetFullURI + * returns the full location specifying URI for the LIB. + */ + const wxString& 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 wxString& GetOptions() const + { + return options; + } + + /** + * 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 SetNickName + * changes the logical name of this library, useful for an editor. + */ + void SetNickName( const wxString& aNickName ) + { + nickName = aNickName; + } + + /** + * Function SetType + * changes the type represented by this record. + */ + void SetType( const wxString& aType ) + { + type = IO_MGR::EnumFromStr( aType ); + } + + /** + * Function SetFullURI + * changes the full URI for the library, useful from a library table editor. + */ + void SetFullURI( const wxString& aFullURI ) + { + uri = aFullURI; + } + + /** + * Function SetOptions + * changes the options string for this record, and is useful from + * the library table editor. + */ + void SetOptions( const wxString& aOptions ) + { + options = aOptions; + } + + private: + + wxString nickName; + wxString uri; + LIB_T type; + wxString options; + }; + + + /** + * 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 ); + + 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 + * 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 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 wxString* tells if not found, but might be too + // promiscuous? + +#if 0 + /** + * 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 wxString* - or NULL if not found. + */ + const wxString* GetURI( const wxString& 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 wxString* - or NULL if not found. + */ + const wxString* GetType( const wxString& 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 wxString* - or NULL if not found. + */ + const wxString* GetLibOptions( const wxString& aLogicalLibraryName ) const + { + const ROW* row = FindRow( aLogicalLibraryName ); + return row ? &row->options : 0; + } +#endif + + //------------------------------------------------------- + +#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 + + /** + * 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 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( 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. + */ + 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() + { + nickIndex.clear(); + + for( ROWS_CITER it = rows.begin(); it != rows.end(); ++it ) + 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; + + 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 // I don't think this is going to be needed. + + /** + * 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 + + +#endif // FP_LIB_TABLE_H_ 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..b8fadde2c3 --- /dev/null +++ b/pcbnew/dialogs/dialog_fp_lib_table.cpp @@ -0,0 +1,397 @@ +/* + * 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 +#include +#include + + +/** + * Class FP_TBL_MODEL + * mixes in wxGridTableBase into FP_LIB_TABLE so that the latter can be used + * as a table within wxGrid. + */ +class FP_TBL_MODEL : public wxGridTableBase, public FP_LIB_TABLE +{ +public: + + /** + * Constructor FP_TBL_MODEL + * 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 + { + } + + //------------------------------------------------ + + 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.SetFullURI( aValue ); break; + case 2: r.SetType( 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() ); + + // use the (wxGridStringTable) source Luke. + if( GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + aPos, + aNumRows ); + + GetView()->ProcessTableMessage( msg ); + } + + return true; + } + return false; + } + + bool AppendRows( size_t aNumRows = 1 ) + { + // 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; + } + + bool DeleteRows( size_t aPos, size_t aNumRows ) + { + if( aPos + aNumRows <= rows.size() ) + { + 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; + } + + 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 + * 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 +{ + 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 );) + } + */ + + //--------------------------------------- + + 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" );) + } + + void appendRowHandler( wxMouseEvent& event ) + { + m_cur_grid->AppendRows( 1 ); + } + + void deleteRowHandler( wxMouseEvent& event ) + { + int curRow = m_cur_grid->GetGridCursorRow(); + m_cur_grid->DeleteRows( curRow ); + } + + void moveUpHandler( wxMouseEvent& event ) + { + 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 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, + 0 ); + + 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__);) + } + + void onCancelButtonClick( wxCommandEvent& event ) + { + EndModal( 0 ); + } + + void onOKButtonClick( wxCommandEvent& event ) + { + int dialogRet = 0; + + if( m_global_model != *m_global ) + { + dialogRet |= 1; + + *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 ); + } + + //-------------------------------------- + + + // caller's tables are modified only on OK button. + FP_LIB_TABLE* m_global; + FP_LIB_TABLE* m_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 + + +public: + 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_global_model( *aGlobal ), + m_project_model( *aProject ) + { + m_global_grid->SetTable( (wxGridTableBase*) &m_global_model ); + m_project_grid->SetTable( (wxGridTableBase*) &m_project_model ); + + m_global_grid->AutoSizeColumns( false ); + + 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() + { + // Destroy the gui stuff first, with a goal of destroying the two wxGrids now, + // since the ~wxGrid() wants the wxGridTableBase to still be non-destroyed. + // Without this call, the wxGridTableBase objects are destroyed first + // (i.e. destructor called) and there is a segfault since wxGridTableBase's vtable + // is then no longer valid. If ~wxGrid() would not examine a wxGridTableBase that + // it does not own, then this would not be a concern. But it is, since it does. + DestroyChildren(); + } +}; + + + +int InvokePcbLibTableEditor( wxFrame* aParent, FP_LIB_TABLE* aGlobal, FP_LIB_TABLE* aProject ) +{ + DIALOG_FP_LIB_TABLE dlg( aParent, aGlobal, aProject ); + + int dialogRet = dlg.ShowModal(); // returns value passed to EndModal() above + + return dialogRet; +} + 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..6844652cf5 --- /dev/null +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.cpp @@ -0,0 +1,221 @@ +/////////////////////////////////////////////////////////////////////////// +// 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_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_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_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* m_global_sizer; + m_global_sizer = new wxBoxSizer( wxVERTICAL ); + + m_global_grid = new wxGrid( m_global_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + 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_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_global_grid->EnableDragRowSize( true ); + m_global_grid->SetRowLabelSize( 40 ); + m_global_grid->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_global_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + m_global_sizer->Add( m_global_grid, 1, wxALL|wxEXPAND, 5 ); + + + m_global_panel->SetSizer( m_global_sizer ); + m_global_panel->Layout(); + 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; + m_project_sizer = new wxBoxSizer( wxVERTICAL ); + + m_project_grid = new wxGrid( m_project_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + 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_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_project_grid->EnableDragRowSize( true ); + m_project_grid->SetRowLabelSize( 40 ); + m_project_grid->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_project_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + m_project_sizer->Add( m_project_grid, 1, wxALL|wxEXPAND, 5 ); + + + 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 ); + + m_top_sizer->Add( m_auinotebook, 1, wxEXPAND | wxALL, 5 ); + + wxBoxSizer* bSizer51; + bSizer51 = new wxBoxSizer( wxHORIZONTAL ); + + 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_append_button, 0, wxALL, 5 ); + + 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_delete_button, 0, wxALL, 5 ); + + 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_move_up_button, 0, wxALL, 5 ); + + 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_move_down_button, 0, wxALL, 5 ); + + + m_top_sizer->Add( bSizer51, 0, wxALIGN_CENTER|wxBOTTOM, 8 ); + + + m_top->SetSizer( m_top_sizer ); + m_top->Layout(); + 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_path_subs_grid = new wxGrid( m_bottom, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + + // Grid + 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_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_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_path_subs_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + sbSizer1->Add( m_path_subs_grid, 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 ); + m_sdbSizer1->AddButton( m_sdbSizer1OK ); + m_sdbSizer1Cancel = new wxButton( m_bottom, wxID_CANCEL ); + m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); + m_sdbSizer1->Realize(); + + m_bottom_sizer->Add( m_sdbSizer1, 0, wxALL|wxEXPAND, 5 ); + + + m_bottom->SetSizer( m_bottom_sizer ); + m_bottom->Layout(); + 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(); + + 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 new file mode 100644 index 0000000000..be77cf4205 --- /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 + + 864,652 + 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_splitter + 1 + + + protected + 1 + + Resizable + 0.0 + 343 + -1 + 1 + + wxSPLIT_HORIZONTAL + wxSP_3DSASH + + 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 + Library Tables by Scope + + m_top_sizer + 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_auinotebook + 1 + + + protected + 1 + + Resizable + 1 + + wxAUI_NB_BOTTOM + + -1 + 0 + + + + + + + + + + + pageChangedHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + + Global Libraries + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_global_panel + 1 + + + protected + 0 + + Resizable + 1 + + + 0 + Module libraries which are visible for all projects + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + m_global_sizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + 1 + 0 + + + + 1 + + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 30 + + wxALIGN_CENTRE + 4 + + + 1 + 0 + Dock + 1 + Left + 0 + 1 + 1 + 1 + 1 + 1 + + 0 + + + 1 + 0 + 0 + wxID_ANY + + + + 0 + 0 + + 0 + + + 0 + + 0 + m_global_grid + 1 + + + protected + 1 + + Fixed + wxALIGN_CENTRE + 40 + + wxALIGN_CENTRE + + 1 + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Project Specific Libraries + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_project_panel + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + wxTAB_TRAVERSAL + + + + + + + + + + + + + + + + + + + + + + + + + + m_project_sizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + 1 + 0 + + + + 1 + + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 30 + + wxALIGN_CENTRE + 4 + + + 1 + 0 + Dock + 1 + Left + 0 + 1 + 1 + 1 + 1 + 1 + + 0 + + + 1 + 0 + 0 + wxID_ANY + + + + 0 + 0 + + 0 + + + 0 + + 0 + m_project_grid + 1 + + + protected + 1 + + Fixed + wxALIGN_CENTRE + 40 + + wxALIGN_CENTRE + + 1 + 1 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + wxALIGN_CENTER|wxBOTTOM + 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_append_button + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Add a pcb library row to this table + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + appendRowHandler + + + + + + + + + + + + + + + + + + 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_delete_button + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Remove a PCB library from this library table + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + deleteRowHandler + + + + + + + + + + + + + + + + + + 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_move_up_button + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Move the currently selected row up one position + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + moveUpHandler + + + + + + + + + + + + + + + + + + 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_move_down_button + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + Move the currently selected row down one position + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + moveDownHandler + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + m_bottom_sizer + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + wxID_ANY + Path Substitutions + + sbSizer1 + wxVERTICAL + none + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + 1 + 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_path_subs_grid + 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 + + onCancelButtonClick + + + + onOKButtonClick + + + + + + + + + + + + + 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..3156b1cdf5 --- /dev/null +++ b/pcbnew/dialogs/dialog_fp_lib_table_base.h @@ -0,0 +1,85 @@ +/////////////////////////////////////////////////////////////////////////// +// 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_splitter; + wxPanel* m_top; + 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_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( 864,652 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_FP_LIB_TABLE_BASE(); + + void m_splitterOnIdle( wxIdleEvent& ) + { + m_splitter->SetSashPosition( 343 ); + m_splitter->Disconnect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FP_LIB_TABLE_BASE::m_splitterOnIdle ), NULL, this ); + } + +}; + +#endif //__DIALOG_FP_LIB_TABLE_BASE_H__ diff --git a/pcbnew/io_mgr.cpp b/pcbnew/io_mgr.cpp index 1f32f77bea..505fe72d19 100644 --- a/pcbnew/io_mgr.cpp +++ b/pcbnew/io_mgr.cpp @@ -80,22 +80,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 85ec6ebc16..53778ca310 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/menubar_pcbframe.cpp b/pcbnew/menubar_pcbframe.cpp index c30143136f..9b1c6c57e6 100644 --- a/pcbnew/menubar_pcbframe.cpp +++ b/pcbnew/menubar_pcbframe.cpp @@ -426,6 +426,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/pcb_parser.h b/pcbnew/pcb_parser.h index 3bbf9624f8..a9659c176c 100644 --- a/pcbnew/pcb_parser.h +++ b/pcbnew/pcb_parser.h @@ -32,7 +32,7 @@ #include #include -using namespace PCB; +using namespace PCB_KEYS_T; class BOARD; 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..8930e593dc 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,37 @@ void PCB_EDIT_FRAME::Process_Config( wxCommandEvent& event ) InstallConfigFrame(); break; + 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 ) + { + // 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 + D( printf( "project has changed\n" );) + } + } + 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..bed0fb40f2 100644 --- a/pcbnew/pcbnew_id.h +++ b/pcbnew/pcbnew_id.h @@ -1,5 +1,5 @@ -#ifndef __PCBNEW_ID_H__ -#define __PCBNEW_ID_H__ +#ifndef PCBNEW_ID_H_ +#define PCBNEW_ID_H_ #include @@ -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__ */ +#endif // PCBNEW_ID_H_