22#include <wx/dcclient.h>
23#include <wx/settings.h>
31bool tryParseMarkdown(
const wxString& aText,
size_t aStart,
size_t& aEnd, wxString& aLabel, wxString& aHref )
33 if( aStart >= aText.length() || aText[aStart] !=
'[' )
36 size_t labelEnd = aText.find(
']', aStart + 1 );
38 if( labelEnd == wxString::npos || labelEnd + 1 >= aText.length() || aText[labelEnd + 1] !=
'(' )
42 size_t hrefStart = labelEnd + 2;
43 size_t hrefEnd = wxString::npos;
46 for(
size_t i = hrefStart; i < aText.length(); ++i )
52 else if( c ==
')' && --depth == 0 )
59 if( hrefEnd == wxString::npos )
62 aLabel = aText.SubString( aStart + 1, labelEnd - 1 );
63 aHref = aText.SubString( hrefStart, hrefEnd - 1 );
69void layoutRuns( wxDC& aDC, std::vector<HYPERLINK_DV_RENDERER::RUN>& aRuns,
int aX,
int aY,
int aHeight )
75 wxSize ext = aDC.GetTextExtent( run.text );
76 run.bounds = wxRect( x, aY, ext.x, aHeight > 0 ? aHeight : ext.y );
86 wxString lower = aHref.Lower();
88 if( lower.StartsWith( wxT(
"http://" ) ) || lower.StartsWith( wxT(
"https://" ) ) )
91 bool isLocalFile = lower.StartsWith( wxT(
"file://" ) ) || lower.StartsWith( wxT(
"\\\\" ) );
95 static const wxString blockedExtensions[] = { wxT(
".exe" ), wxT(
".com" ), wxT(
".bat" ), wxT(
".cmd" ),
96 wxT(
".ps1" ), wxT(
".vbs" ), wxT(
".js" ), wxT(
".jar" ),
97 wxT(
".msi" ), wxT(
".scr" ), wxT(
".pif" ), wxT(
".lnk" ),
100 for(
const wxString& ext : blockedExtensions )
102 if( lower.EndsWith( ext ) )
115 std::vector<RUN> runs;
120 for(
const RUN& run : runs )
134 while( pos < aValue.length() )
140 if( aValue[pos] ==
'[' && tryParseMarkdown( aValue, pos,
end, label, href ) )
142 if( !plain.IsEmpty() )
144 aRuns.push_back( { plain, wxEmptyString, wxRect() } );
149 aRuns.push_back( { label, href, wxRect() } );
151 aRuns.push_back( { label, wxEmptyString, wxRect() } );
157 plain += aValue[pos];
162 if( !plain.IsEmpty() )
163 aRuns.push_back( { plain, wxEmptyString, wxRect() } );
168 wxDataViewCustomRenderer( wxT(
"string" ), wxDATAVIEW_CELL_INERT, wxDVR_DEFAULT_ALIGNMENT )
191 return wxSize( wxDVC_DEFAULT_RENDERER_SIZE, wxDVC_DEFAULT_RENDERER_SIZE );
199 wxSize ext = GetTextExtent( run.text );
201 size.y = std::max( size.y, ext.y );
205 size.y = wxDVC_DEFAULT_RENDERER_SIZE;
213 RenderBackground( aDC, aCell );
218 layoutRuns( *aDC,
m_runs, aCell.x, aCell.y, aCell.height );
220 const bool selected = ( aState & wxDATAVIEW_CELL_SELECTED ) != 0;
224 const int textState = 0;
226 const int textState = aState;
231 wxRect runRect = aCell;
232 runRect.x += xoffset;
233 runRect.width = run.bounds.width;
235 if( !run.href.IsEmpty() )
237 wxDCTextColourChanger col( *aDC, selected ? wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT )
238 : wxSystemSettings::GetColour( wxSYS_COLOUR_HOTLIGHT ) );
240 wxFont linkFont = aDC->GetFont();
241 linkFont.SetUnderlined(
true );
242 wxDCFontChanger font( *aDC, linkFont );
244 RenderText( run.text, 0, runRect, aDC, textState );
250 aDC->SetTextForeground( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );
252 RenderText( run.text, 0, runRect, aDC, textState );
255 xoffset += run.bounds.width;
263 wxString* aHref )
const
265 std::vector<RUN> runs;
268 wxClientDC dc(
const_cast<wxDataViewCtrl*
>( GetView() ) );
270 layoutRuns( dc, runs, aCell.x, aCell.y, aCell.height );
272 for(
const RUN& run : runs )
274 if( !run.href.IsEmpty() && run.bounds.Contains( aPoint ) )
wxSize GetSize() const override
static void ParseRuns(const wxString &aValue, std::vector< RUN > &aRuns)
Split aValue into plain text and link runs.
bool SetValue(const wxVariant &aValue) override
std::vector< RUN > m_runs
static wxString StripMarkup(const wxString &aValue)
Flatten [label](url) markup, keeping just the label.
bool Render(wxRect aCell, wxDC *aDC, int aState) override
bool GetValue(wxVariant &aValue) const override
static bool IsSafeUrl(const wxString &aHref)
Accept only schemes that wxLaunchDefaultBrowser cannot turn into program execution.
bool HitTestRunsForCell(const wxString &aValue, const wxRect &aCell, const wxPoint &aPoint, wxString *aHref) const
Hit-test aPoint against the link runs of aValue laid out in aCell.
wxString result
Test unit parsing edge cases and error handling.