From 60bd6842e40a0e94810bcc710c732049455f7329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 13 Feb 2017 20:09:19 +0100 Subject: [PATCH] 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. --- include/wx/generic/dvrenderers.h | 2 +- include/wx/generic/private/markuptext.h | 100 ++++++++++++++++-------- samples/dataview/mymodels.cpp | 4 +- src/common/markupparser.cpp | 7 +- src/generic/datavgen.cpp | 6 +- src/generic/markuptext.cpp | 37 ++++----- 6 files changed, 94 insertions(+), 62 deletions(-) diff --git a/include/wx/generic/dvrenderers.h b/include/wx/generic/dvrenderers.h index d89db266a3..d85bbe0619 100644 --- a/include/wx/generic/dvrenderers.h +++ b/include/wx/generic/dvrenderers.h @@ -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); diff --git a/include/wx/generic/private/markuptext.h b/include/wx/generic/private/markuptext.h index 377e1d3632..4235d50de8 100644 --- a/include/wx/generic/private/markuptext.h +++ b/include/wx/generic/private/markuptext.h @@ -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 @@ -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_ diff --git a/samples/dataview/mymodels.cpp b/samples/dataview/mymodels.cpp index 1ee62f8083..c7953bfcdc 100644 --- a/samples/dataview/mymodels.cpp +++ b/samples/dataview/mymodels.cpp @@ -441,8 +441,8 @@ void MyListModel::GetValueByRow( wxVariant &variant, "light and " "dark blue", "growing green", - "emphatic red", - "bold cyan", + "emphatic & red", + "bold && cyan", "dull default", }; diff --git a/src/common/markupparser.cpp b/src/common/markupparser.cpp index 5ab9664e44..5f04d76624 100644 --- a/src/common/markupparser.cpp +++ b/src/common/markupparser.cpp @@ -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 diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 01e8a8c354..d7c02c8f63 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -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 diff --git a/src/generic/markuptext.cpp b/src/generic/markuptext.cpp index 1328c52d1c..c883632b9d 100644 --- a/src/generic/markuptext.cpp +++ b/src/generic/markuptext.cpp @@ -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);