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"&lt;");
0220             else if (ch == '>')
0221                     text.append(L"&gt;");
0222             else
0223                     text.push_back(ch);
0224         }
0225         else
0226         {
0227             text.append(L"&nbsp;"); //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 }