1 /*
2 This file is part of Konsole, an X terminal.
3
4 Copyright (C) 2006, 2013 by Robert Knight <robertknight@gmail.com>
5
6 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301 USA.
22 */
23
24 // Own
25 #include "unix/TerminalCharacterDecoder.h"
26
27 // Qt
28 #include <QtCore/QTextStream>
29
PlainTextDecoder()30 PlainTextDecoder::PlainTextDecoder()
31 : _output(nullptr)
32 , _includeTrailingWhitespace(true)
33 {
34
35 }
setTrailingWhitespace(bool enable)36 void PlainTextDecoder::setTrailingWhitespace(bool enable)
37 {
38 _includeTrailingWhitespace = enable;
39 }
trailingWhitespace() const40 bool PlainTextDecoder::trailingWhitespace() const
41 {
42 return _includeTrailingWhitespace;
43 }
begin(QTextStream * output)44 void PlainTextDecoder::begin(QTextStream* output)
45 {
46 _output = output;
47 }
end()48 void PlainTextDecoder::end()
49 {
50 _output = nullptr;
51 }
decodeLine(const Character * const characters,int count,LineProperty)52 void PlainTextDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
53 )
54 {
55 Q_ASSERT( _output );
56
57 //TODO should we ignore or respect the LINE_WRAPPED line property?
58
59 //note: we build up a QString and send it to the text stream rather writing into the text
60 //stream a character at a time because it is more efficient.
61 //(since QTextStream always deals with QStrings internally anyway)
62 QString plainText;
63 plainText.reserve(count);
64
65 int outputCount = count;
66
67 // if inclusion of trailing whitespace is disabled then find the end of the
68 // line
69 if ( !_includeTrailingWhitespace )
70 {
71 for (int i = count-1 ; i >= 0 ; i--)
72 {
73 if ( characters[i].character != ' ' )
74 break;
75 else
76 outputCount--;
77 }
78 }
79
80 for (int i=0;i<outputCount;i++)
81 {
82 plainText.append( QChar(characters[i].character) );
83 }
84
85 *_output << plainText;
86 }
87
HTMLDecoder()88 HTMLDecoder::HTMLDecoder() :
89 _output(nullptr)
90 ,_colorTable(base_color_table)
91 ,_innerSpanOpen(false)
92 ,_lastRendition(DEFAULT_RENDITION)
93 {
94
95 }
96
begin(QTextStream * output)97 void HTMLDecoder::begin(QTextStream* output)
98 {
99 _output = output;
100
101 QString text;
102
103 //open monospace span
104 openSpan(text,"font-family:monospace");
105
106 *output << text;
107 }
108
end()109 void HTMLDecoder::end()
110 {
111 Q_ASSERT( _output );
112
113 QString text;
114
115 closeSpan(text);
116
117 *_output << text;
118
119 _output = nullptr;
120
121 }
122
123 //TODO: Support for LineProperty (mainly double width , double height)
decodeLine(const Character * const characters,int count,LineProperty)124 void HTMLDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
125 )
126 {
127 Q_ASSERT( _output );
128
129 QString text;
130
131 int spaceCount = 0;
132
133 for (int i=0;i<count;i++)
134 {
135 QChar ch(characters[i].character);
136
137 //check if appearance of character is different from previous char
138 if ( characters[i].rendition != _lastRendition ||
139 characters[i].foregroundColor != _lastForeColor ||
140 characters[i].backgroundColor != _lastBackColor )
141 {
142 if ( _innerSpanOpen )
143 closeSpan(text);
144
145 _lastRendition = characters[i].rendition;
146 _lastForeColor = characters[i].foregroundColor;
147 _lastBackColor = characters[i].backgroundColor;
148
149 //build up style string
150 QString style;
151
152 if ( _lastRendition & RE_BOLD ||
153 (_colorTable && characters[i].isBold(_colorTable)) )
154 style.append("font-weight:bold;");
155
156
157 if ( _lastRendition & RE_UNDERLINE )
158 style.append("font-decoration:underline;");
159
160 //colours - a colour table must have been defined first
161 if ( _colorTable )
162 {
163 style.append( QString("color:%1;").arg(_lastForeColor.color(_colorTable).name() ) );
164
165 if (!characters[i].isTransparent(_colorTable))
166 {
167 style.append( QString("background-color:%1;").arg(_lastBackColor.color(_colorTable).name() ) );
168 }
169 }
170
171 //open the span with the current style
172 openSpan(text,style);
173 _innerSpanOpen = true;
174 }
175
176 //handle whitespace
177 if (ch.isSpace())
178 spaceCount++;
179 else
180 spaceCount = 0;
181
182
183 //output current character
184 if (spaceCount < 2)
185 {
186 //escape HTML tag characters and just display others as they are
187 if ( ch == '<' )
188 text.append("<");
189 else if (ch == '>')
190 text.append(">");
191 else
192 text.append(ch);
193 }
194 else
195 {
196 text.append(" "); //HTML truncates multiple spaces, so use a space marker instead
197 }
198
199 }
200
201 //close any remaining open inner spans
202 if ( _innerSpanOpen )
203 closeSpan(text);
204
205 //start new line
206 text.append("<br>");
207
208 *_output << text;
209 }
210
openSpan(QString & text,const QString & style)211 void HTMLDecoder::openSpan(QString& text , const QString& style)
212 {
213 text.append( QString("<span style=\"%1\">").arg(style) );
214 }
215
closeSpan(QString & text)216 void HTMLDecoder::closeSpan(QString& text)
217 {
218 text.append("</span>");
219 }
220
setColorTable(const ColorEntry * table)221 void HTMLDecoder::setColorTable(const ColorEntry* table)
222 {
223 _colorTable = table;
224 }
225