kate Library API Documentation

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;
KDE Logo
This file is part of the documentation for kate Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jul 2 13:11:23 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003