Fix handling of ampersands in wxDataViewCtrl markup

Handle "&" in exactly the same way as "&" in wxMarkupParser, i.e. do not
map the former to "&&" to prevent it from being interpreted as a mnemonic as
this is incompatible with using markup for anything but the control labels,
e.g. for wxDataViewCtrl items text, in which mnemonics are not recognized.
And even when using markup for control labels, it was a questionable decision
as it's really not clear at all why should the XML entity and the raw
character itself be handled differently.

Also split wxMarkupText into two classes, wxMarkupText that handles
mnemonics in the markup (which is typically a label) and a very
similar, but not derived, wxItemMarkupText that handles mnemonics-less
markup for list etc. items, uses DrawItemText() and supports
ellipsizing.

Illustrate the use of ampersands in the dataview sample.
This commit is contained in:
Václav Slavík 2017-02-13 20:09:19 +01:00 committed by Václav Slavík
parent 0e2f6f6ec0
commit 60bd6842e4
6 changed files with 94 additions and 62 deletions

View File

@ -83,7 +83,7 @@ protected:
private:
#if wxUSE_MARKUP
class wxMarkupText *m_markupText;
class wxItemMarkupText *m_markupText;
#endif // wxUSE_MARKUP
wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer);

View File

@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/generic/private/markuptext.h
// Purpose: Generic wxMarkupText class for managing text with markup.
// Purpose: Generic wx*MarkupText classes for managing text with markup.
// Author: Vadim Zeitlin
// Created: 2011-02-21
// Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
@ -21,7 +21,36 @@ class wxMarkupParserOutput;
// wxMarkupText: allows to measure and draw the text containing markup.
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_CORE wxMarkupText
class WXDLLIMPEXP_CORE wxMarkupTextBase
{
public:
// Update the markup string.
void SetMarkup(const wxString& markup) { m_markup = markup; }
// Return the width and height required by the given string and optionally
// the height of the visible part above the baseline (i.e. ascent minus
// internal leading).
//
// The font currently selected into the DC is used for measuring (notice
// that it is changed by this function but normally -- i.e. if markup is
// valid -- restored to its original value when it returns).
wxSize Measure(wxDC& dc, int *visibleHeight = NULL) const;
protected:
wxMarkupTextBase(const wxString& markup)
: m_markup(markup)
{
}
// Return m_markup suitable for measuring by Measure, i.e. stripped of
// any mnenomics.
virtual wxString GetMarkupForMeasuring() const = 0;
wxString m_markup;
};
class WXDLLIMPEXP_CORE wxMarkupText : public wxMarkupTextBase
{
public:
// Constants for Render() flags.
@ -43,8 +72,7 @@ public:
// TODO-MULTILINE-MARKUP: Currently only single line labels are supported,
// search for other occurrences of this comment to find the places which
// need to be updated to support multiline labels with markup.
wxMarkupText(const wxString& markup)
: m_markup(markup)
wxMarkupText(const wxString& markup) : wxMarkupTextBase(markup)
{
}
@ -55,21 +83,6 @@ public:
// The same rules for mnemonics as in the ctor apply to this string.
void SetMarkup(const wxString& markup) { m_markup = markup; }
// This is a convenience method which can be used with the string in which
// mnemonics should be completely ignored, i.e. not interpreted in any way
// but just handled as ordinary characters.
void SetMarkupText(const wxString& markup);
// Return the width and height required by the given string and optionally
// the height of the visible part above the baseline (i.e. ascent minus
// internal leading).
//
// The font currently selected into the DC is used for measuring (notice
// that it is changed by this function but normally -- i.e. if markup is
// valid -- restored to its original value when it returns).
wxSize Measure(wxDC& dc, int *visibleHeight = NULL) const;
// Render the markup string into the given DC in the specified rectangle.
//
// Notice that while the function uses the provided rectangle for alignment
@ -77,24 +90,47 @@ public:
// and set the clipping region before rendering if necessary.
void Render(wxDC& dc, const wxRect& rect, int flags);
// Similar to Render(), but uses wxRendererNative::DrawItemText() instead
// of generic wxDC::DrawLabel(), so is more suitable for use in controls
// that already use DrawItemText() for its items.
protected:
virtual wxString GetMarkupForMeasuring() const wxOVERRIDE;
};
// ----------------------------------------------------------------------------
// wxItemMarkupText: variant of wxMarkupText for items without mnemonics
// ----------------------------------------------------------------------------
// This class has similar interface to wxItemMarkup, but no strings contain
// mnemonics and no escaping is done.
class WXDLLIMPEXP_CORE wxItemMarkupText : public wxMarkupTextBase
{
public:
// Initialize with the given string containing markup (which is supposed to
// be valid, the caller must check for it before constructing this object).
// Notice that mnemonics are not interpreted at all by this class, so
// literal ampersands shouldn't be escaped/doubled.
wxItemMarkupText(const wxString& markup) : wxMarkupTextBase(markup)
{
}
// Default copy ctor, assignment operator and dtor are ok.
// Similar to wxMarkupText::Render(), but uses wxRendererNative::DrawItemText()
// instead of generic wxDC::DrawLabel(), so is more suitable for use in
// controls that already use DrawItemText() for its items.
//
// The meaning of the flags here is different than in the overload above:
// they're passed to DrawItemText() and Render_ShowAccels is not supported
// here.
// The meaning of the flags here is different than in wxMarkupText too:
// they're passed to DrawItemText().
//
// Currently the only supported ellipsize modes are wxELLIPSIZE_NONE and
// wxELLIPSIZE_END, the others are treated as wxELLIPSIZE_END.
void RenderItemText(wxWindow *win,
wxDC& dc,
const wxRect& rect,
int rendererFlags,
wxEllipsizeMode ellipsizeMode);
void Render(wxWindow *win,
wxDC& dc,
const wxRect& rect,
int rendererFlags,
wxEllipsizeMode ellipsizeMode);
private:
wxString m_markup;
protected:
virtual wxString GetMarkupForMeasuring() const wxOVERRIDE { return m_markup; }
};
#endif // _WX_GENERIC_PRIVATE_MARKUPTEXT_H_

