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.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:46:08 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003