File indexing completed on 2025-01-19 04:23:30
0001 /* 0002 This file is part of Konsole, an X terminal. 0003 0004 Copyright 2006-2008 by Robert Knight <robertknight@gmail.com> 0005 0006 This program is free software; you can redistribute it and/or modify 0007 it under the terms of the GNU Lesser General Public License as published by 0008 the Free Software Foundation; either version 2 of the License, or 0009 (at your option) any later version. 0010 0011 This program is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 GNU General Public License for more details. 0015 0016 You should have received a copy of the GNU Lesser General Public License 0017 along with this program; if not, write to the Free Software 0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0019 02110-1301 USA. 0020 */ 0021 0022 // Own 0023 #include "TerminalCharacterDecoder.h" 0024 0025 // stdlib 0026 #include <cwctype> 0027 0028 // Qt 0029 #include <QTextStream> 0030 0031 // KDE 0032 //#include <kdebug.h> 0033 0034 // Konsole 0035 #include "konsole_wcwidth.h" 0036 0037 using namespace Konsole; 0038 PlainTextDecoder::PlainTextDecoder() 0039 : _output(0) 0040 , _includeTrailingWhitespace(true) 0041 , _recordLinePositions(false) 0042 { 0043 0044 } 0045 void PlainTextDecoder::setTrailingWhitespace(bool enable) 0046 { 0047 _includeTrailingWhitespace = enable; 0048 } 0049 bool PlainTextDecoder::trailingWhitespace() const 0050 { 0051 return _includeTrailingWhitespace; 0052 } 0053 void PlainTextDecoder::begin(QTextStream* output) 0054 { 0055 _output = output; 0056 if (!_linePositions.isEmpty()) 0057 _linePositions.clear(); 0058 } 0059 void PlainTextDecoder::end() 0060 { 0061 _output = 0; 0062 } 0063 0064 void PlainTextDecoder::setRecordLinePositions(bool record) 0065 { 0066 _recordLinePositions = record; 0067 } 0068 QList<int> PlainTextDecoder::linePositions() const 0069 { 0070 return _linePositions; 0071 } 0072 void PlainTextDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/ 0073 ) 0074 { 0075 Q_ASSERT( _output ); 0076 0077 if (_recordLinePositions && _output->string()) 0078 { 0079 int pos = _output->string()->count(); 0080 _linePositions << pos; 0081 } 0082 0083 //TODO should we ignore or respect the LINE_WRAPPED line property? 0084 0085 //note: we build up a QString and send it to the text stream rather writing into the text 0086 //stream a character at a time because it is more efficient. 0087 //(since QTextStream always deals with QStrings internally anyway) 0088 std::wstring plainText; 0089 plainText.reserve(count); 0090 0091 int outputCount = count; 0092 0093 // if inclusion of trailing whitespace is disabled then find the end of the 0094 // line 0095 if ( !_includeTrailingWhitespace ) 0096 { 0097 for (int i = count-1 ; i >= 0 ; i--) 0098 { 0099 if ( characters[i].character != L' ' ) 0100 break; 0101 else 0102 outputCount--; 0103 } 0104 } 0105 0106 for (int i=0;i<outputCount;) 0107 { 0108 plainText.push_back( characters[i].character ); 0109 i += qMax(1,konsole_wcwidth(characters[i].character)); 0110 } 0111 *_output << QString::fromStdWString(plainText); 0112 } 0113 0114 HTMLDecoder::HTMLDecoder() : 0115 _output(0) 0116 ,_colorTable(base_color_table) 0117 ,_innerSpanOpen(false) 0118 ,_lastRendition(DEFAULT_RENDITION) 0119 { 0120 0121 } 0122 0123 void HTMLDecoder::begin(QTextStream* output) 0124 { 0125 _output = output; 0126 0127 std::wstring text; 0128 0129 //open monospace span 0130 openSpan(text,QLatin1String("font-family:monospace")); 0131 0132 *output << QString::fromStdWString(text); 0133 } 0134 0135 void HTMLDecoder::end() 0136 { 0137 Q_ASSERT( _output ); 0138 0139 std::wstring text; 0140 0141 closeSpan(text); 0142 0143 *_output << QString::fromStdWString(text); 0144 0145 _output = 0; 0146 0147 } 0148 0149 //TODO: Support for LineProperty (mainly double width , double height) 0150 void HTMLDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/ 0151 ) 0152 { 0153 Q_ASSERT( _output ); 0154 0155 std::wstring text; 0156 0157 int spaceCount = 0; 0158 0159 for (int i=0;i<count;i++) 0160 { 0161 wchar_t ch(characters[i].character); 0162 0163 //check if appearance of character is different from previous char 0164 if ( characters[i].rendition != _lastRendition || 0165 characters[i].foregroundColor != _lastForeColor || 0166 characters[i].backgroundColor != _lastBackColor ) 0167 { 0168 if ( _innerSpanOpen ) 0169 closeSpan(text); 0170 0171 _lastRendition = characters[i].rendition; 0172 _lastForeColor = characters[i].foregroundColor; 0173 _lastBackColor = characters[i].backgroundColor; 0174 0175 //build up style string 0176 QString style; 0177 0178 bool useBold; 0179 ColorEntry::FontWeight weight = characters[i].fontWeight(_colorTable); 0180 if (weight == ColorEntry::UseCurrentFormat) 0181 useBold = _lastRendition & RE_BOLD; 0182 else 0183 useBold = weight == ColorEntry::Bold; 0184 0185 if (useBold) 0186 style.append(QLatin1String("font-weight:bold;")); 0187 0188 if ( _lastRendition & RE_UNDERLINE ) 0189 style.append(QLatin1String("font-decoration:underline;")); 0190 0191 //colours - a colour table must have been defined first 0192 if ( _colorTable ) 0193 { 0194 style.append( QString::fromLatin1("color:%1;").arg(_lastForeColor.color(_colorTable).name() ) ); 0195 0196 if (!characters[i].isTransparent(_colorTable)) 0197 { 0198 style.append( QString::fromLatin1("background-color:%1;").arg(_lastBackColor.color(_colorTable).name() ) ); 0199 } 0200 } 0201 0202 //open the span with the current style 0203 openSpan(text,style); 0204 _innerSpanOpen = true; 0205 } 0206 0207 //handle whitespace 0208 if (std::iswspace(ch)) 0209 spaceCount++; 0210 else 0211 spaceCount = 0; 0212 0213 0214 //output current character 0215 if (spaceCount < 2) 0216 { 0217 //escape HTML tag characters and just display others as they are 0218 if ( ch == '<' ) 0219 text.append(L"<"); 0220 else if (ch == '>') 0221 text.append(L">"); 0222 else 0223 text.push_back(ch); 0224 } 0225 else 0226 { 0227 text.append(L" "); //HTML truncates multiple spaces, so use a space marker instead 0228 } 0229 0230 } 0231 0232 //close any remaining open inner spans 0233 if ( _innerSpanOpen ) 0234 closeSpan(text); 0235 0236 //start new line 0237 text.append(L"<br>"); 0238 0239 *_output << QString::fromStdWString(text); 0240 } 0241 void HTMLDecoder::openSpan(std::wstring& text , const QString& style) 0242 { 0243 text.append( QString(QLatin1String("<span style=\"%1\">")).arg(style).toStdWString() ); 0244 } 0245 0246 void HTMLDecoder::closeSpan(std::wstring& text) 0247 { 0248 text.append(L"</span>"); 0249 } 0250 0251 void HTMLDecoder::setColorTable(const ColorEntry* table) 0252 { 0253 _colorTable = table; 0254 }