View File

@ -441,8 +441,8 @@ void MyListModel::GetValueByRow( wxVariant &variant,
"<span color=\"#87ceeb\">light</span> and "
"<span color=\"#000080\">dark</span> blue",
"<big>growing green</big>",
"<i>emphatic red</i>",
"<b>bold cyan</b>",
"<i>emphatic &amp; red</i>",
"<b>bold &amp;&amp; cyan</b>",
"<small><tt>dull default</tt></small>",
};

View File

@ -371,12 +371,7 @@ bool wxMarkupParser::Parse(const wxString& text)
if ( text.compare(pos, xmlEnt.len, xmlEnt.name) == 0
&& text[pos + xmlEnt.len] == ';' )
{
// Escape the ampersands if needed to protect them
// from being interpreted as mnemonics indicators.
if ( xmlEnt.value == '&' )
current += "&&";
else
current += xmlEnt.value;
current += xmlEnt.value;
it += xmlEnt.len + 1; // +1 for '&' itself

View File

@ -1067,7 +1067,7 @@ void wxDataViewTextRenderer::EnableMarkup(bool enable)
{
if ( !m_markupText )
{
m_markupText = new wxMarkupText(wxString());
m_markupText = new wxItemMarkupText(wxString());
}
}
else
@ -1087,7 +1087,7 @@ bool wxDataViewTextRenderer::SetValue( const wxVariant &value )
#if wxUSE_MARKUP
if ( m_markupText )
m_markupText->SetMarkupText(m_text);
m_markupText->SetMarkup(m_text);
#endif // wxUSE_MARKUP
return true;
@ -1135,7 +1135,7 @@ bool wxDataViewTextRenderer::Render(wxRect rect, wxDC *dc, int state)
int flags = 0;
if ( state & wxDATAVIEW_CELL_SELECTED )
flags |= wxCONTROL_SELECTED;
m_markupText->RenderItemText(GetView(), *dc, rect, flags, GetEllipsizeMode());
m_markupText->Render(GetView(), *dc, rect, flags, GetEllipsizeMode());
}
else
#endif // wxUSE_MARKUP

View File

@ -66,10 +66,8 @@ public:
const wxSize& GetSize() const { return m_size; }
virtual void OnText(const wxString& text_) wxOVERRIDE
virtual void OnText(const wxString& text) wxOVERRIDE
{
const wxString text(wxControl::RemoveMnemonics(text_));
// TODO-MULTILINE-MARKUP: Must use GetMultiLineTextExtent().
const wxSize size = m_dc.GetTextExtent(text);
@ -253,10 +251,8 @@ public:
m_ellipsizeMode = ellipsizeMode == wxELLIPSIZE_NONE ? wxELLIPSIZE_NONE : wxELLIPSIZE_END;
}
virtual void OnText(const wxString& text_) wxOVERRIDE
virtual void OnText(const wxString& text) wxOVERRIDE
{
const wxString text(wxControl::RemoveMnemonics(text_));
wxRect rect(m_rect);
rect.x = m_pos;
rect.SetRight(m_rect.GetRight());
@ -315,16 +311,11 @@ private:
// wxMarkupText implementation
// ============================================================================
void wxMarkupText::SetMarkupText(const wxString& markup)
{
m_markup = wxControl::EscapeMnemonics(markup);
}
wxSize wxMarkupText::Measure(wxDC& dc, int *visibleHeight) const
wxSize wxMarkupTextBase::Measure(wxDC& dc, int *visibleHeight) const
{
wxMarkupParserMeasureOutput out(dc, visibleHeight);
wxMarkupParser parser(out);
if ( !parser.Parse(m_markup) )
if ( !parser.Parse(GetMarkupForMeasuring()) )
{
wxFAIL_MSG( "Invalid markup" );
return wxDefaultSize;
@ -333,6 +324,11 @@ wxSize wxMarkupText::Measure(wxDC& dc, int *visibleHeight) const
return out.GetSize();
}
wxString wxMarkupText::GetMarkupForMeasuring() const
{
return wxControl::RemoveMnemonics(m_markup);
}
void wxMarkupText::Render(wxDC& dc, const wxRect& rect, int flags)
{
// We want to center the above-baseline parts of the letter vertically, so
@ -347,11 +343,16 @@ void wxMarkupText::Render(wxDC& dc, const wxRect& rect, int flags)
parser.Parse(m_markup);
}
void wxMarkupText::RenderItemText(wxWindow *win,
wxDC& dc,
const wxRect& rect,
int rendererFlags,
wxEllipsizeMode ellipsizeMode)
// ============================================================================
// wxItemMarkupText implementation
// ============================================================================
void wxItemMarkupText::Render(wxWindow *win,
wxDC& dc,
const wxRect& rect,
int rendererFlags,
wxEllipsizeMode ellipsizeMode)
{
wxMarkupParserRenderItemOutput out(win, dc, rect, rendererFlags, ellipsizeMode);
wxMarkupParser parser(out);