Loading common/edaappl.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -680,7 +680,11 @@ bool WinEDA_App::SetLanguage( bool first_time ) delete m_Locale; m_Locale = new wxLocale; #if wxCHECK_VERSION( 2, 9, 0 ) if( !m_Locale->Init( m_LanguageId ) ) #else if( !m_Locale->Init( m_LanguageId, wxLOCALE_CONV_ENCODING ) ) #endif { wxLogDebug( wxT("This language is not supported by the system.") ); Loading eeschema/annotate.cpp +159 −66 Original line number Diff line number Diff line Loading @@ -19,14 +19,11 @@ #include "sch_component.h" #include "lib_pin.h" //#define USE_OLD_ALGO static void BreakReference( SCH_REFERENCE_LIST& aComponentsList ); static void ReAnnotateComponents( SCH_REFERENCE_LIST& aComponentsList ); static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aUseSheetNum ); static int GetLastReferenceNumber( int aObjet,SCH_REFERENCE_LIST& aComponentsList ); static int ExistUnit( int aObjet, int aUnit, SCH_REFERENCE_LIST& aComponentList ); /** * Function DeleteAnnotation * Remove current component annotations Loading Loading @@ -109,7 +106,7 @@ void SCH_EDIT_FRAME::AnnotateComponents( // Update the screen date. screens.SetDate( GenDate() ); // Set sheet number and total sheet counts. // Set sheet number and number of sheets. SetSheetNumberAndCount(); /* Build component list */ Loading @@ -124,7 +121,7 @@ void SCH_EDIT_FRAME::AnnotateComponents( /* Break full components reference in name (prefix) and number: * example: IC1 become IC, and 1 */ BreakReference( references ); references.SplitReferences( ); bool useSheetNum = false; switch( sortOption ) Loading Loading @@ -152,36 +149,126 @@ void SCH_EDIT_FRAME::AnnotateComponents( break; } /* Recalculate reference numbers */ // Recalculate and update reference numbers in schematic ComputeReferenceNumber( references, useSheetNum ); ReAnnotateComponents( references ); references.UpdateAnnotation(); /* Final control (just in case ... )*/ CheckAnnotate( NULL, !annotateSchematic ); OnModify(); // Update on screen refences, that can be modified by previous calculations: m_CurrentSheet->UpdateAllScreenReferences(); SetSheetNumberAndCount(); DrawPanel->Refresh( true ); } #ifdef USE_OLD_ALGO /** helper function * Search the last used (greatest) reference number in the component list * for the prefix reference given by Objet * The component list must be sorted. * * @param aObjet = reference item ( aComponentsList[aObjet].m_TextRef is * the search pattern) * @param aComponentsList = list of items * @param aMinValue = min value for the current search */ static int GetLastNumberInReference( int aObjet,SCH_REFERENCE_LIST& aComponentsList, int aMinValue ) { int lastNumber = aMinValue; /* * Update the reference component for the schematic project (or the current sheet) for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) { // search only for the current reference prefix: if( aComponentsList[aObjet].CompareRef( aComponentsList[ii] ) != 0 ) continue; // update max value for the current reference prefix if( lastNumber < aComponentsList[ii].m_NumRef ) lastNumber = aComponentsList[ii].m_NumRef; } return lastNumber; } #else /** * helper function BuildRefIdInUseList * creates the list of reference numbers in use for a given reference prefix. * @param aObjet = the current component index to use for reference prefix filtering. * @param aComponentsList = the full list of components * @param aIdList = the buffer to fill * @param aMinRefId = the min id value to store. all values < aMinRefId are ignored */ static void ReAnnotateComponents( SCH_REFERENCE_LIST& aComponentList ) static void BuildRefIdInUseList( int aObjet,SCH_REFERENCE_LIST& aComponentsList, std::vector<int>& aIdList, int aMinRefId ) { /* update the reference numbers */ for( unsigned ii = 0; ii < aComponentList.GetCount(); ii++ ) aIdList.clear(); for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) { aComponentList[ii].Annotate(); if( ( aComponentsList[aObjet].CompareRef( aComponentsList[ii] ) == 0 ) && ( aComponentsList[ii].m_NumRef >= aMinRefId ) ) aIdList.push_back( aComponentsList[ii].m_NumRef ); } sort( aIdList.begin(), aIdList.end() ); // Ensure each reference Id appears only once // If there are multiple parts per package the same Id will be stored for each part. for( unsigned ii = 1; ii < aIdList.size(); ii++ ) { if( aIdList[ii] != aIdList[ii-1] ) continue; aIdList.erase(aIdList.begin() + ii ); ii--; } } /** * helper function CreateFirstFreeRefId * Search for a free ref Id inside a list of reference numbers in use. * This list is expected sorted by increasing values, and each value stored only once * @see BuildRefIdInUseList to prepare this list * @param aIdList = the buffer that contains Ids in use * @param aFirstValue = the first expected free value * @return a free (not yet used) Id * and this new id is added in list */ static int CreateFirstFreeRefId( std::vector<int>& aIdList, int aFirstValue ) { int expectedId = aFirstValue; void BreakReference( SCH_REFERENCE_LIST& aComponentsList ) // We search for expectedId a value >= aFirstValue. // Skip existing Id < aFirstValue unsigned ii = 0; for( ; ii < aIdList.size(); ii++ ) { for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) aComponentsList[ii].Split(); if( expectedId <= aIdList[ii] ) break; } // Ids are sorted by increasing value, from aFirstValue // So we search from aFirstValue the first not used value, i.e. the first hole in list. for(; ii < aIdList.size(); ii++ ) { if( expectedId != aIdList[ii] ) // This id is not yet used. { // Insert this free Id, in order to keep list sorted aIdList.insert(aIdList.begin() + ii, expectedId); return expectedId; } expectedId++; } // All existing Id are tested, and all values are found in use. // So Create a new one. aIdList.push_back( expectedId ); return expectedId; } #endif /* * Compute the reference number for components without reference number Loading @@ -189,7 +276,11 @@ void BreakReference( SCH_REFERENCE_LIST& aComponentsList ) */ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aUseSheetNum ) { int LastReferenceNumber, NumberOfUnits, Unit; if ( aComponentsList.GetCount() == 0 ) return; int LastReferenceNumber = 0; int NumberOfUnits, Unit; /* Components with an invisible reference (power...) always are * re-annotated. So set their .m_IsNew member to true Loading @@ -209,33 +300,59 @@ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aU * IC .. will be set to IC4, IC4, IC5 ... */ unsigned first = 0; /* calculate the last used number for this reference prefix: */ LastReferenceNumber = GetLastReferenceNumber( first, aComponentsList ); #ifdef USE_OLD_ALGO int minRefId = 0; // when using sheet number, ensure ref number >= sheet number* 100 if( aUseSheetNum ) minRefId = aComponentsList[first].m_SheetNum * 100; LastReferenceNumber = GetLastNumberInReference( first, aComponentsList, minRefId ); #else int minRefId = 1; // when using sheet number, ensure ref number >= sheet number* 100 if( aUseSheetNum ) minRefId = aComponentsList[first].m_SheetNum * 100 + 1; // This is the list of all Id already in use for a given reference prefix. // Will be refilled for each new reference prefix. std::vector<int>idList; BuildRefIdInUseList( first, aComponentsList, idList, minRefId ); #endif for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) { if( aComponentsList[ii].m_Flag ) continue; if( aComponentsList[first].CompareRef( aComponentsList[ii] ) != 0 ) if( ( aComponentsList[first].CompareRef( aComponentsList[ii] ) != 0 ) || ( aUseSheetNum && ( aComponentsList[first].m_SheetNum != aComponentsList[ii].m_SheetNum ) ) ) { /* New reference found: we need a new ref number for this * reference */ first = ii; LastReferenceNumber = GetLastReferenceNumber( ii, aComponentsList ); } // when using sheet number, ensure annot number >= sheet number* 100 #ifdef USE_OLD_ALGO minRefId = 0; // when using sheet number, ensure ref number >= sheet number* 100 if( aUseSheetNum ) { int min_num = aComponentsList[ii].m_SheetNum * 100; if( LastReferenceNumber < min_num ) LastReferenceNumber = min_num; minRefId = aComponentsList[ii].m_SheetNum * 100; LastReferenceNumber = GetLastNumberInReference( ii, aComponentsList, minRefId); #else minRefId = 1; // when using sheet number, ensure ref number >= sheet number* 100 if( aUseSheetNum ) minRefId = aComponentsList[ii].m_SheetNum * 100 + 1; BuildRefIdInUseList( first, aComponentsList, idList, minRefId ); #endif } /* Annotation of one part per package components (trivial case)*/ if( aComponentsList[ii].m_Entry->GetPartCount() <= 1 ) { if( aComponentsList[ii].m_IsNew ) { #ifdef USE_OLD_ALGO LastReferenceNumber++; #else LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); #endif aComponentsList[ii].m_NumRef = LastReferenceNumber; } Loading @@ -251,7 +368,11 @@ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aU if( aComponentsList[ii].m_IsNew ) { #ifdef USE_OLD_ALGO LastReferenceNumber++; #else LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); #endif aComponentsList[ii].m_NumRef = LastReferenceNumber; if( !aComponentsList[ii].IsPartsLocked() ) Loading Loading @@ -307,33 +428,6 @@ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aU } /** * Search the last used (greatest) reference number in the component list * for the prefix reference given by Objet * The component list must be sorted. * * @param aObjet = reference item ( aComponentsList[aObjet].m_TextRef is * the search pattern) * @param aComponentsList = list of items */ int GetLastReferenceNumber( int aObjet,SCH_REFERENCE_LIST& aComponentsList ) { int LastNumber = 0; for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) { /* New identifier. */ if( aComponentsList[aObjet].CompareRef( aComponentsList[ii] ) != 0 ) continue; if( LastNumber < aComponentsList[ii].m_NumRef ) LastNumber = aComponentsList[ii].m_NumRef; } return LastNumber; } /** * Search in the sorted list of components, for a given component an other * component with the same reference and a given part unit. Mainly used to Loading Loading @@ -391,7 +485,7 @@ static int ExistUnit( int aObjet, int Unit, SCH_REFERENCE_LIST& aComponentsList */ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOnly ) { int error; int error = 0; wxString Buff; wxString msg, cmpref; Loading @@ -410,18 +504,15 @@ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOn /* Break full components reference in name (prefix) and number: example: * IC1 become IC, and 1 */ BreakReference( ComponentsList ); ComponentsList.SplitReferences(); /* count not yet annotated items */ error = 0; int imax = ComponentsList.GetCount() - 1; for( int ii = 0; ii < imax; ii++ ) /* count not yet annotated items or annottaion error*/ for( unsigned ii = 0; ii < ComponentsList.GetCount(); ii++ ) { msg.Empty(); Buff.Empty(); if( ComponentsList[ii].m_IsNew ) if( ComponentsList[ii].m_IsNew ) // Not yet annotated { if( ComponentsList[ii].m_NumRef >= 0 ) Buff << ComponentsList[ii].m_NumRef; Loading @@ -446,7 +537,8 @@ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOn break; } // Annotate error // Annotate error if unit selected does not exist ( i.e. > number of parts ) // Can happen if a component has changed in a lib, after a previous annotation if( MAX( ComponentsList[ii].m_Entry->GetPartCount(), 1 ) < ComponentsList[ii].m_Unit ) { if( ComponentsList[ii].m_NumRef >= 0 ) Loading Loading @@ -477,6 +569,7 @@ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOn return error; // count the duplicated elements (if all are annotated) int imax = ComponentsList.GetCount() - 1; for( int ii = 0; (ii < imax) && (error < 4); ii++ ) { msg.Empty(); Loading eeschema/netlist.h +33 −0 Original line number Diff line number Diff line Loading @@ -226,6 +226,39 @@ public: * When annotating, some or all components are not annotated, * i.e. ref is only U or R, with no number. */ /** * Function SplitReferences * attempts to split all reference designators into a name (U) and number (1). If the * last character is '?' or not a digit, the reference is tagged as not annotated. * For components with multiple parts per package that are not already annotated, set * m_Unit to a max value (0x7FFFFFFF). * @see SCH_REFERENCE::Split() */ void SplitReferences() { for( unsigned ii = 0; ii < GetCount(); ii++ ) componentFlatList[ii].Split(); } /** * function UpdateAnnotation * Update the reference components for the schematic project (or the current sheet) * Note: this function does not calculate the reference numbers * stored in m_NumRef * So, it must be called after calcultaion of new reference numbers * @see SCH_REFERENCE::Annotate() */ void UpdateAnnotation() { /* update the reference numbers */ for( unsigned ii = 0; ii < GetCount(); ii++ ) { componentFlatList[ii].Annotate(); } } /** * Function SortCmpByXCoordinate * sort the flat list by X coordinates. Loading new/sch_dir_lib_source.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -459,8 +459,12 @@ void DIR_LIB_SOURCE::GetRevisions( STRINGS* aResults, const STRING& aPartName ) PN_ITER it = partnames.upper_bound( partName +'/' ); PN_ITER end = partnames.lower_bound( partName + char( '/' +1 ) ); while( it != end ) aResults->push_back( *it++ ); for( ; it != end; ++it ) { const char* rev = endsWithRev( *it ); assert( rev ); aResults->push_back( it->substr( rev - it->c_str() ) ); } } } Loading new/sch_lib.cpp +63 −31 Original line number Diff line number Diff line Loading @@ -39,13 +39,12 @@ /* The LIB part cache consist of a std::map of partnames without revisions at the top level. Each top level map entry can point to another std::map which it owns and holds all the revisions for that part name. At any point in the tree, there can be NULL pointers which allow for lazy loading, including the very top most root pointer itself, which is PARTS* parts. We use the key to hold the partName at one level, and revision at the deeper nested level, and that key information may not be present within right hand side of the map tuple. The LIB part cache consists of a std::map of partnames without revisions at the top level. Each top level map entry can point to another std::map which it owns and which holds all the revisions for that part name. At any point in the tree, there can be NULL pointers which allow for lazy loading, including the very top most root pointer itself, which is PARTS* parts. We use the key to hold the partName at one level, and revision at the deeper nested level. 1) Only things which are asked for are done. 2) Anything we learn we remember. Loading @@ -54,10 +53,31 @@ right hand side of the map tuple. namespace SCH { class PART_REVS : public std::map< STRING, PART* > /** * Struct LTREV * is for PART_REVS, and provides a custom way to compare rev STRINGs. * Namely, the revN[N..] string if present, is collated according to a * 'higher revision first'. */ struct LTREV { bool operator() ( const STRING& s1, const STRING& s2 ) const { // @todo provide an integer sort on revN.. strings here. return RevCmp( s1.c_str(), s2.c_str() ) < 0; } }; /** * Class PART_REVS * contains the collection of revisions for a particular part name, in the * form of cached PARTs. The tuple consists of a rev string and a PART pointer. * The rev string is like "rev1", the PART pointer will be NULL until the PART * gets loaded, lazily. */ class PART_REVS : public std::map< STRING, PART*, LTREV > { public: ~PART_REVS() { Loading @@ -68,6 +88,15 @@ public: } }; /** * Class PARTS * contains the collection of PART_REVS for all PARTs in the lib. * The tuple consists of a part name and a PART_REVS pointer. * The part name does not have the revision attached (of course this is understood * by definition of "part name"). The PART_REVS pointer will be NULL until a client * askes about the revisions for a part name, so the loading is done lazily. */ class PARTS : public std::map< STRING, PART_REVS* > { public: Loading Loading @@ -126,7 +155,7 @@ LIB::~LIB() } const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR ) const PART* LIB::lookupPart( const LPID& aLPID ) throw( IO_ERROR ) { if( !parts ) { Loading @@ -137,7 +166,7 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR ) // insert a PART_REVS for each part name for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it ) { // D(printf("findPart:%s\n", it->c_str() );) D(printf("lookupPart:%s\n", it->c_str() );) (*parts)[*it] = new PART_REVS; } } Loading @@ -152,44 +181,46 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR ) // if the key for parts has no aLPID.GetPartName() the part is not in this lib if( revs ) { if( revs->size() == 0 ) if( revs->size() == 0 ) // assume rev list has not been loaded yet { // load all the revisions for this part. source->GetRevisions( &vfetch, aLPID.GetPartName() ); // creat a PART_REV entry for revision, but leave the PART* NULL // create a PART_REV entry for each revision, but leave the PART* NULL for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it ) { // D(printf("findPartRev:%s\n", it->c_str() );) D(printf("lookupPartRev:%s\n", it->c_str() );) (*revs)[*it] = 0; } } PART_REVS::iterator result = revs->find( aLPID.GetPartNameAndRev() ); PART_REVS::iterator rev; if( result != revs->end() ) // If caller did not say what revision, find the highest numbered one and return that. if( !aLPID.GetRevision().size() && revs->size() ) { if( !result->second ) // the PART has never been loaded before rev = revs->begin(); // sort order has highest rev first if( !rev->second ) // the PART has never been instantiated before { result->second = new PART( this, aLPID.GetPartNameAndRev() ); rev->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), rev->first ) ); } return result->second; D(printf("lookupPartLatestRev:%s\n", rev->second->partNameAndRev.c_str() );) return rev->second; } // If caller did not say what revision, find the highest numbered one and return that. // Otherwise he knew what he wanted specifically, and we do not have it. if( !aLPID.GetRevision().size() && revs->size() ) else { result = revs->begin(); // sort order has highest rev first rev = revs->find( aLPID.GetRevision() ); if( !result->second ) // the PART has never been loaded before if( rev != revs->end() ) { if( !rev->second ) // the PART has never been instantiated before { result->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), result->first ) ); rev->second = new PART( this, aLPID.GetPartNameAndRev() ); } return rev->second; } return result->second; } } Loading @@ -199,7 +230,7 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR ) PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR ) { PART* part = (PART*) findPart( aLPID ); PART* part = (PART*) lookupPart( aLPID ); if( !part ) // part does not exist in this lib { Loading @@ -221,7 +252,8 @@ PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR printf( "\n" ); #endif SWEET_LEXER sw( part->body, wxString::FromUTF8("body") /* @todo have ReadPart give better source */ ); // @todo consider changing ReadPart to return a "source" SWEET_LEXER sw( part->body, wxString::FromUTF8( aLPID.Format().c_str() ) ); part->Parse( &sw, aLibTable ); } Loading Loading
common/edaappl.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -680,7 +680,11 @@ bool WinEDA_App::SetLanguage( bool first_time ) delete m_Locale; m_Locale = new wxLocale; #if wxCHECK_VERSION( 2, 9, 0 ) if( !m_Locale->Init( m_LanguageId ) ) #else if( !m_Locale->Init( m_LanguageId, wxLOCALE_CONV_ENCODING ) ) #endif { wxLogDebug( wxT("This language is not supported by the system.") ); Loading
eeschema/annotate.cpp +159 −66 Original line number Diff line number Diff line Loading @@ -19,14 +19,11 @@ #include "sch_component.h" #include "lib_pin.h" //#define USE_OLD_ALGO static void BreakReference( SCH_REFERENCE_LIST& aComponentsList ); static void ReAnnotateComponents( SCH_REFERENCE_LIST& aComponentsList ); static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aUseSheetNum ); static int GetLastReferenceNumber( int aObjet,SCH_REFERENCE_LIST& aComponentsList ); static int ExistUnit( int aObjet, int aUnit, SCH_REFERENCE_LIST& aComponentList ); /** * Function DeleteAnnotation * Remove current component annotations Loading Loading @@ -109,7 +106,7 @@ void SCH_EDIT_FRAME::AnnotateComponents( // Update the screen date. screens.SetDate( GenDate() ); // Set sheet number and total sheet counts. // Set sheet number and number of sheets. SetSheetNumberAndCount(); /* Build component list */ Loading @@ -124,7 +121,7 @@ void SCH_EDIT_FRAME::AnnotateComponents( /* Break full components reference in name (prefix) and number: * example: IC1 become IC, and 1 */ BreakReference( references ); references.SplitReferences( ); bool useSheetNum = false; switch( sortOption ) Loading Loading @@ -152,36 +149,126 @@ void SCH_EDIT_FRAME::AnnotateComponents( break; } /* Recalculate reference numbers */ // Recalculate and update reference numbers in schematic ComputeReferenceNumber( references, useSheetNum ); ReAnnotateComponents( references ); references.UpdateAnnotation(); /* Final control (just in case ... )*/ CheckAnnotate( NULL, !annotateSchematic ); OnModify(); // Update on screen refences, that can be modified by previous calculations: m_CurrentSheet->UpdateAllScreenReferences(); SetSheetNumberAndCount(); DrawPanel->Refresh( true ); } #ifdef USE_OLD_ALGO /** helper function * Search the last used (greatest) reference number in the component list * for the prefix reference given by Objet * The component list must be sorted. * * @param aObjet = reference item ( aComponentsList[aObjet].m_TextRef is * the search pattern) * @param aComponentsList = list of items * @param aMinValue = min value for the current search */ static int GetLastNumberInReference( int aObjet,SCH_REFERENCE_LIST& aComponentsList, int aMinValue ) { int lastNumber = aMinValue; /* * Update the reference component for the schematic project (or the current sheet) for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) { // search only for the current reference prefix: if( aComponentsList[aObjet].CompareRef( aComponentsList[ii] ) != 0 ) continue; // update max value for the current reference prefix if( lastNumber < aComponentsList[ii].m_NumRef ) lastNumber = aComponentsList[ii].m_NumRef; } return lastNumber; } #else /** * helper function BuildRefIdInUseList * creates the list of reference numbers in use for a given reference prefix. * @param aObjet = the current component index to use for reference prefix filtering. * @param aComponentsList = the full list of components * @param aIdList = the buffer to fill * @param aMinRefId = the min id value to store. all values < aMinRefId are ignored */ static void ReAnnotateComponents( SCH_REFERENCE_LIST& aComponentList ) static void BuildRefIdInUseList( int aObjet,SCH_REFERENCE_LIST& aComponentsList, std::vector<int>& aIdList, int aMinRefId ) { /* update the reference numbers */ for( unsigned ii = 0; ii < aComponentList.GetCount(); ii++ ) aIdList.clear(); for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) { aComponentList[ii].Annotate(); if( ( aComponentsList[aObjet].CompareRef( aComponentsList[ii] ) == 0 ) && ( aComponentsList[ii].m_NumRef >= aMinRefId ) ) aIdList.push_back( aComponentsList[ii].m_NumRef ); } sort( aIdList.begin(), aIdList.end() ); // Ensure each reference Id appears only once // If there are multiple parts per package the same Id will be stored for each part. for( unsigned ii = 1; ii < aIdList.size(); ii++ ) { if( aIdList[ii] != aIdList[ii-1] ) continue; aIdList.erase(aIdList.begin() + ii ); ii--; } } /** * helper function CreateFirstFreeRefId * Search for a free ref Id inside a list of reference numbers in use. * This list is expected sorted by increasing values, and each value stored only once * @see BuildRefIdInUseList to prepare this list * @param aIdList = the buffer that contains Ids in use * @param aFirstValue = the first expected free value * @return a free (not yet used) Id * and this new id is added in list */ static int CreateFirstFreeRefId( std::vector<int>& aIdList, int aFirstValue ) { int expectedId = aFirstValue; void BreakReference( SCH_REFERENCE_LIST& aComponentsList ) // We search for expectedId a value >= aFirstValue. // Skip existing Id < aFirstValue unsigned ii = 0; for( ; ii < aIdList.size(); ii++ ) { for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) aComponentsList[ii].Split(); if( expectedId <= aIdList[ii] ) break; } // Ids are sorted by increasing value, from aFirstValue // So we search from aFirstValue the first not used value, i.e. the first hole in list. for(; ii < aIdList.size(); ii++ ) { if( expectedId != aIdList[ii] ) // This id is not yet used. { // Insert this free Id, in order to keep list sorted aIdList.insert(aIdList.begin() + ii, expectedId); return expectedId; } expectedId++; } // All existing Id are tested, and all values are found in use. // So Create a new one. aIdList.push_back( expectedId ); return expectedId; } #endif /* * Compute the reference number for components without reference number Loading @@ -189,7 +276,11 @@ void BreakReference( SCH_REFERENCE_LIST& aComponentsList ) */ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aUseSheetNum ) { int LastReferenceNumber, NumberOfUnits, Unit; if ( aComponentsList.GetCount() == 0 ) return; int LastReferenceNumber = 0; int NumberOfUnits, Unit; /* Components with an invisible reference (power...) always are * re-annotated. So set their .m_IsNew member to true Loading @@ -209,33 +300,59 @@ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aU * IC .. will be set to IC4, IC4, IC5 ... */ unsigned first = 0; /* calculate the last used number for this reference prefix: */ LastReferenceNumber = GetLastReferenceNumber( first, aComponentsList ); #ifdef USE_OLD_ALGO int minRefId = 0; // when using sheet number, ensure ref number >= sheet number* 100 if( aUseSheetNum ) minRefId = aComponentsList[first].m_SheetNum * 100; LastReferenceNumber = GetLastNumberInReference( first, aComponentsList, minRefId ); #else int minRefId = 1; // when using sheet number, ensure ref number >= sheet number* 100 if( aUseSheetNum ) minRefId = aComponentsList[first].m_SheetNum * 100 + 1; // This is the list of all Id already in use for a given reference prefix. // Will be refilled for each new reference prefix. std::vector<int>idList; BuildRefIdInUseList( first, aComponentsList, idList, minRefId ); #endif for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) { if( aComponentsList[ii].m_Flag ) continue; if( aComponentsList[first].CompareRef( aComponentsList[ii] ) != 0 ) if( ( aComponentsList[first].CompareRef( aComponentsList[ii] ) != 0 ) || ( aUseSheetNum && ( aComponentsList[first].m_SheetNum != aComponentsList[ii].m_SheetNum ) ) ) { /* New reference found: we need a new ref number for this * reference */ first = ii; LastReferenceNumber = GetLastReferenceNumber( ii, aComponentsList ); } // when using sheet number, ensure annot number >= sheet number* 100 #ifdef USE_OLD_ALGO minRefId = 0; // when using sheet number, ensure ref number >= sheet number* 100 if( aUseSheetNum ) { int min_num = aComponentsList[ii].m_SheetNum * 100; if( LastReferenceNumber < min_num ) LastReferenceNumber = min_num; minRefId = aComponentsList[ii].m_SheetNum * 100; LastReferenceNumber = GetLastNumberInReference( ii, aComponentsList, minRefId); #else minRefId = 1; // when using sheet number, ensure ref number >= sheet number* 100 if( aUseSheetNum ) minRefId = aComponentsList[ii].m_SheetNum * 100 + 1; BuildRefIdInUseList( first, aComponentsList, idList, minRefId ); #endif } /* Annotation of one part per package components (trivial case)*/ if( aComponentsList[ii].m_Entry->GetPartCount() <= 1 ) { if( aComponentsList[ii].m_IsNew ) { #ifdef USE_OLD_ALGO LastReferenceNumber++; #else LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); #endif aComponentsList[ii].m_NumRef = LastReferenceNumber; } Loading @@ -251,7 +368,11 @@ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aU if( aComponentsList[ii].m_IsNew ) { #ifdef USE_OLD_ALGO LastReferenceNumber++; #else LastReferenceNumber = CreateFirstFreeRefId( idList, minRefId ); #endif aComponentsList[ii].m_NumRef = LastReferenceNumber; if( !aComponentsList[ii].IsPartsLocked() ) Loading Loading @@ -307,33 +428,6 @@ static void ComputeReferenceNumber( SCH_REFERENCE_LIST& aComponentsList, bool aU } /** * Search the last used (greatest) reference number in the component list * for the prefix reference given by Objet * The component list must be sorted. * * @param aObjet = reference item ( aComponentsList[aObjet].m_TextRef is * the search pattern) * @param aComponentsList = list of items */ int GetLastReferenceNumber( int aObjet,SCH_REFERENCE_LIST& aComponentsList ) { int LastNumber = 0; for( unsigned ii = 0; ii < aComponentsList.GetCount(); ii++ ) { /* New identifier. */ if( aComponentsList[aObjet].CompareRef( aComponentsList[ii] ) != 0 ) continue; if( LastNumber < aComponentsList[ii].m_NumRef ) LastNumber = aComponentsList[ii].m_NumRef; } return LastNumber; } /** * Search in the sorted list of components, for a given component an other * component with the same reference and a given part unit. Mainly used to Loading Loading @@ -391,7 +485,7 @@ static int ExistUnit( int aObjet, int Unit, SCH_REFERENCE_LIST& aComponentsList */ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOnly ) { int error; int error = 0; wxString Buff; wxString msg, cmpref; Loading @@ -410,18 +504,15 @@ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOn /* Break full components reference in name (prefix) and number: example: * IC1 become IC, and 1 */ BreakReference( ComponentsList ); ComponentsList.SplitReferences(); /* count not yet annotated items */ error = 0; int imax = ComponentsList.GetCount() - 1; for( int ii = 0; ii < imax; ii++ ) /* count not yet annotated items or annottaion error*/ for( unsigned ii = 0; ii < ComponentsList.GetCount(); ii++ ) { msg.Empty(); Buff.Empty(); if( ComponentsList[ii].m_IsNew ) if( ComponentsList[ii].m_IsNew ) // Not yet annotated { if( ComponentsList[ii].m_NumRef >= 0 ) Buff << ComponentsList[ii].m_NumRef; Loading @@ -446,7 +537,8 @@ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOn break; } // Annotate error // Annotate error if unit selected does not exist ( i.e. > number of parts ) // Can happen if a component has changed in a lib, after a previous annotation if( MAX( ComponentsList[ii].m_Entry->GetPartCount(), 1 ) < ComponentsList[ii].m_Unit ) { if( ComponentsList[ii].m_NumRef >= 0 ) Loading Loading @@ -477,6 +569,7 @@ int SCH_EDIT_FRAME::CheckAnnotate( wxArrayString* aMessageList, bool aOneSheetOn return error; // count the duplicated elements (if all are annotated) int imax = ComponentsList.GetCount() - 1; for( int ii = 0; (ii < imax) && (error < 4); ii++ ) { msg.Empty(); Loading
eeschema/netlist.h +33 −0 Original line number Diff line number Diff line Loading @@ -226,6 +226,39 @@ public: * When annotating, some or all components are not annotated, * i.e. ref is only U or R, with no number. */ /** * Function SplitReferences * attempts to split all reference designators into a name (U) and number (1). If the * last character is '?' or not a digit, the reference is tagged as not annotated. * For components with multiple parts per package that are not already annotated, set * m_Unit to a max value (0x7FFFFFFF). * @see SCH_REFERENCE::Split() */ void SplitReferences() { for( unsigned ii = 0; ii < GetCount(); ii++ ) componentFlatList[ii].Split(); } /** * function UpdateAnnotation * Update the reference components for the schematic project (or the current sheet) * Note: this function does not calculate the reference numbers * stored in m_NumRef * So, it must be called after calcultaion of new reference numbers * @see SCH_REFERENCE::Annotate() */ void UpdateAnnotation() { /* update the reference numbers */ for( unsigned ii = 0; ii < GetCount(); ii++ ) { componentFlatList[ii].Annotate(); } } /** * Function SortCmpByXCoordinate * sort the flat list by X coordinates. Loading
new/sch_dir_lib_source.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -459,8 +459,12 @@ void DIR_LIB_SOURCE::GetRevisions( STRINGS* aResults, const STRING& aPartName ) PN_ITER it = partnames.upper_bound( partName +'/' ); PN_ITER end = partnames.lower_bound( partName + char( '/' +1 ) ); while( it != end ) aResults->push_back( *it++ ); for( ; it != end; ++it ) { const char* rev = endsWithRev( *it ); assert( rev ); aResults->push_back( it->substr( rev - it->c_str() ) ); } } } Loading
new/sch_lib.cpp +63 −31 Original line number Diff line number Diff line Loading @@ -39,13 +39,12 @@ /* The LIB part cache consist of a std::map of partnames without revisions at the top level. Each top level map entry can point to another std::map which it owns and holds all the revisions for that part name. At any point in the tree, there can be NULL pointers which allow for lazy loading, including the very top most root pointer itself, which is PARTS* parts. We use the key to hold the partName at one level, and revision at the deeper nested level, and that key information may not be present within right hand side of the map tuple. The LIB part cache consists of a std::map of partnames without revisions at the top level. Each top level map entry can point to another std::map which it owns and which holds all the revisions for that part name. At any point in the tree, there can be NULL pointers which allow for lazy loading, including the very top most root pointer itself, which is PARTS* parts. We use the key to hold the partName at one level, and revision at the deeper nested level. 1) Only things which are asked for are done. 2) Anything we learn we remember. Loading @@ -54,10 +53,31 @@ right hand side of the map tuple. namespace SCH { class PART_REVS : public std::map< STRING, PART* > /** * Struct LTREV * is for PART_REVS, and provides a custom way to compare rev STRINGs. * Namely, the revN[N..] string if present, is collated according to a * 'higher revision first'. */ struct LTREV { bool operator() ( const STRING& s1, const STRING& s2 ) const { // @todo provide an integer sort on revN.. strings here. return RevCmp( s1.c_str(), s2.c_str() ) < 0; } }; /** * Class PART_REVS * contains the collection of revisions for a particular part name, in the * form of cached PARTs. The tuple consists of a rev string and a PART pointer. * The rev string is like "rev1", the PART pointer will be NULL until the PART * gets loaded, lazily. */ class PART_REVS : public std::map< STRING, PART*, LTREV > { public: ~PART_REVS() { Loading @@ -68,6 +88,15 @@ public: } }; /** * Class PARTS * contains the collection of PART_REVS for all PARTs in the lib. * The tuple consists of a part name and a PART_REVS pointer. * The part name does not have the revision attached (of course this is understood * by definition of "part name"). The PART_REVS pointer will be NULL until a client * askes about the revisions for a part name, so the loading is done lazily. */ class PARTS : public std::map< STRING, PART_REVS* > { public: Loading Loading @@ -126,7 +155,7 @@ LIB::~LIB() } const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR ) const PART* LIB::lookupPart( const LPID& aLPID ) throw( IO_ERROR ) { if( !parts ) { Loading @@ -137,7 +166,7 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR ) // insert a PART_REVS for each part name for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it ) { // D(printf("findPart:%s\n", it->c_str() );) D(printf("lookupPart:%s\n", it->c_str() );) (*parts)[*it] = new PART_REVS; } } Loading @@ -152,44 +181,46 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR ) // if the key for parts has no aLPID.GetPartName() the part is not in this lib if( revs ) { if( revs->size() == 0 ) if( revs->size() == 0 ) // assume rev list has not been loaded yet { // load all the revisions for this part. source->GetRevisions( &vfetch, aLPID.GetPartName() ); // creat a PART_REV entry for revision, but leave the PART* NULL // create a PART_REV entry for each revision, but leave the PART* NULL for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it ) { // D(printf("findPartRev:%s\n", it->c_str() );) D(printf("lookupPartRev:%s\n", it->c_str() );) (*revs)[*it] = 0; } } PART_REVS::iterator result = revs->find( aLPID.GetPartNameAndRev() ); PART_REVS::iterator rev; if( result != revs->end() ) // If caller did not say what revision, find the highest numbered one and return that. if( !aLPID.GetRevision().size() && revs->size() ) { if( !result->second ) // the PART has never been loaded before rev = revs->begin(); // sort order has highest rev first if( !rev->second ) // the PART has never been instantiated before { result->second = new PART( this, aLPID.GetPartNameAndRev() ); rev->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), rev->first ) ); } return result->second; D(printf("lookupPartLatestRev:%s\n", rev->second->partNameAndRev.c_str() );) return rev->second; } // If caller did not say what revision, find the highest numbered one and return that. // Otherwise he knew what he wanted specifically, and we do not have it. if( !aLPID.GetRevision().size() && revs->size() ) else { result = revs->begin(); // sort order has highest rev first rev = revs->find( aLPID.GetRevision() ); if( !result->second ) // the PART has never been loaded before if( rev != revs->end() ) { if( !rev->second ) // the PART has never been instantiated before { result->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), result->first ) ); rev->second = new PART( this, aLPID.GetPartNameAndRev() ); } return rev->second; } return result->second; } } Loading @@ -199,7 +230,7 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR ) PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR ) { PART* part = (PART*) findPart( aLPID ); PART* part = (PART*) lookupPart( aLPID ); if( !part ) // part does not exist in this lib { Loading @@ -221,7 +252,8 @@ PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR printf( "\n" ); #endif SWEET_LEXER sw( part->body, wxString::FromUTF8("body") /* @todo have ReadPart give better source */ ); // @todo consider changing ReadPart to return a "source" SWEET_LEXER sw( part->body, wxString::FromUTF8( aLPID.Format().c_str() ) ); part->Parse( &sw, aLibTable ); } Loading