22#include <wx/dcclient.h>
23#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();
90 if( uri.GetScheme() == wxT(
"http" ) || uri.GetScheme() == wxT(
"https" ) )
93 if( uri.GetScheme() == 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" ),
101 wxString
path = wxURI::Unescape( uri.GetPath() );
103 while(
path.EndsWith( wxT(
"." ) ) ||
path.EndsWith( wxT(
" " ) ) )
106 for(
const wxString& ext : blockedExtensions )
108 if(
path.EndsWith( ext ) )
121 std::vector<RUN> runs;
126 for(
const RUN& run : runs )
140 while( pos < aValue.length() )
146 if( aValue[pos] ==
'[' && tryParseMarkdown( aValue, pos,
end, label, href ) )
148 if( !plain.IsEmpty() )
150 aRuns.push_back( { plain, wxEmptyString, wxRect() } );
155 aRuns.push_back( { label, href, wxRect() } );
157 aRuns.push_back( { label, wxEmptyString, wxRect() } );
163 plain += aValue[pos];
168 if( !plain.IsEmpty() )
169 aRuns.push_back( { plain, wxEmptyString, wxRect() } );
174 wxDataViewCustomRenderer( wxT(
"string" ), wxDATAVIEW_CELL_INERT, wxDVR_DEFAULT_ALIGNMENT )
197 return wxSize( wxDVC_DEFAULT_RENDERER_SIZE, wxDVC_DEFAULT_RENDERER_SIZE );
205 wxSize ext = GetTextExtent( run.text );
207 size.y = std::max( size.y, ext.y );
211 size.y = wxDVC_DEFAULT_RENDERER_SIZE;
219 RenderBackground( aDC, aCell );
221 layoutRuns( *aDC,
m_runs, aCell.x, aCell.y, aCell.height );
223 const bool selected = ( aState & wxDATAVIEW_CELL_SELECTED ) != 0;
227 const int textState = 0;
229 const int textState = aState;
234 wxRect runRect = aCell;
235 runRect.x += xoffset;
236 runRect.width = run.bounds.width;
238 if( !run.href.IsEmpty() )
240 wxDCTextColourChanger col( *aDC, selected ? wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT )
241 : wxSystemSettings::GetColour( wxSYS_COLOUR_HOTLIGHT ) );
243 wxFont linkFont = aDC->GetFont();
244 linkFont.SetUnderlined(
true );
245 wxDCFontChanger font( *aDC, linkFont );
247 RenderText( run.text, 0, runRect, aDC, textState );
253 aDC->SetTextForeground( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT ) );
255 RenderText( run.text, 0, runRect, aDC, textState );
258 xoffset += run.bounds.width;
266 const wxRect& aCellRect,
const wxPoint& aPoint, wxString* aHref )
const
268 std::vector<RUN> runs;
271 wxClientDC dc(
const_cast<wxDataViewCtrl*
>( GetView() ) );
272 wxFont font = GetView()->GetFont();
274 if( aCellAttr.GetBold() )
277 if( aCellAttr.GetItalic() )
280 if( aCellAttr.GetStrikethrough() )
281 font.MakeStrikethrough();
284 layoutRuns( dc, runs, aCellRect.x, aCellRect.y, aCellRect.height );
286 for(
const RUN& run : runs )
288 if( !run.href.IsEmpty() && run.bounds.Contains( aPoint ) )
bool HitTestRunsForCell(const wxString &aValue, const wxDataViewItemAttr &aCellAttr, const wxRect &aCellRect, const wxPoint &aPoint, wxString *aHref) const
Hit-test aPoint against the link runs of aValue laid out in aCell.
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.
wxString result
Test unit parsing edge cases and error handling.