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: private:
#if wxUSE_MARKUP #if wxUSE_MARKUP
class wxMarkupText *m_markupText; class wxItemMarkupText *m_markupText;
#endif // wxUSE_MARKUP #endif // wxUSE_MARKUP
wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer); wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer);

View File

@@ -1,6 +1,6 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Name: wx/generic/private/markuptext.h // 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 // Author: Vadim Zeitlin
// Created: 2011-02-21 // Created: 2011-02-21
// Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org> // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
@@ -21,7 +21,36 @@ class wxMarkupParserOutput;
// wxMarkupText: allows to measure and draw the text containing markup. // 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: public:
// Constants for Render() flags. // Constants for Render() flags.
@@ -43,8 +72,7 @@ public:
// TODO-MULTILINE-MARKUP: Currently only single line labels are supported, // TODO-MULTILINE-MARKUP: Currently only single line labels are supported,
// search for other occurrences of this comment to find the places which // search for other occurrences of this comment to find the places which
// need to be updated to support multiline labels with markup. // need to be updated to support multiline labels with markup.
wxMarkupText(const wxString& markup) wxMarkupText(const wxString& markup) : wxMarkupTextBase(markup)
: m_markup(markup)
{ {
} }
@@ -55,21 +83,6 @@ public:
// The same rules for mnemonics as in the ctor apply to this string. // The same rules for mnemonics as in the ctor apply to this string.
void SetMarkup(const wxString& markup) { m_markup = markup; } 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. // Render the markup string into the given DC in the specified rectangle.
// //
// Notice that while the function uses the provided rectangle for alignment // 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. // and set the clipping region before rendering if necessary.
void Render(wxDC& dc, const wxRect& rect, int flags); void Render(wxDC& dc, const wxRect& rect, int flags);
// Similar to Render(), but uses wxRendererNative::DrawItemText() instead protected:
// of generic wxDC::DrawLabel(), so is more suitable for use in controls virtual wxString GetMarkupForMeasuring() const wxOVERRIDE;
// that already use DrawItemText() for its items. };
// ----------------------------------------------------------------------------
// 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: // The meaning of the flags here is different than in wxMarkupText too:
// they're passed to DrawItemText() and Render_ShowAccels is not supported // they're passed to DrawItemText().
// here.
// //
// Currently the only supported ellipsize modes are wxELLIPSIZE_NONE and // Currently the only supported ellipsize modes are wxELLIPSIZE_NONE and
// wxELLIPSIZE_END, the others are treated as wxELLIPSIZE_END. // wxELLIPSIZE_END, the others are treated as wxELLIPSIZE_END.
void RenderItemText(wxWindow *win, void Render(wxWindow *win,
wxDC& dc, wxDC& dc,
const wxRect& rect, const wxRect& rect,
int rendererFlags, int rendererFlags,
wxEllipsizeMode ellipsizeMode); wxEllipsizeMode ellipsizeMode);
private: protected:
wxString m_markup; virtual wxString GetMarkupForMeasuring() const wxOVERRIDE { return m_markup; }
}; };
#endif // _WX_GENERIC_PRIVATE_MARKUPTEXT_H_ #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=\"#87ceeb\">light</span> and "
"<span color=\"#000080\">dark</span> blue", "<span color=\"#000080\">dark</span> blue",
"<big>growing green</big>", "<big>growing green</big>",
"<i>emphatic red</i>", "<i>emphatic &amp; red</i>",
"<b>bold cyan</b>", "<b>bold &amp;&amp; cyan</b>",
"<small><tt>dull default</tt></small>", "<small><tt>dull default</tt></small>",
}; };

View File

@@ -371,11 +371,6 @@ bool wxMarkupParser::Parse(const wxString& text)
if ( text.compare(pos, xmlEnt.len, xmlEnt.name) == 0 if ( text.compare(pos, xmlEnt.len, xmlEnt.name) == 0
&& text[pos + xmlEnt.len] == ';' ) && 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 it += xmlEnt.len + 1; // +1 for '&' itself

View File

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

View File

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