Improve editing values with {return} in text fields; Add hyperlink detection.

This commit is contained in:
Alex Shvartzkop 2023-10-15 01:00:02 +03:00
parent 95032bd487
commit 9ed19192de
10 changed files with 91 additions and 27 deletions

View File

@ -433,7 +433,7 @@ void LIB_TREE_MODEL_ADAPTER::FinishTreeInitialization()
for( ; idx < m_columns.size() - 1; idx++ ) for( ; idx < m_columns.size() - 1; idx++ )
{ {
wxASSERT( m_colIdxMap.count( idx ) ); wxASSERT( m_colIdxMap.count( idx ) );
col = m_columns[idx]; col = m_columns[idx];
header = m_colIdxMap[idx]; header = m_colIdxMap[idx];
@ -537,14 +537,15 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant,
LIB_TREE_NODE* node = ToNode( aItem ); LIB_TREE_NODE* node = ToNode( aItem );
wxCHECK( node, /* void */ ); wxCHECK( node, /* void */ );
wxString valueStr;
switch( aCol ) switch( aCol )
{ {
case NAME_COL: case NAME_COL:
if( node->m_Pinned ) if( node->m_Pinned )
aVariant = GetPinningSymbol() + UnescapeString( node->m_Name ); valueStr = GetPinningSymbol() + UnescapeString( node->m_Name );
else else
aVariant = UnescapeString( node->m_Name ); valueStr = UnescapeString( node->m_Name );
break; break;
@ -554,15 +555,19 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant& aVariant,
const wxString& key = m_colIdxMap.at( aCol ); const wxString& key = m_colIdxMap.at( aCol );
if( node->m_Fields.count( key ) ) if( node->m_Fields.count( key ) )
aVariant = node->m_Fields.at( key ); valueStr = UnescapeString( node->m_Fields.at( key ) );
else if( key == wxT( "Description" ) ) else if( key == wxT( "Description" ) )
aVariant = node->m_Desc; valueStr = UnescapeString( node->m_Desc );
else else
aVariant = wxEmptyString; valueStr = wxEmptyString;
} }
break; break;
} }
valueStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks
aVariant = valueStr;
} }

View File

