kate Library: katetextline.cpp Source File (kate Library)

| # kate Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# katetextline.cpp

    00001 /* This file is part of the KDE libraries
    00002    Copyright (C) 2001-2003 Christoph Cullmann <cullmann@kde.org>
    00003    Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
    00004
    00005    Based on:
    00006      KateTextLine : Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
    00007
    00008    This library is free software; you can redistribute it and/or
    00009    modify it under the terms of the GNU Library General Public
    00010    License version 2 as published by the Free Software Foundation.
    00011
    00012    This library is distributed in the hope that it will be useful,
    00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015    Library General Public License for more details.
    00016
    00017    You should have received a copy of the GNU Library General Public License
    00018    along with this library; see the file COPYING.LIB.  If not, write to
    00019    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00020    Boston, MA 02111-1307, USA.
    00021 */
    00022
    00023 #include "katetextline.h"
    00024 #include "katerenderer.h"
    00025
    00026 #include <qregexp.h>
    00027 #include <kglobal.h>
    00028 #include <kdebug.h>
    00029 #include <qstylesheet.h>
    00030
    00031 KateTextLine::KateTextLine ()
    00032   : m_flags(0)
    00033 {
    00034 }
    00035
    00036 KateTextLine::~KateTextLine()
    00037 {
    00038 }
    00039
    00040 void KateTextLine::insertText (uint pos, uint insLen, const QChar *insText, uchar *insAttribs)
    00041 {
    00042   // nothing to do
    00043   if (insLen == 0)
    00044     return;
    00045
    00046   // calc new textLen, store old
    00047   uint oldTextLen = m_text.length();
    00048   m_text.insert (pos, insText, insLen);
    00049   uint textLen = m_text.length();
    00050
    00051   // resize the array
    00052   m_attributes.resize (textLen);
    00053
    00054   // HA, insert behind text end, fill with spaces
    00055   if (pos >= oldTextLen)
    00056   {
    00057     for (uint z = oldTextLen; z < pos; z++)
    00058       m_attributes[z] = 0;
    00059   }
    00060   // HA, insert in text, move the old text behind pos
    00061   else if (oldTextLen > 0)
    00062   {
    00063     for (int z = oldTextLen -1; z >= (int) pos; z--)
    00064       m_attributes[z+insLen] = m_attributes[z];
    00065   }
    00066
    00067   // BUH, actually insert the new text
    00068   for (uint z = 0; z < insLen; z++)
    00069   {
    00070     if (insAttribs == 0)
    00071       m_attributes[z+pos] = 0;
    00072     else
    00073       m_attributes[z+pos] = insAttribs[z];
    00074   }
    00075 }
    00076
    00077 void KateTextLine::removeText (uint pos, uint delLen)
    00078 {
    00079   // nothing to do
    00080   if (delLen == 0)
    00081     return;
    00082
    00083   uint textLen = m_text.length();
    00084
    00085   if (textLen == 0)
    00086     return; // uh, again nothing real to do ;)
    00087
    00088   if (pos >= textLen)
    00089     return;
    00090
    00091   if ((pos + delLen) > textLen)
    00092     delLen = textLen - pos;
    00093
    00094   // BU, MOVE THE OLD TEXT AROUND
    00095   for (uint z = pos; z < textLen - delLen; z++)
    00096     m_attributes[z] = m_attributes[z+delLen];
    00097
    00098   m_text.remove (pos, delLen);
    00099   m_attributes.resize (m_text.length ());
    00100 }
    00101
    00102 void KateTextLine::truncate(uint newLen)
    00103 {
    00104   if (newLen < m_text.length())
    00105   {
    00106     m_text.truncate (newLen);
    00107     m_attributes.truncate (newLen);
    00108   }
    00109 }
    00110
    00111 int KateTextLine::nextNonSpaceChar(uint pos) const
    00112 {
    00113   for(int i = pos; i < (int)m_text.length(); i++)
    00114   {
    00115     if(!m_text[i].isSpace())
    00116       return i;
    00117   }
    00118
    00119   return -1;
    00120 }
    00121
    00122 int KateTextLine::previousNonSpaceChar(uint pos) const
    00123 {
    00124   if (pos >= m_text.length())
    00125     pos = m_text.length() - 1;
    00126
    00127   for(int i = pos; i >= 0; i--)
    00128   {
    00129     if(!m_text[i].isSpace())
    00130       return i;
    00131   }
    00132
    00133   return -1;
    00134 }
    00135
    00136 int KateTextLine::firstChar() const
    00137 {
    00138   return nextNonSpaceChar(0);
    00139 }
    00140
    00141 int KateTextLine::lastChar() const
    00142 {
    00143   return previousNonSpaceChar(m_text.length() - 1);
    00144 }
    00145
    00146 const QChar *KateTextLine::firstNonSpace() const
    00147 {
    00148   int first = firstChar();
    00149   return (first > -1) ? ((QChar*)m_text.unicode())+first : m_text.unicode();
    00150 }
    00151
    00152 uint KateTextLine::indentDepth (uint tabwidth) const
    00153 {
    00154   uint d = 0;
    00155
    00156   for(uint i = 0; i < m_text.length(); i++)
    00157   {
    00158     if(m_text[i].isSpace())
    00159     {
    00160       if (m_text[i] == QChar('\t'))
    00161         d += tabwidth - (d % tabwidth);
    00162       else
    00163         d++;
    00164     }
    00165     else
    00166       return d;
    00167   }
    00168
    00169   return d;
    00170 }
    00171
    00172 bool KateTextLine::stringAtPos(uint pos, const QString& match) const
    00173 {
    00174   if ((pos+match.length()) > m_text.length())
    00175     return false;
    00176
    00177   for (uint i=0; i < match.length(); i++)
    00178     if (m_text[i+pos] != match[i])
    00179       return false;
    00180
    00181   return true;
    00182 }
    00183
    00184 bool KateTextLine::startingWith(const QString& match) const
    00185 {
    00186   if (match.length() > m_text.length())
    00187     return false;
    00188
    00189   for (uint i=0; i < match.length(); i++)
    00190     if (m_text[i] != match[i])
    00191       return false;
    00192
    00193   return true;
    00194 }
    00195
    00196 bool KateTextLine::endingWith(const QString& match) const
    00197 {
    00198   if (match.length() > m_text.length())
    00199     return false;
    00200
    00201   uint start = m_text.length() - match.length();
    00202   for (uint i=0; i < match.length(); i++)
    00203     if (m_text[start+i] != match[i])
    00204       return false;
    00205
    00206   return true;
    00207 }
    00208
    00209 int KateTextLine::cursorX(uint pos, uint tabChars) const
    00210 {
    00211   uint x = 0;
    00212
    00213   for ( uint z = 0; z < kMin (pos, m_text.length()); z++)
    00214   {
    00215     if (m_text[z] == QChar('\t'))
    00216       x += tabChars - (x % tabChars);
    00217     else
    00218       x++;
    00219   }
    00220
    00221   return x;
    00222 }
    00223
    00224
    00225 uint KateTextLine::lengthWithTabs (uint tabChars) const
    00226 {
    00227   uint x = 0;
    00228
    00229   for ( uint z = 0; z < m_text.length(); z++)
    00230   {
    00231     if (m_text[z] == QChar('\t'))
    00232       x += tabChars - (x % tabChars);
    00233     else
    00234       x++;
    00235   }
    00236
    00237   return x;
    00238 }
    00239
    00240 bool KateTextLine::searchText (uint startCol, const QString &text, uint *foundAtCol, uint *matchLen, bool casesensitive, bool backwards)
    00241 {
    00242   int index;
    00243
    00244   if (backwards)
    00245   {
    00246     int col = startCol;
    00247     uint l = text.length();
    00248     // allow finding the string ending at eol
    00249     if ( col == m_text.length() ) startCol++;
    00250
    00251     do {
    00252       index = m_text.findRev( text, col, casesensitive );
    00253       col--;
    00254     } while ( col >= 0 && l + index >= startCol );
    00255   }
    00256   else
    00257     index = m_text.find (text, startCol, casesensitive);
    00258
    00259   if (index > -1)
    00260   {
    00261     if (foundAtCol)
    00262       (*foundAtCol) = index;
    00263     if (matchLen)
    00264       (*matchLen)=text.length();
    00265     return true;
    00266   }
    00267
    00268   return false;
    00269 }
    00270
    00271 bool KateTextLine::searchText (uint startCol, const QRegExp &regexp, uint *foundAtCol, uint *matchLen, bool backwards)
    00272 {
    00273   int index;
    00274
    00275   if (backwards)
    00276   {
    00277     int col = startCol;
    00278
    00279     // allow finding the string ending at eol
    00280     if ( col == m_text.length() ) startCol++;
    00281     do {
    00282       index = regexp.searchRev (m_text, col);
    00283       col--;
    00284     } while ( col >= 0 && regexp.matchedLength() + index >= (int)startCol );
    00285   }
    00286   else
    00287     index = regexp.search (m_text, startCol);
    00288
    00289   if (index > -1)
    00290   {
    00291     if (foundAtCol)
    00292       (*foundAtCol) = index;
    00293
    00294     if (matchLen)
    00295       (*matchLen)=regexp.matchedLength();
    00296     return true;
    00297   }
    00298
    00299   return false;
    00300 }
    00301
    00302 char *KateTextLine::dump (char *buf, bool withHighlighting) const
    00303 {
    00304   uint l = m_text.length();
    00305   char f = m_flags;
    00306
    00307   if (!withHighlighting)
    00308     f = f | KateTextLine::flagNoOtherData;
    00309
    00310   memcpy(buf, (char *) &f, 1);
    00311   buf += 1;
    00312
    00313   memcpy(buf, &l, sizeof(uint));
    00314   buf += sizeof(uint);
    00315
    00316   memcpy(buf, (char *) m_text.unicode(), sizeof(QChar)*l);
    00317   buf += sizeof(QChar) * l;
    00318
    00319   if (!withHighlighting)
    00320     return buf;
    00321
    00322   memcpy(buf, (char *)m_attributes.data(), sizeof(uchar) * l);
    00323   buf += sizeof (uchar) * l;
    00324
    00325   uint lctx = m_ctx.size();
    00326   uint lfold = m_foldingList.size();
    00327   uint lind = m_indentationDepth.size();
    00328
    00329   memcpy(buf, &lctx, sizeof(uint));
    00330   buf += sizeof(uint);
    00331
    00332   memcpy(buf, &lfold, sizeof(uint));
    00333   buf += sizeof(uint);
    00334
    00335   memcpy(buf, &lind, sizeof(uint));
    00336   buf += sizeof(uint);
    00337
    00338   memcpy(buf, (char *)m_ctx.data(), sizeof(short) * lctx);
    00339   buf += sizeof (short) * lctx;
    00340
    00341   memcpy(buf, (char *)m_foldingList.data(), sizeof(uint)*lfold);
    00342   buf += sizeof (uint) * lfold;
    00343
    00344   memcpy(buf, (char *)m_indentationDepth.data(), sizeof(unsigned short) * lind);
    00345   buf += sizeof (unsigned short) * lind;
    00346
    00347   return buf;
    00348 }
    00349
    00350 char *KateTextLine::restore (char *buf)
    00351 {
    00352   uint l = 0;
    00353   char f = 0;
    00354
    00355   memcpy((char *) &f, buf, 1);
    00356   buf += 1;
    00357
    00358   // text + context length read
    00359   memcpy((char *) &l, buf, sizeof(uint));
    00360   buf += sizeof(uint);
    00361
    00362   // text + attributes
    00363   m_text.setUnicode ((QChar *) buf, l);
    00364   buf += sizeof(QChar) * l;
    00365
    00366   // we just restore a KateTextLine from a buffer first time
    00367   if (f & KateTextLine::flagNoOtherData)
    00368   {
    00369     m_flags = 0;
    00370
    00371     if (f & KateTextLine::flagAutoWrapped)
    00372       m_flags = m_flags | KateTextLine::flagAutoWrapped;
    00373
    00374     // fill with clean empty attribs !
    00375     m_attributes.fill (0, l);
    00376
    00377     return buf;
    00378   }
    00379   else
    00380     m_flags = f;
    00381
    00382   m_attributes.duplicate ((uchar *) buf, l);
    00383   buf += sizeof(uchar) * l;
    00384
    00385   uint lctx = 0;
    00386   uint lfold = 0;
    00387   uint lind = 0;
    00388
    00389   memcpy((char *) &lctx, buf, sizeof(uint));
    00390   buf += sizeof(uint);
    00391
    00392   memcpy((char *) &lfold, buf, sizeof(uint));
    00393   buf += sizeof(uint);
    00394
    00395   memcpy((char *) &lind, buf, sizeof(uint));
    00396   buf += sizeof(uint);
    00397
    00398   m_ctx.duplicate ((short *) buf, lctx);
    00399   buf += sizeof(short) * lctx;
    00400
    00401   m_foldingList.duplicate ((uint *) buf, lfold);
    00402   buf += sizeof(uint)*lfold;
    00403
    00404   m_indentationDepth.duplicate ((unsigned short *) buf, lind);
    00405   buf += sizeof(unsigned short) * lind;
    00406
    00407   return buf;
    00408 }
    00409
    00410
    00411 void KateTextLine::stringAsHtml(uint startCol, uint length, KateRenderer *renderer, QTextStream *outputStream) const
    00412 {
    00413   if(length == 0) return;
    00414   // some variables :
    00415   bool previousCharacterWasBold = false;
    00416   bool previousCharacterWasItalic = false;
    00417   // when entering a new color, we'll close all the <b> & <i> tags,
    00418   // for HTML compliancy. that means right after that font tag, we'll
    00419   // need to reinitialize the <b> and <i> tags.
    00420   bool needToReinitializeTags = false;
    00421   QColor previousCharacterColor(0,0,0); // default color of HTML characters is black
    00422   QColor blackColor(0,0,0);
    00423 //  (*outputStream) << "<span style='color: #000000'>";
    00424
    00425
    00426   // for each character of the line : (curPos is the position in the line)
    00427   for (uint curPos=startCol;curPos<(length+startCol);curPos++)
    00428     {
    00429       KateAttribute* charAttributes = 0;
    00430
    00431       charAttributes = renderer->attribute(attribute(curPos));
    00432
    00433
    00434       //ASSERT(charAttributes != NULL);
    00435       // let's give the color for that character :
    00436       if ( (charAttributes->textColor() != previousCharacterColor))
    00437       {  // the new character has a different color :
    00438         // if we were in a bold or italic section, close it
    00439         if (previousCharacterWasBold)
    00440           (*outputStream) << "</b>";
    00441         if (previousCharacterWasItalic)
    00442           (*outputStream) << "</i>";
    00443
    00444         // close the previous font tag :
    00445     if(previousCharacterColor != blackColor)
    00446           (*outputStream) << "</span>";
    00447         // let's read that color :
    00448         int red, green, blue;
    00449         // getting the red, green, blue values of the color :
    00450         charAttributes->textColor().rgb(&red, &green, &blue);
    00451     if(!(red == 0 && green == 0 && blue == 0)) {
    00452           (*outputStream) << "<span style='color: #"
    00453               << ( (red < 0x10)?"0":"")  // need to put 0f, NOT f for instance. don't touch 1f.
    00454               << QString::number(red, 16) // html wants the hex value here (hence the 16)
    00455               << ( (green < 0x10)?"0":"")
    00456               << QString::number(green, 16)
    00457               << ( (blue < 0x10)?"0":"")
    00458               << QString::number(blue, 16)
    00459               << "'>";
    00460     }
    00461         // we need to reinitialize the bold/italic status, since we closed all the tags
    00462         needToReinitializeTags = true;
    00463       }
    00464       // bold status :
    00465       if ( (needToReinitializeTags && charAttributes->bold()) ||
    00466           (!previousCharacterWasBold && charAttributes->bold()) )
    00467         // we enter a bold section
    00468         (*outputStream) << "<b>";
    00469       if ( !needToReinitializeTags && (previousCharacterWasBold && !charAttributes->bold()) )
    00470         // we leave a bold section
    00471         (*outputStream) << "</b>";
    00472
    00473       // italic status :
    00474       if ( (needToReinitializeTags && charAttributes->italic()) ||
    00475            (!previousCharacterWasItalic && charAttributes->italic()) )
    00476         // we enter an italic section
    00477         (*outputStream) << "<i>";
    00478       if ( !needToReinitializeTags && (previousCharacterWasItalic && !charAttributes->italic()) )
    00479         // we leave an italic section
    00480         (*outputStream) << "</i>";
    00481
    00482       // write the actual character :
    00483       (*outputStream) << QStyleSheet::escape(QString(getChar(curPos)));
    00484
    00485       // save status for the next character :
    00486       previousCharacterWasItalic = charAttributes->italic();
    00487       previousCharacterWasBold = charAttributes->bold();
    00488       previousCharacterColor = charAttributes->textColor();
    00489       needToReinitializeTags = false;
    00490     }
    00491   // Be good citizens and close our tags
    00492   if (previousCharacterWasBold)
    00493     (*outputStream) << "</b>";
    00494   if (previousCharacterWasItalic)
    00495     (*outputStream) << "</i>";
    00496
    00497   if(previousCharacterColor != blackColor)
    00498     (*outputStream) << "</span>";
    00499 }
    00500
    00501 // kate: space-indent on; indent-width 2; replace-tabs on;

This file is part of the documentation for kate Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:36:38 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003