23#include <wx/dcclient.h>
24#include <wx/settings.h>
32bool tryParseMarkdown(
const wxString& aText,
size_t aStart,
size_t& aEnd, wxString& aLabel, wxString& aHref )
34 if( aStart >= aText.length() || aText[aStart] !=
'[' )
37 size_t labelEnd = aText.find(
']', aStart + 1 );
39 if( labelEnd == wxString::npos || labelEnd + 1 >= aText.length() || aText[labelEnd + 1] !=
'(' )
43 size_t hrefStart = labelEnd + 2;
44 size_t hrefEnd = wxString::npos;
47 for(
size_t i = hrefStart; i < aText.length(); ++i )
53 else if( c ==
')' && --depth == 0 )
60 if( hrefEnd == wxString::npos )
63 aLabel = aText.SubString( aStart + 1, labelEnd - 1 );
64 aHref = aText.SubString( hrefStart, hrefEnd - 1 );
70void layoutRuns( wxDC& aDC, std::vector<HYPERLINK_DV_RENDERER::RUN>& aRuns,
int aX,
int aY,
int aHeight )
76 wxSize ext = aDC.GetTextExtent( run.text );
77 run.bounds = wxRect( x, aY, ext.x, aHeight > 0 ? aHeight : ext.y );
87 wxString lower = aHref.Lower();
89 if( lower.StartsWith( wxT(
"http://" ) ) || lower.StartsWith( wxT(
"https://" ) ) )
92 bool isLocalFile = lower.StartsWith( wxT(
"file://" ) ) || lower.StartsWith( wxT(
"\\\\" ) );
96 static const wxString blockedExtensions[] = { wxT(
".exe" ), wxT(
".com" ), wxT(
".bat" ), wxT(
".cmd" ),
97 wxT(
".ps1" ), wxT(
".vbs" ), wxT(
".js" ), wxT(
".jar" ),
98 wxT(
".msi" ), wxT(
".scr" ), wxT(
".pif" ), wxT(
".lnk" ),
101 for(
const wxString& ext : blockedExtensions )
103 if( lower.EndsWith( ext ) )
116 std::vector<RUN> runs;
121 for(
const RUN& run : runs )
135 while( pos < aValue.length() )
141 if( aValue[pos] ==
'[' && tryParseMarkdown( aValue, pos,
end, label, href ) )
143 if( !plain.IsEmpty() )
145 aRuns.push_back( { plain, wxEmptyString, wxRect() } );
150 aRuns.push_back( { label, href, wxRect() } );
152 aRuns.push_back( { label, wxEmptyString, wxRect() } );
158 plain += aValue[pos];
163 if( !plain.IsEmpty() )
164 aRuns.push_back( { plain, wxEmptyString, wxRect() } );
169 wxDataViewCustomRenderer( wxT(
"string" ), wxDATAVIEW_CELL_INERT, wxDVR_DEFAULT_ALIGNMENT )
192 return wxSize( wxDVC_DEFAULT_RENDERER_SIZE, wxDVC_DEFAULT_RENDERER_SIZE );
200 wxSize ext = GetTextExtent( run.text );
202 size.y = std::max( size.y, ext.y );
206 size.y = wxDVC_DEFAULT_RENDERER_SIZE;
214 RenderBackground( aDC, aCell );
219 layoutRuns( *aDC,
m_runs, aCell.x, aCell.y, aCell.height );
221 const bool selected = ( aState & wxDATAVIEW_CELL_SELECTED ) != 0;
225 const int textState = 0;
227 const int textState = aState;
232 wxRect runRect = aCell;
233 runRect.x += xoffset;
234 runRect.width = run.bounds.width;
236 if( !run.href.IsEmpty() )
238 wxDCTextColourChanger col( *aDC, selected ? wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT )
239 : wxSystemSettings::GetColour( wxSYS_COLOUR_HOTLIGHT ) );
241 wxFont linkFont = aDC->GetFont();
242 linkFont.SetUnderlined(
true );
243 wxDCFontChanger font( *aDC, linkFont );
245 RenderText( run.text, 0, runRect, aDC, textState );
251 aDC->SetTextForeground( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );
253 RenderText( run.text, 0, runRect, aDC, textState );
256 xoffset += run.bounds.width;
264 wxString* aHref )
const
266 std::vector<RUN> runs;
269 wxClientDC dc(
const_cast<wxDataViewCtrl*
>( GetView() ) );
271 layoutRuns( dc, runs, aCell.x, aCell.y, aCell.height );
273 for(
const RUN& run : runs )
275 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.