@ -33,6 +33,7 @@
#include <richio.h> // StrPrintf #include <richio.h> // StrPrintf
#include <string_utils.h> #include <string_utils.h>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <wx/regex.h>
/** /**
@ -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, "<a href=\"\\0\">\\0</a>" );
return aStr;
}
bool NoPrintableChars( const wxString& aString ) bool NoPrintableChars( const wxString& aString )
{ {
wxString tmp = aString; wxString tmp = aString;

View File

@ -302,11 +302,11 @@ bool DIALOG_FIELD_PROPERTIES::TransferDataToWindow()
{ {
if( m_TextCtrl->IsShown() ) if( m_TextCtrl->IsShown() )
{ {
m_TextCtrl->SetValue( m_text ); m_TextCtrl->SetValue( EscapeString( m_text, CTX_LINE ) );
} }
else if( m_StyledTextCtrl->IsShown() ) else if( m_StyledTextCtrl->IsShown() )
{ {
m_StyledTextCtrl->SetValue( m_text ); m_StyledTextCtrl->SetValue( EscapeString( m_text, CTX_LINE ) );
m_StyledTextCtrl->EmptyUndoBuffer(); m_StyledTextCtrl->EmptyUndoBuffer();
} }
@ -349,9 +349,9 @@ bool DIALOG_FIELD_PROPERTIES::TransferDataToWindow()
bool DIALOG_FIELD_PROPERTIES::TransferDataFromWindow() bool DIALOG_FIELD_PROPERTIES::TransferDataFromWindow()
{ {
if( m_TextCtrl->IsShown() ) if( m_TextCtrl->IsShown() )
m_text = m_TextCtrl->GetValue(); m_text = UnescapeString( m_TextCtrl->GetValue() );
else if( m_StyledTextCtrl->IsShown() ) else if( m_StyledTextCtrl->IsShown() )
m_text = m_StyledTextCtrl->GetValue(); m_text = UnescapeString( m_StyledTextCtrl->GetValue() );
if( m_fieldId == REFERENCE_FIELD ) if( m_fieldId == REFERENCE_FIELD )
{ {

View File

@ -561,7 +561,7 @@ wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
} }
case FDC_VALUE: case FDC_VALUE:
return UnescapeString( field.GetText() ); return EscapeString( UnescapeString( field.GetText() ), CTX_LINE );
case FDC_SHOWN: case FDC_SHOWN:
return StringFromBool( field.IsVisible() ); return StringFromBool( field.IsVisible() );
@ -696,7 +696,7 @@ void FIELDS_GRID_TABLE<T>::SetValue( int aRow, int aCol, const wxString &aValue
value = EscapeString( value, CTX_LIBID ); value = EscapeString( value, CTX_LIBID );
} }
field.SetText( value ); field.SetText( UnescapeString( value ) );
break; break;
} }

View File

@ -138,9 +138,15 @@ protected:
void SetHtmlDesc() 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( "<br>" ) );
// Add links
esc_desc = LinkifyHTML( esc_desc );
m_html.Replace( wxS( "__DESC__" ), wxString::Format( DescFormat, esc_desc ) );
} }

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2017 CERN * 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 <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* *
* This program is free software; you can redistribute it and/or * 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(); node->m_Desc = m_frame->GetCurSymbol()->GetDescription();
} }
wxString valueStr;
if( node->m_Fields.count( key ) ) if( node->m_Fields.count( key ) )
aVariant = node->m_Fields.at( key ); valueStr = node->m_Fields.at( key );
else if( key == wxT( "Description" ) ) else if( key == wxT( "Description" ) )
aVariant = node->m_Desc; valueStr = node->m_Desc;
else else
aVariant = wxEmptyString; valueStr = wxEmptyString;
valueStr.Replace( wxS( "\n" ), wxS( " " ) ); // Clear line breaks
aVariant = valueStr;
} }
break; break;
} }

View File

@ -129,6 +129,19 @@ KICOMMON_API wxString EscapeHTML( const wxString& aString );
*/ */
KICOMMON_API wxString UnescapeHTML( 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 <a href=""></a> tags.
*/
KICOMMON_API wxString LinkifyHTML( wxString aStr );
/** /**
* Read one line line from \a aFile. * Read one line line from \a aFile.
* *

View File

@ -254,7 +254,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataToWindow()
m_FootprintNameCtrl->ChangeValue( footprintName ); 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() ); m_KeywordCtrl->SetValue( m_footprint->GetKeywords() );
if( !wxDialog::TransferDataToWindow() ) if( !wxDialog::TransferDataToWindow() )
@ -492,7 +492,7 @@ bool DIALOG_FOOTPRINT_PROPERTIES_FP_EDITOR::TransferDataFromWindow()
fpID.SetLibItemName( m_FootprintNameCtrl->GetValue() ); fpID.SetLibItemName( m_FootprintNameCtrl->GetValue() );
m_footprint->SetFPID( fpID ); m_footprint->SetFPID( fpID );
m_footprint->SetLibDescription( m_DocCtrl->GetValue() ); m_footprint->SetLibDescription( UnescapeString( m_DocCtrl->GetValue() ) );
m_footprint->SetKeywords( m_KeywordCtrl->GetValue() ); m_footprint->SetKeywords( m_KeywordCtrl->GetValue() );
// Update fields // Update fields

View File

@ -198,6 +198,7 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte
switch( aCol ) switch( aCol )
{ {
case NAME_COL: case NAME_COL:
{
if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() ) if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() )
{ {
// Do not use GetLoadedFPID(); it returns m_footprintNameWhenLoaded. // Do not use GetLoadedFPID(); it returns m_footprintNameWhenLoaded.
@ -220,8 +221,10 @@ void FP_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataViewIte
} }
break; break;
}
case DESC_COL: case DESC_COL:
{
if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() ) if( node->m_LibId == m_frame->GetLoadedFPID() && !m_frame->IsCurrentFPFromBoard() )
{ {
node->m_Desc = m_frame->GetBoard()->GetFirstFootprint()->GetLibDescription(); 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; wxString descStr = UnescapeString( node->m_Desc );
break; 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; aVariant = node->m_Name;
break; break;
} }

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com> * Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
* 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 * 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 * under the terms of the GNU General Public License as published by the
@ -118,12 +118,18 @@ public:
doc += ch; doc += ch;
} }
desc.Replace( doc, _( "doc url" ) );
} }
wxString esc_desc = EscapeHTML( UnescapeString( desc ) );
// Add line breaks
esc_desc.Replace( wxS( "\n" ), wxS( "<br>" ) );
// Add links
esc_desc = LinkifyHTML( esc_desc );
m_html.Replace( "__DESC__", esc_desc );
m_html.Replace( "__NAME__", EscapeHTML( name ) ); m_html.Replace( "__NAME__", EscapeHTML( name ) );
m_html.Replace( "__DESC__", EscapeHTML( desc ) );
wxString keywordsHtml = KeywordsFormat; wxString keywordsHtml = KeywordsFormat;
keywordsHtml.Replace( "__KEYWORDS__", EscapeHTML( keywords ) ); keywordsHtml.Replace( "__KEYWORDS__", EscapeHTML( keywords ) );