From aba0fa7bf89097ab65e38e64257c51edc86e3365 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Mon, 6 Apr 2020 14:06:57 +0100 Subject: [PATCH] Allow cross-referencing text substitutions. --- eeschema/dialogs/dialog_edit_label.cpp | 128 +++++++++++++++++++++- eeschema/sch_component.cpp | 47 ++++++++ eeschema/sch_component.h | 6 + eeschema/sch_field.cpp | 107 +++--------------- eeschema/sch_field.h | 2 +- eeschema/sch_sheet.cpp | 24 ++++ eeschema/sch_sheet.h | 6 + eeschema/sch_text.cpp | 52 ++++++--- eeschema/sch_text.h | 2 +- include/eda_text.h | 7 +- pcbnew/class_module.cpp | 22 ++++ pcbnew/class_module.h | 6 + pcbnew/class_pcb_text.cpp | 31 +++++- pcbnew/class_pcb_text.h | 2 +- pcbnew/class_text_mod.cpp | 41 +++---- pcbnew/class_text_mod.h | 2 +- pcbnew/dialogs/dialog_text_properties.cpp | 98 ++++++++++++++++- pcbnew/dialogs/dialog_text_properties.h | 3 + 18 files changed, 432 insertions(+), 154 deletions(-) diff --git a/eeschema/dialogs/dialog_edit_label.cpp b/eeschema/dialogs/dialog_edit_label.cpp index 901ecd7bf1..3ede422a21 100644 --- a/eeschema/dialogs/dialog_edit_label.cpp +++ b/eeschema/dialogs/dialog_edit_label.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -180,15 +182,126 @@ DIALOG_LABEL_EDITOR::~DIALOG_LABEL_EDITOR() } +wxString convertKIIDsToReferences( const wxString& aSource ) +{ + wxString newbuf; + size_t sourceLen = aSource.length(); + + for( size_t i = 0; i < sourceLen; ++i ) + { + if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' ) + { + wxString token; + bool isCrossRef = false; + + for( i = i + 2; i < sourceLen; ++i ) + { + if( aSource[i] == '}' ) + break; + + if( aSource[i] == ':' ) + isCrossRef = true; + + token.append( aSource[i] ); + } + + if( isCrossRef ) + { + SCH_SHEET_LIST sheetList( g_RootSheet ); + wxArrayString parts = wxSplit( token, ':' ); + SCH_SHEET_PATH refSheetPath; + SCH_ITEM* refItem = sheetList.GetItem( KIID( parts[0] ), &refSheetPath ); + + if( refItem && refItem->Type() == SCH_COMPONENT_T ) + { + SCH_COMPONENT* refComponent = static_cast( refItem ); + token = refComponent->GetRef( &refSheetPath, true ) + ":" + parts[1]; + } + } + + newbuf.append( "${" + token + "}" ); + } + else + { + newbuf.append( aSource[i] ); + } + } + + return newbuf; +} + + +wxString convertReferencesToKIIDs( const wxString& aSource ) +{ + wxString newbuf; + size_t sourceLen = aSource.length(); + + for( size_t i = 0; i < sourceLen; ++i ) + { + if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' ) + { + wxString token; + bool isCrossRef = false; + + for( i = i + 2; i < sourceLen; ++i ) + { + if( aSource[i] == '}' ) + break; + + if( aSource[i] == ':' ) + isCrossRef = true; + + token.append( aSource[i] ); + } + + if( isCrossRef ) + { + SCH_SHEET_LIST sheets( g_RootSheet ); + wxArrayString parts = wxSplit( token, ':' ); + SCH_REFERENCE_LIST references; + + sheets.GetComponents( references ); + + for( size_t jj = 0; jj < references.GetCount(); jj++ ) + { + SCH_COMPONENT* refComponent = references[ jj ].GetComp(); + wxString ref = refComponent->GetRef( &references[ jj ].GetSheetPath() ); + + if( ref == parts[0] ) + { + token = refComponent->m_Uuid.AsString() + ":" + parts[1]; + break; + } + } + } + + newbuf.append( "${" + token + "}" ); + } + else + { + newbuf.append( aSource[i] ); + } + } + + return newbuf; +} + + bool DIALOG_LABEL_EDITOR::TransferDataToWindow() { if( !wxDialog::TransferDataToWindow() ) return false; - if( m_activeTextEntry ) - m_activeTextEntry->SetValue( UnescapeString( m_CurrentText->GetText() ) ); + if( m_CurrentText->Type() == SCH_TEXT_T ) + { + // show text variable cross-references in a human-readable format + m_valueMultiLine->SetValue( convertKIIDsToReferences( m_CurrentText->GetText() ) ); + } else - m_valueMultiLine->SetValue( UnescapeString( m_CurrentText->GetText() ) ); + { + // show control characters in a human-readable format + m_activeTextEntry->SetValue( UnescapeString( m_CurrentText->GetText() ) ); + } if( m_valueCombo->IsShown() ) { @@ -308,11 +421,16 @@ bool DIALOG_LABEL_EDITOR::TransferDataFromWindow() m_Parent->GetCanvas()->Refresh(); - // Escape string only if is is a label. For a simple graphic text do not change anything if( m_CurrentText->Type() == SCH_TEXT_T ) - text = m_valueMultiLine->GetValue(); + { + // convert any text variable cross-references to their UUIDs + text = convertReferencesToKIIDs( m_valueMultiLine->GetValue() ); + } else + { + // labels need escaping text = EscapeString( m_activeTextEntry->GetValue(), CTX_NETNAME ); + } if( !text.IsEmpty() ) m_CurrentText->SetText( text ); diff --git a/eeschema/sch_component.cpp b/eeschema/sch_component.cpp index 16ac2495bd..9c69d5383c 100644 --- a/eeschema/sch_component.cpp +++ b/eeschema/sch_component.cpp @@ -931,6 +931,53 @@ void SCH_COMPONENT::SwapData( SCH_ITEM* aItem ) } +bool SCH_COMPONENT::ResolveTextVar( wxString* token, int aDepth ) const +{ + for( int i = 0; i < MANDATORY_FIELDS; ++i ) + { + if( token->IsSameAs( m_Fields[ i ].GetCanonicalName().Upper() ) ) + { + *token = m_Fields[ i ].GetShownText( aDepth + 1 ); + return true; + } + } + + for( size_t i = MANDATORY_FIELDS; i < m_Fields.size(); ++i ) + { + if( token->IsSameAs( m_Fields[ i ].GetName() ) + || token->IsSameAs( m_Fields[ i ].GetName().Upper() ) ) + { + *token = m_Fields[ i ].GetShownText( aDepth + 1 ); + return true; + } + } + + if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) ) + { + const SCH_FIELD& field = m_Fields[ FOOTPRINT ]; + wxArrayString parts = wxSplit( field.GetText(), ':' ); + + *token = parts[ 0 ]; + return true; + } + else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) ) + { + const SCH_FIELD& field = m_Fields[ FOOTPRINT ]; + wxArrayString parts = wxSplit( field.GetText(), ':' ); + + *token = parts[ std::min( 1, (int) parts.size() - 1 ) ]; + return true; + } + else if( token->IsSameAs( wxT( "UNIT" ) ) ) + { + *token = LIB_PART::SubReference( GetUnit() ); + return true; + } + + return false; +} + + void SCH_COMPONENT::ClearAnnotation( SCH_SHEET_PATH* aSheetPath ) { // Build a reference with no annotation, diff --git a/eeschema/sch_component.h b/eeschema/sch_component.h index 59602a94c8..0461245370 100644 --- a/eeschema/sch_component.h +++ b/eeschema/sch_component.h @@ -305,6 +305,12 @@ public: */ int GetOrientation(); + /** + * Resolve any references to system tokens supported by the component. + * @param aDepth a counter to limit recursion and circular references. + */ + bool ResolveTextVar( wxString* token, int aDepth = 0 ) const; + void GetMsgPanelInfo( EDA_UNITS aUnits, std::vector& aList ) override; /** diff --git a/eeschema/sch_field.cpp b/eeschema/sch_field.cpp index 3de4fb7283..e5ef8898c9 100644 --- a/eeschema/sch_field.cpp +++ b/eeschema/sch_field.cpp @@ -72,103 +72,20 @@ EDA_ITEM* SCH_FIELD::Clone() const } -wxString SCH_FIELD::GetShownText() const +wxString SCH_FIELD::GetShownText( int aDepth ) const { std::function symbolResolver = - [this]( wxString* token ) -> bool + [&]( wxString* token ) -> bool { SCH_COMPONENT* component = static_cast( m_Parent ); - std::vector& fields = component->GetFields(); - - for( int i = 0; i < MANDATORY_FIELDS; ++i ) - { - if( token->IsSameAs( fields[ i ].GetCanonicalName().Upper() ) ) - { - // silently drop recursive references - if( &fields[ i ] == this ) - *token = wxEmptyString; - else - *token = fields[ i ].GetShownText(); - - return true; - } - } - - for( size_t i = MANDATORY_FIELDS; i < fields.size(); ++i ) - { - if( token->IsSameAs( fields[ i ].GetName() ) - || token->IsSameAs( fields[ i ].GetName().Upper() ) ) - { - // silently drop recursive references - if( &fields[ i ] == this ) - *token = wxEmptyString; - else - *token = fields[ i ].GetShownText(); - - return true; - } - } - - if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) ) - { - SCH_FIELD& f = component->GetFields()[ FOOTPRINT ]; - wxArrayString parts = wxSplit( f.GetText(), ':' ); - - *token = parts[ 0 ]; - return true; - } - else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) ) - { - SCH_FIELD& f = component->GetFields()[ FOOTPRINT ]; - wxArrayString parts = wxSplit( f.GetText(), ':' ); - - *token = parts[ std::min( 1, (int) parts.size() - 1 ) ]; - return true; - } - else if( token->IsSameAs( wxT( "UNIT" ) ) ) - { - *token = LIB_PART::SubReference( component->GetUnit() ); - return true; - } - - return false; + return component->ResolveTextVar( token, aDepth + 1 ); }; std::function sheetResolver = [&]( wxString* token ) -> bool { SCH_SHEET* sheet = static_cast( m_Parent ); - std::vector& fields = sheet->GetFields(); - - for( int i = 0; i < SHEET_MANDATORY_FIELDS; ++i ) - { - if( token->IsSameAs( fields[ i ].GetCanonicalName().Upper() ) ) - { - // silently drop recursive references - if( &fields[ i ] == this ) - *token = wxEmptyString; - else - *token = fields[ i ].GetShownText(); - - return true; - } - } - - for( size_t i = SHEET_MANDATORY_FIELDS; i < fields.size(); ++i ) - { - if( token->IsSameAs( fields[ i ].GetName() ) ) - { - // silently drop recursive references - if( &fields[ i ] == this ) - *token = wxEmptyString; - else - *token = fields[ i ].GetShownText(); - - return true; - } - } - - return false; + return sheet->ResolveTextVar( token, aDepth + 1 ); }; PROJECT* project = nullptr; @@ -177,10 +94,15 @@ wxString SCH_FIELD::GetShownText() const if( g_RootSheet && g_RootSheet->GetScreen() ) project = &g_RootSheet->GetScreen()->Kiway().Prj(); - if( m_Parent && m_Parent->Type() == SCH_COMPONENT_T ) - text = ExpandTextVars( text, &symbolResolver, project ); - else if( m_Parent && m_Parent->Type() == SCH_SHEET_T ) - text = ExpandTextVars( text, &sheetResolver, project ); + if( aDepth < 10 ) + { + if( m_Parent && m_Parent->Type() == SCH_COMPONENT_T ) + text = ExpandTextVars( text, &symbolResolver, project ); + else if( m_Parent && m_Parent->Type() == SCH_SHEET_T ) + text = ExpandTextVars( text, &sheetResolver, project ); + else + text = ExpandTextVars( text, nullptr, project ); + } // WARNING: the IDs of FIELDS and SHEETS overlap, so one must check *both* the // id and the parent's type. @@ -197,8 +119,7 @@ wxString SCH_FIELD::GetShownText() const text << LIB_PART::SubReference( component->GetUnit() ); } } - - if( m_Parent && m_Parent->Type() == SCH_SHEET_T ) + else if( m_Parent && m_Parent->Type() == SCH_SHEET_T ) { if( m_id == SHEETFILENAME ) text = _( "File: " ) + text; diff --git a/eeschema/sch_field.h b/eeschema/sch_field.h index f747a78d56..a199a0a2dc 100644 --- a/eeschema/sch_field.h +++ b/eeschema/sch_field.h @@ -115,7 +115,7 @@ public: void SetId( int aId ) { m_id = aId; } - wxString GetShownText() const override; + wxString GetShownText( int aDepth = 0 ) const override; const EDA_RECT GetBoundingBox() const override; diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp index 54dbfec886..67602ef458 100644 --- a/eeschema/sch_sheet.cpp +++ b/eeschema/sch_sheet.cpp @@ -190,6 +190,30 @@ SCH_SHEET* SCH_SHEET::GetRootSheet() } +bool SCH_SHEET::ResolveTextVar( wxString* token, int aDepth ) const +{ + for( int i = 0; i < SHEET_MANDATORY_FIELDS; ++i ) + { + if( token->IsSameAs( m_fields[i].GetCanonicalName().Upper() ) ) + { + *token = m_fields[i].GetShownText( aDepth + 1 ); + return true; + } + } + + for( size_t i = SHEET_MANDATORY_FIELDS; i < m_fields.size(); ++i ) + { + if( token->IsSameAs( m_fields[i].GetName() ) ) + { + *token = m_fields[i].GetShownText( aDepth + 1 ); + return true; + } + } + + return false; +} + + bool SCH_SHEET::UsesDefaultStroke() const { return m_borderWidth == 0 && m_borderColor == COLOR4D::UNSPECIFIED; diff --git a/eeschema/sch_sheet.h b/eeschema/sch_sheet.h index 295aa94b8a..2400b88de4 100644 --- a/eeschema/sch_sheet.h +++ b/eeschema/sch_sheet.h @@ -336,6 +336,12 @@ public: */ int GetScreenCount() const; + /** + * Resolve any references to system tokens supported by the sheet. + * @param aDepth a counter to limit recursion and circular references. + */ + bool ResolveTextVar( wxString* token, int aDepth = 0 ) const; + void GetMsgPanelInfo( EDA_UNITS aUnits, std::vector& aList ) override; /* there is no member for orientation in sch_sheet, to preserve file diff --git a/eeschema/sch_text.cpp b/eeschema/sch_text.cpp index e17313cbc4..4f621846c6 100644 --- a/eeschema/sch_text.cpp +++ b/eeschema/sch_text.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -450,10 +451,10 @@ wxString getElectricalTypeLabel( PINSHEETLABEL_SHAPE aType ) } -wxString SCH_TEXT::GetShownText() const +wxString SCH_TEXT::GetShownText( int aDepth ) const { std::function textResolver = - [this]( wxString* token ) -> bool + [&]( wxString* token ) -> bool { if( ( Type() == SCH_GLOBAL_LABEL_T || Type() == SCH_HIER_LABEL_T @@ -467,23 +468,39 @@ wxString SCH_TEXT::GetShownText() const if( Type() == SCH_SHEET_PIN_T && m_Parent ) { SCH_SHEET* sheet = static_cast( m_Parent ); - std::vector& fields = sheet->GetFields(); - for( int i = 0; i < SHEET_MANDATORY_FIELDS; ++i ) + if( sheet->ResolveTextVar( token, aDepth ) ) + return true; + } + + if( Type() == SCH_TEXT_T ) + { + if( token->Contains( ':' ) ) { - if( token->IsSameAs( fields[i].GetCanonicalName().Upper() ) ) + SCH_SHEET_LIST sheetList( g_RootSheet ); + wxArrayString parts = wxSplit( *token, ':' ); + SCH_SHEET_PATH dummy; + SCH_ITEM* refItem = sheetList.GetItem( KIID( parts[0] ), &dummy ); + + if( refItem && refItem->Type() == SCH_COMPONENT_T ) { - *token = fields[i].GetShownText(); - return true; + SCH_COMPONENT* refComponent = static_cast( refItem ); + + if( refComponent->ResolveTextVar( &parts[1], aDepth + 1 ) ) + { + *token = parts[1]; + return true; + } } - } - - for( size_t i = SHEET_MANDATORY_FIELDS; i < fields.size(); ++i ) - { - if( token->IsSameAs( fields[i].GetName() ) ) + else if( refItem && refItem->Type() == SCH_SHEET_T ) { - *token = fields[i].GetShownText(); - return true; + SCH_SHEET* refSheet = static_cast( refItem ); + + if( refSheet->ResolveTextVar( &parts[1], aDepth + 1 ) ) + { + *token = parts[1]; + return true; + } } } } @@ -496,7 +513,12 @@ wxString SCH_TEXT::GetShownText() const if( g_RootSheet && g_RootSheet->GetScreen() ) project = &g_RootSheet->GetScreen()->Kiway().Prj(); - return ExpandTextVars( EDA_TEXT::GetShownText(), &textResolver, project ); + wxString text = EDA_TEXT::GetShownText( aDepth ); + + if( aDepth < 10 ) + text = ExpandTextVars( text, &textResolver, project ); + + return text; } diff --git a/eeschema/sch_text.h b/eeschema/sch_text.h index 9bbb4fcdf1..04ae79f609 100644 --- a/eeschema/sch_text.h +++ b/eeschema/sch_text.h @@ -207,7 +207,7 @@ public: return wxT( "SCH_TEXT" ); } - wxString GetShownText() const override; + wxString GetShownText( int aDepth = 0 ) const override; /** * Increment the label text, if it ends with a number. diff --git a/include/eda_text.h b/include/eda_text.h index 82d46b005d..9a60cbd12f 100644 --- a/include/eda_text.h +++ b/include/eda_text.h @@ -123,10 +123,11 @@ public: virtual const wxString& GetText() const { return m_text; } /** - * Return the string actually shown after processing of the base - * text. Default is no processing + * Return the string actually shown after processing of the base text. + * @aParam aDepth is used to prevent infinite recusions and loops when expanding + * text variables. */ - virtual wxString GetShownText() const { return m_shown_text; } + virtual wxString GetShownText( int aDepth = 0 ) const { return m_shown_text; } /** * Returns a shortened version (max 15 characters) of the shown text diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 6c3be99527..2654fc0bf4 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -260,6 +260,28 @@ MODULE& MODULE::operator=( const MODULE& aOther ) } +bool MODULE::ResolveTextVar( wxString* token, int aDepth ) const +{ + if( token->IsSameAs( wxT( "REFERENCE" ) ) ) + { + *token = m_Reference->GetShownText( aDepth + 1 ); + return true; + } + else if( token->IsSameAs( wxT( "VALUE" ) ) ) + { + *token = m_Value->GetShownText( aDepth + 1 ); + return true; + } + else if( token->IsSameAs( wxT( "LAYER" ) ) ) + { + *token = GetLayerName(); + return true; + } + + return false; +} + + void MODULE::ClearAllNets() { // Force the ORPHANED dummy net info for all pads. diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index 5b15602a43..ede4268175 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -411,6 +411,12 @@ public: void TransformGraphicTextWithClearanceToPolygonSet( PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aError = ARC_HIGH_DEF ) const; + /** + * Resolve any references to system tokens supported by the component. + * @param aDepth a counter to limit recursion and circular references. + */ + bool ResolveTextVar( wxString* token, int aDepth = 0 ) const; + ///> @copydoc EDA_ITEM::GetMsgPanelInfo void GetMsgPanelInfo( EDA_UNITS aUnits, std::vector& aList ) override; diff --git a/pcbnew/class_pcb_text.cpp b/pcbnew/class_pcb_text.cpp index 803d985021..d548c4916e 100644 --- a/pcbnew/class_pcb_text.cpp +++ b/pcbnew/class_pcb_text.cpp @@ -61,13 +61,13 @@ TEXTE_PCB::~TEXTE_PCB() } -wxString TEXTE_PCB::GetShownText() const +wxString TEXTE_PCB::GetShownText( int aDepth ) const { - const BOARD* board = static_cast( GetParent() ); + BOARD* board = static_cast( GetParent() ); wxASSERT( board ); - std::function moduleResolver = - [ this ]( wxString* token ) -> bool + std::function pcbTextResolver = + [&]( wxString* token ) -> bool { if( token->IsSameAs( wxT( "LAYER" ) ) ) { @@ -75,10 +75,31 @@ wxString TEXTE_PCB::GetShownText() const return true; } + if( token->Contains( ':' ) ) + { + wxArrayString parts = wxSplit( *token, ':' ); + BOARD_ITEM* refItem = board->GetItem( KIID( parts[0] ) ); + + if( refItem && refItem->Type() == PCB_MODULE_T ) + { + MODULE* refModule = static_cast( refItem ); + + if( refModule->ResolveTextVar( &parts[1], aDepth + 1 ) ) + { + *token = parts[1]; + return true; + } + } + } return false; }; - return ExpandTextVars( EDA_TEXT::GetShownText(), &moduleResolver, board->GetProject() ); + wxString text = EDA_TEXT::GetShownText( aDepth ); + + if( aDepth < 10 ) + text = ExpandTextVars( text, &pcbTextResolver, board->GetProject() ); + + return text; } diff --git a/pcbnew/class_pcb_text.h b/pcbnew/class_pcb_text.h index d626ea59db..2399e4e744 100644 --- a/pcbnew/class_pcb_text.h +++ b/pcbnew/class_pcb_text.h @@ -53,7 +53,7 @@ public: return aItem && PCB_TEXT_T == aItem->Type(); } - wxString GetShownText() const override; + wxString GetShownText( int aDepth = 0 ) const override; bool Matches( wxFindReplaceData& aSearchData, void* aAuxData ) override { diff --git a/pcbnew/class_text_mod.cpp b/pcbnew/class_text_mod.cpp index c694f1b184..7f68ab84e9 100644 --- a/pcbnew/class_text_mod.cpp +++ b/pcbnew/class_text_mod.cpp @@ -488,38 +488,25 @@ unsigned int TEXTE_MODULE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const } -wxString TEXTE_MODULE::GetShownText() const +wxString TEXTE_MODULE::GetShownText( int aDepth ) const { const MODULE* module = static_cast( GetParent() ); - wxASSERT( module ); - - const BOARD* board = static_cast( module->GetParent() ); - wxASSERT( board ); + wxASSERT( module ); std::function moduleResolver = - [ this, module ]( wxString* token ) -> bool + [&]( wxString* token ) -> bool { - if( module ) - { - if( token->IsSameAs( wxT( "REFERENCE" ) ) ) - { - *token = module->GetReference(); - return true; - } - else if( token->IsSameAs( wxT( "VALUE" ) ) ) - { - *token = module->GetValue(); - return true; - } - else if( token->IsSameAs( wxT( "LAYER" ) ) ) - { - *token = GetLayerName(); - return true; - } - } - - return false; + return module && module->ResolveTextVar( token, aDepth ); }; - return ExpandTextVars( EDA_TEXT::GetShownText(), &moduleResolver, board->GetProject() ); + PROJECT* project = nullptr; + wxString text = EDA_TEXT::GetShownText( aDepth ); + + if( module && module->GetParent() ) + project = static_cast( module->GetParent() )->GetProject(); + + if( aDepth < 10 ) + text = ExpandTextVars( text, &moduleResolver, project ); + + return text; } diff --git a/pcbnew/class_text_mod.h b/pcbnew/class_text_mod.h index a4aaa72830..4536d540de 100644 --- a/pcbnew/class_text_mod.h +++ b/pcbnew/class_text_mod.h @@ -216,7 +216,7 @@ public: EDA_ITEM* Clone() const override; - virtual wxString GetShownText() const override; + virtual wxString GetShownText( int aDepth = 0 ) const override; virtual const BOX2I ViewBBox() const override; diff --git a/pcbnew/dialogs/dialog_text_properties.cpp b/pcbnew/dialogs/dialog_text_properties.cpp index 00f8403972..04d08e18bc 100644 --- a/pcbnew/dialogs/dialog_text_properties.cpp +++ b/pcbnew/dialogs/dialog_text_properties.cpp @@ -291,6 +291,99 @@ void DIALOG_TEXT_PROPERTIES::OnDimensionUnitsChange( wxCommandEvent& event ) } +wxString DIALOG_TEXT_PROPERTIES::convertKIIDsToReferences( const wxString& aSource ) +{ + wxString newbuf; + size_t sourceLen = aSource.length(); + + for( size_t i = 0; i < sourceLen; ++i ) + { + if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' ) + { + wxString token; + bool isCrossRef = false; + + for( i = i + 2; i < sourceLen; ++i ) + { + if( aSource[i] == '}' ) + break; + + if( aSource[i] == ':' ) + isCrossRef = true; + + token.append( aSource[i] ); + } + + if( isCrossRef ) + { + wxArrayString parts = wxSplit( token, ':' ); + BOARD_ITEM* refItem = m_Parent->GetBoard()->GetItem( KIID( parts[0] ) ); + + if( refItem && refItem->Type() == PCB_MODULE_T ) + token = static_cast( refItem )->GetReference() + ":" + parts[1]; + } + + newbuf.append( "${" + token + "}" ); + } + else + { + newbuf.append( aSource[i] ); + } + } + + return newbuf; +} + + +wxString DIALOG_TEXT_PROPERTIES::convertReferencesToKIIDs( const wxString& aSource ) +{ + wxString newbuf; + size_t sourceLen = aSource.length(); + + for( size_t i = 0; i < sourceLen; ++i ) + { + if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' ) + { + wxString token; + bool isCrossRef = false; + + for( i = i + 2; i < sourceLen; ++i ) + { + if( aSource[i] == '}' ) + break; + + if( aSource[i] == ':' ) + isCrossRef = true; + + token.append( aSource[i] ); + } + + if( isCrossRef ) + { + wxArrayString parts = wxSplit( token, ':' ); + + for( MODULE* mod : m_Parent->GetBoard()->Modules() ) + { + if( mod->GetReference().CmpNoCase( parts[0] ) == 0 ) + { + token = mod->m_Uuid.AsString() + ":" + parts[1]; + break; + } + } + } + + newbuf.append( "${" + token + "}" ); + } + else + { + newbuf.append( aSource[i] ); + } + } + + return newbuf; +} + + bool DIALOG_TEXT_PROPERTIES::TransferDataToWindow() { if( m_SingleLineText->IsShown() ) @@ -304,7 +397,7 @@ bool DIALOG_TEXT_PROPERTIES::TransferDataToWindow() } else if( m_MultiLineText->IsShown() ) { - m_MultiLineText->SetValue( m_edaText->GetText() ); + m_MultiLineText->SetValue( convertKIIDsToReferences( m_edaText->GetText() ) ); m_MultiLineText->SetSelection( -1, -1 ); } else if (m_DimensionText->IsShown() ) @@ -403,10 +496,11 @@ bool DIALOG_TEXT_PROPERTIES::TransferDataFromWindow() { if( !m_MultiLineText->GetValue().IsEmpty() ) { + wxString txt = convertReferencesToKIIDs( m_MultiLineText->GetValue() ); + // On Windows, a new line is coded as \r\n. // We use only \n in kicad files and in drawing routines. // so strip the \r char - wxString txt = m_MultiLineText->GetValue(); #ifdef __WINDOWS__ txt.Replace( "\r", "" ); #endif diff --git a/pcbnew/dialogs/dialog_text_properties.h b/pcbnew/dialogs/dialog_text_properties.h index 64a727f4de..f06038ac7a 100644 --- a/pcbnew/dialogs/dialog_text_properties.h +++ b/pcbnew/dialogs/dialog_text_properties.h @@ -60,6 +60,9 @@ private: wxFloatingPointValidator m_OrientValidator; double m_OrientValue; + wxString convertReferencesToKIIDs( const wxString& aSource ); + wxString convertKIIDsToReferences( const wxString& aSource ); + bool TransferDataToWindow() override; bool TransferDataFromWindow() override;