From 9ed19192de25125a36b0adf454c9442c8afe5360 Mon Sep 17 00:00:00 2001 From: Alex Shvartzkop Date: Sun, 15 Oct 2023 01:00:02 +0300 Subject: [PATCH] Improve editing values with {return} in text fields; Add hyperlink detection. --- common/lib_tree_model_adapter.cpp | 17 +++++++++------ common/string_utils.cpp | 21 +++++++++++++++++++ eeschema/dialogs/dialog_field_properties.cpp | 8 +++---- eeschema/fields_grid_table.cpp | 4 ++-- eeschema/generate_alias_info.cpp | 10 +++++++-- .../symbol_tree_synchronizing_adapter.cpp | 14 +++++++++---- include/string_utils.h | 13 ++++++++++++ .../dialog_footprint_properties_fp_editor.cpp | 4 ++-- pcbnew/fp_tree_synchronizing_adapter.cpp | 13 +++++++++--- pcbnew/generate_footprint_info.cpp | 14 +++++++++---- 10 files changed, 91 insertions(+), 27 deletions(-) diff --git a/common/lib_tree_model_adapter.cpp b/common/lib_tree_model_adapter.cpp index fe9153bba2..c134fa179d 100644 --- a/common/lib_tree_model_adapter.cpp +++ b/common/lib_tree_model_adapter.cpp @@ -433,7 +433,7 @@ void LIB_TREE_MODEL_ADAPTER::FinishTreeInitialization() for( ; idx < m_columns.size() - 1; idx++ ) { wxASSERT( m_colIdxMap.count( idx ) ); - + col = m_columns[idx]; header = m_colIdxMap[idx]; @@ -537,14 +537,15 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant, LIB_TREE_NODE* node = ToNode( aItem ); wxCHECK( node, /* void */ ); + wxString valueStr; switch( aCol ) { case NAME_COL: if( node->m_Pinned ) - aVariant = GetPinningSymbol() + UnescapeString( node->m_Name ); + valueStr = GetPinningSymbol() + UnescapeString( node->m_Name ); else - aVariant = UnescapeString( node->m_Name ); + valueStr = UnescapeString( node->m_Name ); break; @@ -554,15 +555,19 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant, const wxString& key = m_colIdxMap.at( aCol ); if( node->m_Fields.count( key ) ) - aVariant = node->m_Fields.at( key ); + valueStr = UnescapeString( node->m_Fields.at( key ) ); else if( key == wxT( "Description" ) ) - aVariant = node->m_Desc; + valueStr = UnescapeString( node->m_Desc ); else - aVariant = wxEmptyString; + valueStr = wxEmptyString; } break; } + + valueStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks + + aVariant = valueStr; } diff --git a/common/string_utils.cpp b/common/string_utils.cpp index 7227c3bf0c..3ea2dad4cc 100644 --- a/common/string_utils.cpp +++ b/common/string_utils.cpp @@ -33,6 +33,7 @@ #include // StrPrintf #include #include +#include /** @@ -548,6 +549,26 @@ wxString UnescapeHTML( const wxString& aString ) } +wxString RemoveHTMLTags( const wxString& aInput ) +{ + wxString str = aInput; + wxRegEx( wxS( "<[^>]*>" ) ).ReplaceAll( &str, wxEmptyString ); + + return str; +} + + +wxString LinkifyHTML( wxString aStr ) +{ + wxRegEx regex( wxS( "\\b(https?|ftp|file)://([-\\w+&@#/%?=~|!:,.;]*[^.<>\\s\u00b6])" ), + wxRE_ICASE ); + + regex.ReplaceAll( &aStr, "\\0" ); + + return aStr; +} + + bool NoPrintableChars( const wxString& aString ) { wxString tmp = aString; diff --git a/eeschema/dialogs/dialog_field_properties.cpp b/eeschema/dialogs/dialog_field_properties.cpp index ebe923cdb3..dfc745af88 100644 --- a/eeschema/dialogs/dialog_field_properties.cpp +++ b/eeschema/dialogs/dialog_field_properties.cpp @@ -302,11 +302,11 @@ bool DIALOG_FIELD_PROPERTIES::TransferDataToWindow() { if( m_TextCtrl->IsShown() ) { - m_TextCtrl->SetValue( m_text ); + m_TextCtrl->SetValue( EscapeString( m_text, CTX_LINE ) ); } else if( m_StyledTextCtrl->IsShown() ) { - m_StyledTextCtrl->SetValue( m_text ); + m_StyledTextCtrl->SetValue( EscapeString( m_text, CTX_LINE ) ); m_StyledTextCtrl->EmptyUndoBuffer(); } @@ -349,9 +349,9 @@ bool DIALOG_FIELD_PROPERTIES::TransferDataToWindow() bool DIALOG_FIELD_PROPERTIES::TransferDataFromWindow() { if( m_TextCtrl->IsShown() ) - m_text = m_TextCtrl->GetValue(); + m_text = UnescapeString( m_TextCtrl->GetValue() ); else if( m_StyledTextCtrl->IsShown() ) - m_text = m_StyledTextCtrl->GetValue(); + m_text = UnescapeString( m_StyledTextCtrl->GetValue() ); if( m_fieldId == REFERENCE_FIELD ) { diff --git a/eeschema/fields_grid_table.cpp b/eeschema/fields_grid_table.cpp index 8bea0bc6db..7ff3a8b647 100644 --- a/eeschema/fields_grid_table.cpp +++ b/eeschema/fields_grid_table.cpp @@ -561,7 +561,7 @@ wxString FIELDS_GRID_TABLE::GetValue( int aRow, int aCol ) } case FDC_VALUE: - return UnescapeString( field.GetText() ); + return EscapeString( UnescapeString( field.GetText() ), CTX_LINE ); case FDC_SHOWN: return StringFromBool( field.IsVisible() ); @@ -696,7 +696,7 @@ void FIELDS_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue value = EscapeString( value, CTX_LIBID ); } - field.SetText( value ); + field.SetText( UnescapeString( value ) ); break; } diff --git a/eeschema/generate_alias_info.cpp b/eeschema/generate_alias_info.cpp index d9831c7fe6..cb2e6ffef6 100644 --- a/eeschema/generate_alias_info.cpp +++ b/eeschema/generate_alias_info.cpp @@ -138,9 +138,15 @@ protected: void SetHtmlDesc() { - wxString raw_desc = m_symbol->GetDescription(); + wxString esc_desc = EscapeHTML( UnescapeString( m_symbol->GetDescription() ) ); - m_html.Replace( wxS( "__DESC__" ), wxString::Format( DescFormat, EscapeHTML( raw_desc ) ) ); + // Add line breaks + esc_desc.Replace( wxS( "\n" ), wxS( "
" ) ); + + // Add links + esc_desc = LinkifyHTML( esc_desc ); + + m_html.Replace( wxS( "__DESC__" ), wxString::Format( DescFormat, esc_desc ) ); } diff --git a/eeschema/symbol_tree_synchronizing_adapter.cpp b/eeschema/symbol_tree_synchronizing_adapter.cpp index ebab724ada..b254eb17cd 100644 --- a/eeschema/symbol_tree_synchronizing_adapter.cpp +++ b/eeschema/symbol_tree_synchronizing_adapter.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 CERN - * Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2019-2023 KiCad Developers, see AUTHORS.txt for contributors. * @author Maciej Suminski * * This program is free software; you can redistribute it and/or @@ -279,12 +279,18 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataVie node->m_Desc = m_frame->GetCurSymbol()->GetDescription(); } + wxString valueStr; + if( node->m_Fields.count( key ) ) - aVariant = node->m_Fields.at( key ); + valueStr = node->m_Fields.at( key ); else if( key == wxT( "Description" ) ) - aVariant = node->m_Desc; + valueStr = node->m_Desc; else - aVariant = wxEmptyString; + valueStr = wxEmptyString; + + valueStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks + + aVariant = valueStr; } break; } diff --git a/include/string_utils.h b/include/string_utils.h index ae1ce6e9bc..d3220dbc9a 100644 --- a/include/string_utils.h +++ b/include/string_utils.h @@ -129,6 +129,19 @@ KICOMMON_API wxString EscapeHTML( const wxString& aString ); */ KICOMMON_API wxString UnescapeHTML( const wxString& aString ); +/** + * Removes HTML tags from a string. + * + * Do not use for filtering potentially malicious inputs and rendering as HTML + * without escaping. + */ +KICOMMON_API wxString RemoveHTMLTags( const wxString& aInput ); + +/** + * Wraps links in HTML tags. + */ +KICOMMON_API wxString LinkifyHTML( wxString aStr ); + /** * Read one line line from \a aFile. * diff --git a/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp b/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp index 87bd9510fe..0f50c25495 100644 --- a/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp +++ b/pcbnew/dialogs/dialog_footprint_properties_fp_editor.cpp @@ -254,7 +254,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow() m_FootprintNameCtrl->ChangeValue( footprintName ); - m_DocCtrl->SetValue( m_footprint->GetLibDescription() ); + m_DocCtrl->SetValue( EscapeString( m_footprint->GetLibDescription(), CTX_LINE ) ); m_KeywordCtrl->SetValue( m_footprint->GetKeywords() ); if( !wxDialog::TransferDataToWindow() ) @@ -492,7 +492,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow() fpID.SetLibItemName( m_FootprintNameCtrl->GetValue() ); m_footprint->SetFPID( fpID ); - m_footprint->SetLibDescription( m_DocCtrl->GetValue() ); + m_footprint->SetLibDescription( UnescapeString( m_DocCtrl->GetValue() ) ); m_footprint->SetKeywords( m_KeywordCtrl->GetValue() ); // Update fields diff --git a/pcbnew/fp_tree_synchronizing_adapter.cpp b/pcbnew/fp_tree_synchronizing_adapter.cpp index 7b5ec24774..c356ef20a6 100644 --- a/pcbnew/fp_tree_synchronizing_adapter.cpp +++ b/pcbnew/fp_tree_synchronizing_adapter.cpp @@ -198,6 +198,7 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte switch( aCol ) { case NAME_COL: + { if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() ) { // Do not use GetLoadedFPID(); it returns m_footprintNameWhenLoaded. @@ -220,8 +221,10 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte } break; + } case DESC_COL: + { if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() ) { node->m_Desc = m_frame->GetBoard()->GetFirstFootprint()->GetLibDescription(); @@ -241,10 +244,14 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte } } - aVariant = node->m_Desc; - break; + wxString descStr = UnescapeString( node->m_Desc ); + descStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks - default: // column == -1 is used for default Compare function + aVariant = descStr; + break; + } + + default: // column == -1 is used for default Compare function aVariant = node->m_Name; break; } diff --git a/pcbnew/generate_footprint_info.cpp b/pcbnew/generate_footprint_info.cpp index f61dbab5ee..db36b606ce 100644 --- a/pcbnew/generate_footprint_info.cpp +++ b/pcbnew/generate_footprint_info.cpp @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 Chris Pavlina - * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.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 @@ -118,12 +118,18 @@ public: doc += ch; } - - desc.Replace( doc, _( "doc url" ) ); } + wxString esc_desc = EscapeHTML( UnescapeString( desc ) ); + + // Add line breaks + esc_desc.Replace( wxS( "\n" ), wxS( "
" ) ); + + // Add links + esc_desc = LinkifyHTML( esc_desc ); + + m_html.Replace( "__DESC__", esc_desc ); m_html.Replace( "__NAME__", EscapeHTML( name ) ); - m_html.Replace( "__DESC__", EscapeHTML( desc ) ); wxString keywordsHtml = KeywordsFormat; keywordsHtml.Replace( "__KEYWORDS__", EscapeHTML( keywords ) );