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("&lt;");
189 			else if (ch == '>')
190 					text.append("&gt;");
191 			else
192 					text.append(ch);
193 		}
194 		else
195 		{
196 			text.append("&nbsp;"); //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