preserve TAB characters when copying HTML <pre> content to clipboard
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@53282 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -375,12 +375,17 @@ public:
|
||||
void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2,
|
||||
wxHtmlRenderingInfo& info);
|
||||
virtual wxCursor GetMouseCursor(wxHtmlWindowInterface *window) const;
|
||||
wxString ConvertToText(wxHtmlSelection *sel) const;
|
||||
virtual wxString ConvertToText(wxHtmlSelection *sel) const;
|
||||
bool IsLinebreakAllowed() const { return m_allowLinebreak; }
|
||||
|
||||
void SetPreviousWord(wxHtmlWordCell *cell);
|
||||
|
||||
protected:
|
||||
virtual wxString GetAllAsText() const
|
||||
{ return m_Word; }
|
||||
virtual wxString GetPartAsText(int begin, int end) const
|
||||
{ return m_Word.Mid(begin, end - begin); }
|
||||
|
||||
void SetSelectionPrivPos(const wxDC& dc, wxHtmlSelection *s) const;
|
||||
void Split(const wxDC& dc,
|
||||
const wxPoint& selFrom, const wxPoint& selTo,
|
||||
@@ -394,7 +399,28 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
// wxHtmlWordCell specialization for storing text fragments with embedded
|
||||
// '\t's; these differ from normal words in that the displayed text is
|
||||
// different from the text copied to clipboard
|
||||
class WXDLLIMPEXP_HTML wxHtmlWordWithTabsCell : public wxHtmlWordCell
|
||||
{
|
||||
public:
|
||||
wxHtmlWordWithTabsCell(const wxString& word,
|
||||
const wxString& wordOrig,
|
||||
size_t linepos,
|
||||
const wxDC& dc)
|
||||
: wxHtmlWordCell(word, dc),
|
||||
m_wordOrig(wordOrig),
|
||||
m_linepos(linepos)
|
||||
{}
|
||||
|
||||
protected:
|
||||
virtual wxString GetAllAsText() const;
|
||||
virtual wxString GetPartAsText(int begin, int end) const;
|
||||
|
||||
wxString m_wordOrig;
|
||||
size_t m_linepos;
|
||||
};
|
||||
|
||||
|
||||
// Container contains other cells, thus forming tree structure of rendering
|
||||
|
@@ -145,11 +145,25 @@ public:
|
||||
// creates font depending on m_Font* members.
|
||||
virtual wxFont* CreateCurrentFont();
|
||||
|
||||
enum WhitespaceMode
|
||||
{
|
||||
Whitespace_Normal, // normal mode, collapse whitespace
|
||||
Whitespace_Pre // inside <pre>, keep whitespace as-is
|
||||
};
|
||||
|
||||
// change the current whitespace handling mode
|
||||
void SetWhitespaceMode(WhitespaceMode mode) { m_whitespaceMode = mode; }
|
||||
WhitespaceMode GetWhitespaceMode() const { return m_whitespaceMode; }
|
||||
|
||||
protected:
|
||||
virtual void AddText(const wxString& txt);
|
||||
|
||||
private:
|
||||
void DoAddText(wxChar *temp, int& templen);
|
||||
void FlushWordBuf(wxChar *temp, int& len);
|
||||
void AddWord(wxHtmlWordCell *word);
|
||||
void AddWord(const wxString& word)
|
||||
{ AddWord(new wxHtmlWordCell(word, *(GetDC()))); }
|
||||
void AddPreBlock(const wxString& text);
|
||||
|
||||
bool m_tmpLastWasSpace;
|
||||
wxChar *m_tmpStrBuf;
|
||||
@@ -207,8 +221,15 @@ private:
|
||||
wxEncodingConverter *m_EncConv;
|
||||
#endif
|
||||
|
||||
// current whitespace handling mode
|
||||
WhitespaceMode m_whitespaceMode;
|
||||
|
||||
wxHtmlWordCell *m_lastWordCell;
|
||||
|
||||
// current position on line, in num. of characters; used to properly
|
||||
// expand TABs; only updated while inside <pre>
|
||||
int m_posColumn;
|
||||
|
||||
DECLARE_NO_COPY_CLASS(wxHtmlWinParser)
|
||||
};
|
||||
|
||||
|
@@ -464,6 +464,8 @@ void wxHtmlWordCell::Split(const wxDC& dc,
|
||||
|
||||
pos1 = i;
|
||||
pos2 = j;
|
||||
|
||||
wxASSERT( pos2 >= pos1 );
|
||||
}
|
||||
|
||||
void wxHtmlWordCell::SetSelectionPrivPos(const wxDC& dc, wxHtmlSelection *s) const
|
||||
@@ -617,6 +619,17 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y,
|
||||
}
|
||||
}
|
||||
|
||||
wxCursor wxHtmlWordCell::GetMouseCursor(wxHtmlWindowInterface *window) const
|
||||
{
|
||||
if ( !GetLink() )
|
||||
{
|
||||
return window->GetHTMLCursor(wxHtmlWindowInterface::HTMLCursor_Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxHtmlCell::GetMouseCursor(window);
|
||||
}
|
||||
}
|
||||
|
||||
wxString wxHtmlWordCell::ConvertToText(wxHtmlSelection *s) const
|
||||
{
|
||||
@@ -634,28 +647,76 @@ wxString wxHtmlWordCell::ConvertToText(wxHtmlSelection *s) const
|
||||
// TODO: but this really needs to be fixed in some better way later...
|
||||
if ( priv != wxDefaultPosition )
|
||||
{
|
||||
int part1 = priv.x;
|
||||
int part2 = priv.y;
|
||||
return m_Word.Mid(part1, part2-part1);
|
||||
const int part1 = priv.x;
|
||||
const int part2 = priv.y;
|
||||
if ( part1 == part2 )
|
||||
return wxEmptyString;
|
||||
return GetPartAsText(part1, part2);
|
||||
}
|
||||
//else: return the whole word below
|
||||
}
|
||||
|
||||
return m_Word;
|
||||
return GetAllAsText();
|
||||
}
|
||||
|
||||
wxCursor wxHtmlWordCell::GetMouseCursor(wxHtmlWindowInterface *window) const
|
||||
wxString wxHtmlWordWithTabsCell::GetAllAsText() const
|
||||
{
|
||||
if ( !GetLink() )
|
||||
return m_wordOrig;
|
||||
}
|
||||
|
||||
wxString wxHtmlWordWithTabsCell::GetPartAsText(int begin, int end) const
|
||||
{
|
||||
return window->GetHTMLCursor(wxHtmlWindowInterface::HTMLCursor_Text);
|
||||
// NB: The 'begin' and 'end' positions are in the _displayed_ text
|
||||
// (stored in m_Word) and not in the text with tabs that should
|
||||
// be copied to clipboard (m_wordOrig).
|
||||
//
|
||||
// NB: Because selection is performed on displayed text, it's possible
|
||||
// to select e.g. "half of TAB character" -- IOW, 'begin' and 'end'
|
||||
// may be in the middle of TAB character expansion into ' 's. In this
|
||||
// case, we copy the TAB character to clipboard once.
|
||||
|
||||
wxASSERT( begin < end );
|
||||
|
||||
const unsigned SPACES_PER_TAB = 8;
|
||||
|
||||
wxString sel;
|
||||
|
||||
int pos = 0;
|
||||
wxString::const_iterator i = m_wordOrig.begin();
|
||||
|
||||
// find the beginning of text to copy:
|
||||
for ( ; pos < begin; ++i )
|
||||
{
|
||||
if ( *i == '\t' )
|
||||
{
|
||||
pos += 8 - (m_linepos + pos) % SPACES_PER_TAB;
|
||||
if ( pos >= begin )
|
||||
{
|
||||
sel += '\t';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxHtmlCell::GetMouseCursor(window);
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
// copy the content until we reach 'end':
|
||||
for ( ; pos < end; ++i )
|
||||
{
|
||||
const wxChar c = *i;
|
||||
sel += c;
|
||||
|
||||
if ( c == '\t' )
|
||||
pos += 8 - (m_linepos + pos) % SPACES_PER_TAB;
|
||||
else
|
||||
++pos;
|
||||
}
|
||||
|
||||
return sel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// wxHtmlContainerCell
|
||||
|
@@ -28,40 +28,28 @@
|
||||
FORCE_LINK_ME(m_pre)
|
||||
|
||||
// replaces '\t', ' ' and '\n' with HTML markup:
|
||||
static wxString LINKAGEMODE HtmlizeWhitespaces(const wxString& str)
|
||||
static wxString LINKAGEMODE HtmlizeLinebreaks(const wxString& str)
|
||||
{
|
||||
wxString out;
|
||||
out.reserve(str.length()); // we'll certainly need at least that
|
||||
|
||||
size_t len = str.Len();
|
||||
size_t linepos = 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
switch ( str[i].GetValue() )
|
||||
{
|
||||
case wxT('<'):
|
||||
while (i < len && str[i] != wxT('>'))
|
||||
case '<':
|
||||
while (i < len && str[i] != '>')
|
||||
{
|
||||
out << str[i++];
|
||||
}
|
||||
out << wxT('>');
|
||||
out << '>';
|
||||
break;
|
||||
case wxT(' '):
|
||||
out << wxT(" ");
|
||||
linepos++;
|
||||
break;
|
||||
case wxT('\n'):
|
||||
out << wxT("<br>");
|
||||
linepos = 0;
|
||||
break;
|
||||
case wxT('\t'):
|
||||
{
|
||||
for (size_t j = 8 - linepos % 8; j > 0; j--)
|
||||
out << wxT(" ");
|
||||
linepos += 8 - linepos % 8;
|
||||
}
|
||||
case '\n':
|
||||
out << "<br>";
|
||||
break;
|
||||
default:
|
||||
out << str[i];
|
||||
linepos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -81,13 +69,16 @@ TAG_HANDLER_BEGIN(PRE, "PRE")
|
||||
{
|
||||
wxHtmlContainerCell *c;
|
||||
|
||||
int fixed = m_WParser->GetFontFixed(),
|
||||
italic = m_WParser->GetFontItalic(),
|
||||
underlined = m_WParser->GetFontUnderlined(),
|
||||
bold = m_WParser->GetFontBold(),
|
||||
fsize = m_WParser->GetFontSize();
|
||||
const int fixed = m_WParser->GetFontFixed();
|
||||
const int italic = m_WParser->GetFontItalic();
|
||||
const int underlined = m_WParser->GetFontUnderlined();
|
||||
const int bold = m_WParser->GetFontBold();
|
||||
const int fsize = m_WParser->GetFontSize();
|
||||
const wxHtmlWinParser::WhitespaceMode whitespace =
|
||||
m_WParser->GetWhitespaceMode();
|
||||
|
||||
c = m_WParser->GetContainer();
|
||||
m_WParser->SetWhitespaceMode(wxHtmlWinParser::Whitespace_Pre);
|
||||
m_WParser->SetFontUnderlined(false);
|
||||
m_WParser->SetFontBold(false);
|
||||
m_WParser->SetFontItalic(false);
|
||||
@@ -103,12 +94,17 @@ TAG_HANDLER_BEGIN(PRE, "PRE")
|
||||
c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
|
||||
|
||||
wxString srcMid = m_WParser->GetInnerSource(tag);
|
||||
ParseInnerSource(HtmlizeWhitespaces(srcMid));
|
||||
|
||||
// setting Whitespace_Pre mode takes care of spaces and TABs, but
|
||||
// not linebreaks, so we have to translate them into <br> by
|
||||
// calling HtmlizeLinebreaks() here
|
||||
ParseInnerSource(HtmlizeLinebreaks(srcMid));
|
||||
|
||||
m_WParser->CloseContainer();
|
||||
m_WParser->CloseContainer();
|
||||
c = m_WParser->OpenContainer();
|
||||
|
||||
m_WParser->SetWhitespaceMode(whitespace);
|
||||
m_WParser->SetFontUnderlined(underlined);
|
||||
m_WParser->SetFontBold(bold);
|
||||
m_WParser->SetFontItalic(italic);
|
||||
|
@@ -52,7 +52,9 @@ wxHtmlWinParser::wxHtmlWinParser(wxHtmlWindowInterface *wndIface)
|
||||
m_InputEnc = wxFONTENCODING_ISO8859_1;
|
||||
m_OutputEnc = wxFONTENCODING_DEFAULT;
|
||||
#endif
|
||||
m_whitespaceMode = Whitespace_Normal;
|
||||
m_lastWordCell = NULL;
|
||||
m_posColumn = 0;
|
||||
|
||||
{
|
||||
int i, j, k, l, m;
|
||||
@@ -345,7 +347,17 @@ wxFSFile *wxHtmlWinParser::OpenURL(wxHtmlURLType type,
|
||||
|
||||
void wxHtmlWinParser::AddText(const wxString& txt)
|
||||
{
|
||||
register wxChar d;
|
||||
#define NBSP_UNICODE_VALUE (wxChar(160))
|
||||
#if !wxUSE_UNICODE
|
||||
if ( m_nbsp == 0 )
|
||||
m_nbsp = GetEntitiesParser()->GetCharForCode(NBSP_UNICODE_VALUE);
|
||||
#define CUR_NBSP_VALUE m_nbsp
|
||||
#else
|
||||
#define CUR_NBSP_VALUE NBSP_UNICODE_VALUE
|
||||
#endif
|
||||
|
||||
if ( m_whitespaceMode == Whitespace_Normal )
|
||||
{
|
||||
int templen = 0;
|
||||
|
||||
size_t lng = txt.length();
|
||||
@@ -358,7 +370,7 @@ void wxHtmlWinParser::AddText(const wxString& txt)
|
||||
wxChar *temp = m_tmpStrBuf;
|
||||
|
||||
wxString::const_iterator i = txt.begin();
|
||||
wxString::const_iterator end = txt.end();
|
||||
const wxString::const_iterator end = txt.end();
|
||||
|
||||
if (m_tmpLastWasSpace)
|
||||
{
|
||||
@@ -373,7 +385,7 @@ void wxHtmlWinParser::AddText(const wxString& txt)
|
||||
while (i < end)
|
||||
{
|
||||
size_t x = 0;
|
||||
d = temp[templen++] = *i;
|
||||
wxChar d = *i;
|
||||
if ((d == wxT('\n')) || (d == wxT('\r')) || (d == wxT(' ')) || (d == wxT('\t')))
|
||||
{
|
||||
++i, ++x;
|
||||
@@ -386,62 +398,125 @@ void wxHtmlWinParser::AddText(const wxString& txt)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
if (d == CUR_NBSP_VALUE)
|
||||
d = ' ';
|
||||
|
||||
temp[templen++] = d;
|
||||
|
||||
if (x)
|
||||
{
|
||||
temp[templen-1] = wxT(' ');
|
||||
DoAddText(temp, templen);
|
||||
FlushWordBuf(temp, templen);
|
||||
m_tmpLastWasSpace = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (templen && (templen > 1 || temp[0] != wxT(' ')))
|
||||
{
|
||||
DoAddText(temp, templen);
|
||||
FlushWordBuf(temp, templen);
|
||||
m_tmpLastWasSpace = false;
|
||||
}
|
||||
}
|
||||
else // m_whitespaceMode == Whitespace_Pre
|
||||
{
|
||||
if ( txt.find(CUR_NBSP_VALUE) != wxString::npos )
|
||||
{
|
||||
// we need to substitute spaces for here just like we
|
||||
// did in the Whitespace_Normal branch above
|
||||
wxString txt2(txt);
|
||||
txt2.Replace(CUR_NBSP_VALUE, ' ');
|
||||
AddPreBlock(txt2);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddPreBlock(txt);
|
||||
}
|
||||
|
||||
// don't eat any whitespace in <pre> block
|
||||
m_tmpLastWasSpace = false;
|
||||
}
|
||||
}
|
||||
|
||||
void wxHtmlWinParser::DoAddText(wxChar *temp, int& templen)
|
||||
void wxHtmlWinParser::FlushWordBuf(wxChar *buf, int& len)
|
||||
{
|
||||
#define NBSP_UNICODE_VALUE 160
|
||||
#if !wxUSE_UNICODE
|
||||
if ( m_nbsp == 0 )
|
||||
m_nbsp = GetEntitiesParser()->GetCharForCode(NBSP_UNICODE_VALUE);
|
||||
#define CUR_NBSP_VALUE m_nbsp
|
||||
#else
|
||||
#define CUR_NBSP_VALUE NBSP_UNICODE_VALUE
|
||||
#endif
|
||||
buf[len] = 0;
|
||||
|
||||
temp[templen] = 0;
|
||||
templen = 0;
|
||||
#if !wxUSE_UNICODE
|
||||
if (m_EncConv)
|
||||
m_EncConv->Convert(temp);
|
||||
m_EncConv->Convert(buf);
|
||||
#endif
|
||||
size_t len = wxStrlen(temp);
|
||||
for (size_t j = 0; j < len; j++)
|
||||
|
||||
AddWord(wxString(buf, len));
|
||||
|
||||
len = 0;
|
||||
}
|
||||
|
||||
void wxHtmlWinParser::AddWord(wxHtmlWordCell *word)
|
||||
{
|
||||
if (temp[j] == CUR_NBSP_VALUE)
|
||||
temp[j] = wxT(' ');
|
||||
ApplyStateToCell(word);
|
||||
|
||||
m_Container->InsertCell(word);
|
||||
word->SetPreviousWord(m_lastWordCell);
|
||||
m_lastWordCell = word;
|
||||
}
|
||||
|
||||
wxHtmlWordCell *c = new wxHtmlWordCell(temp, *(GetDC()));
|
||||
void wxHtmlWinParser::AddPreBlock(const wxString& text)
|
||||
{
|
||||
if ( text.find('\t') != wxString::npos )
|
||||
{
|
||||
wxString text2;
|
||||
text2.reserve(text.length());
|
||||
|
||||
ApplyStateToCell(c);
|
||||
const wxString::const_iterator end = text.end();
|
||||
wxString::const_iterator copyFrom = text.begin();
|
||||
size_t posFrom = 0;
|
||||
size_t pos = 0;
|
||||
int posColumn = m_posColumn;
|
||||
for ( wxString::const_iterator i = copyFrom; i != end; ++i, ++pos )
|
||||
{
|
||||
if ( *i == '\t' )
|
||||
{
|
||||
if ( copyFrom != i )
|
||||
text2.append(copyFrom, i);
|
||||
|
||||
m_Container->InsertCell(c);
|
||||
c->SetPreviousWord(m_lastWordCell);
|
||||
m_lastWordCell = c;
|
||||
const unsigned SPACES_PER_TAB = 8;
|
||||
const size_t expandTo = SPACES_PER_TAB - posColumn % SPACES_PER_TAB;
|
||||
text2.append(expandTo, ' ');
|
||||
|
||||
posColumn += expandTo;
|
||||
copyFrom = i + 1;
|
||||
posFrom = pos + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++posColumn;
|
||||
}
|
||||
}
|
||||
if ( copyFrom != text.end() )
|
||||
text2.append(copyFrom, text.end());
|
||||
|
||||
AddWord(new wxHtmlWordWithTabsCell(text2, text, m_posColumn, *(GetDC())));
|
||||
|
||||
m_posColumn = posColumn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no special formatting needed
|
||||
AddWord(text);
|
||||
m_posColumn += text.length();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wxHtmlContainerCell* wxHtmlWinParser::OpenContainer()
|
||||
{
|
||||
m_Container = new wxHtmlContainerCell(m_Container);
|
||||
m_Container->SetAlignHor(m_Align);
|
||||
m_posColumn = 0;
|
||||
m_tmpLastWasSpace = true;
|
||||
/* to avoid space being first character in paragraph */
|
||||
return m_Container;
|
||||
|
Reference in New Issue
Block a user