kdecore Library API Documentation

kstringhandler.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999 Ian Zepp (icszepp@islc.net) 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 /* AIX needs strings.h for str*casecmp(), and our config.h loads it on AIX 00021 So we don't need to include strings.h explicitly */ 00022 #include "config.h" 00023 00024 #include "kstringhandler.h" 00025 #include "kglobal.h" 00026 00027 static void parsePythonRange( const QCString &range, uint &start, uint &end ) 00028 { 00029 const int colon = range.find( ':' ); 00030 if ( colon == -1 ) { 00031 start = range.toUInt(); 00032 end = start; 00033 } else if ( colon == int( range.length() - 1 ) ) { 00034 start = range.left( colon ).toUInt(); 00035 } else if ( colon == 0 ) { 00036 end = range.mid( 1 ).toUInt(); 00037 } else { 00038 start = range.left( colon ).toInt(); 00039 end = range.mid( colon + 1 ).toInt(); 00040 } 00041 } 00042 00043 QString KStringHandler::word( const QString &text , uint pos ) 00044 { 00045 return text.section( ' ', pos, pos ); 00046 } 00047 00048 QString KStringHandler::word( const QString &text , const char *range ) 00049 { 00050 // Format in: START:END 00051 // Note index starts a 0 (zero) 00052 // 00053 // 0: first word to end 00054 // 1:3 second to fourth words 00055 QStringList list = QStringList::split( " ", text , true ); 00056 QString tmp = ""; 00057 QString r = range; 00058 00059 if ( text.isEmpty() ) 00060 return tmp; 00061 00062 uint pos = 0, cnt = list.count(); 00063 parsePythonRange( range, pos, cnt ); 00064 00065 // 00066 // Extract words 00067 // 00068 int wordsToExtract = cnt-pos+1; 00069 QStringList::Iterator it = list.at( pos); 00070 00071 while ( (it != list.end()) && (wordsToExtract-- > 0)) 00072 { 00073 tmp += *it; 00074 tmp += " "; 00075 it++; 00076 } 00077 00078 return tmp.stripWhiteSpace(); 00079 } 00080 00081 // 00082 // Insertion and removal routines 00083 // 00084 QString KStringHandler::insword( const QString &text , const QString &word , uint pos ) 00085 { 00086 if ( text.isEmpty() ) 00087 return word; 00088 00089 if ( word.isEmpty() ) 00090 return text; 00091 00092 // Split words and add into list 00093 QStringList list = QStringList::split( " ", text, true ); 00094 00095 if ( pos >= list.count() ) 00096 list.append( word ); 00097 else 00098 list.insert( list.at(pos) , word ); 00099 00100 // Rejoin 00101 return list.join( " " ); 00102 } 00103 00104 QString KStringHandler::setword( const QString &text , const QString &word , uint pos ) 00105 { 00106 if ( text.isEmpty() ) 00107 return word; 00108 00109 if ( word.isEmpty() ) 00110 return text; 00111 00112 // Split words and add into list 00113 QStringList list = QStringList::split( " ", text, true ); 00114 00115 if ( pos >= list.count() ) 00116 list.append( word ); 00117 else 00118 { 00119 list.insert( list.remove( list.at(pos) ) , word ); 00120 } 00121 00122 // Rejoin 00123 return list.join( " " ); 00124 } 00125 00126 QString KStringHandler::remrange( const QString &text , const char *range ) 00127 { 00128 // Format in: START:END 00129 // Note index starts a 0 (zero) 00130 // 00131 // 0: first word to end 00132 // 1:3 second to fourth words 00133 QStringList list = QStringList::split( " ", text , true ); 00134 QString tmp = ""; 00135 QString r = range; 00136 00137 if ( text.isEmpty() ) 00138 return tmp; 00139 00140 uint pos = 0, cnt = list.count(); 00141 parsePythonRange( range, pos, cnt ); 00142 00143 // 00144 // Remove that range of words 00145 // 00146 int wordsToDelete = cnt-pos+1; 00147 QStringList::Iterator it = list.at( pos); 00148 00149 while ( (it != list.end()) && (wordsToDelete-- > 0)) 00150 it = list.remove( it ); 00151 00152 return list.join( " " ); 00153 } 00154 00155 QString KStringHandler::remword( const QString &text , uint pos ) 00156 { 00157 QString tmp = ""; 00158 00159 if ( text.isEmpty() ) 00160 return tmp; 00161 00162 // Split words and add into list 00163 QStringList list = QStringList::split( " ", text, true ); 00164 00165 if ( pos < list.count() ) 00166 list.remove( list.at( pos ) ); 00167 00168 // Rejoin 00169 return list.join( " " ); 00170 } 00171 00172 QString KStringHandler::remword( const QString &text , const QString &word ) 00173 { 00174 QString tmp = ""; 00175 00176 if ( text.isEmpty() ) 00177 return tmp; 00178 00179 if ( word.isEmpty() ) 00180 return text; 00181 00182 // Split words and add into list 00183 QStringList list = QStringList::split( " ", text, true ); 00184 00185 QStringList::Iterator it = list.find(word); 00186 00187 if (it != list.end()) 00188 list.remove( it ); 00189 00190 // Rejoin 00191 return list.join( " " ); 00192 } 00193 00194 // 00195 // Capitalization routines 00196 // 00197 QString KStringHandler::capwords( const QString &text ) 00198 { 00199 if ( text.isEmpty() ) { 00200 return text; 00201 } 00202 00203 const QString strippedText = text.stripWhiteSpace(); 00204 const QStringList words = capwords( QStringList::split( ' ', strippedText ) ); 00205 00206 QString result = text; 00207 result.replace( strippedText, words.join( " " ) ); 00208 return result; 00209 } 00210 00211 QStringList KStringHandler::capwords( const QStringList &list ) 00212 { 00213 QStringList tmp = list; 00214 for ( QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it ) { 00215 *it = ( *it )[ 0 ].upper() + ( *it ).mid( 1 ); 00216 } 00217 return tmp; 00218 } 00219 00220 // 00221 // Reverse routines 00222 // 00223 QString KStringHandler::reverse( const QString &text ) 00224 { 00225 QString tmp; 00226 00227 if ( text.isEmpty() ) 00228 return tmp; 00229 00230 QStringList list; 00231 list = QStringList::split( " ", text, true ); 00232 list = reverse( list ); 00233 00234 return list.join( " " ); 00235 } 00236 00237 QStringList KStringHandler::reverse( const QStringList &list ) 00238 { 00239 QStringList tmp; 00240 00241 if ( list.count() == 0 ) 00242 return tmp; 00243 00244 for ( QStringList::ConstIterator it= list.begin(); 00245 it != list.end(); 00246 it++) 00247 tmp.prepend( *it ); 00248 00249 return tmp; 00250 } 00251 00252 // 00253 // Left, Right, Center justification 00254 // 00255 QString KStringHandler::ljust( const QString &text , uint width ) 00256 { 00257 return text.stripWhiteSpace().leftJustify( width ); 00258 } 00259 00260 QString KStringHandler::rjust( const QString &text , uint width ) 00261 { 00262 return text.stripWhiteSpace().rightJustify( width ); 00263 } 00264 00265 QString KStringHandler::center( const QString &text , uint width ) 00266 { 00267 const QString s = text.stripWhiteSpace(); 00268 const unsigned int length = s.length(); 00269 if ( width <= length ) { 00270 return s; 00271 } 00272 00273 QString result; 00274 result.fill( ' ', ( width - length ) / 2 ); 00275 result += s; 00276 00277 return result.leftJustify( width ); 00278 } 00279 00280 QString KStringHandler::lsqueeze( const QString & str, uint maxlen ) 00281 { 00282 if (str.length() > maxlen) { 00283 int part = maxlen-3; 00284 return QString("..." + str.right(part)); 00285 } 00286 else return str; 00287 } 00288 00289 QString KStringHandler::csqueeze( const QString & str, uint maxlen ) 00290 { 00291 if (str.length() > maxlen && maxlen > 3) { 00292 int part = (maxlen-3)/2; 00293 return QString(str.left(part) + "..." + str.right(part)); 00294 } 00295 else return str; 00296 } 00297 00298 QString KStringHandler::rsqueeze( const QString & str, uint maxlen ) 00299 { 00300 if (str.length() > maxlen) { 00301 int part = maxlen-3; 00302 return QString(str.left(part) + "..."); 00303 } 00304 else return str; 00305 } 00306 00307 QString KStringHandler::lEmSqueeze(const QString &name, const QFontMetrics& fontMetrics, uint maxlen) 00308 { 00309 return lPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); 00310 } 00311 00312 QString KStringHandler::lPixelSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxPixels) 00313 { 00314 uint nameWidth = fontMetrics.width(name); 00315 00316 if (maxPixels < nameWidth) 00317 { 00318 QString tmp = name; 00319 const uint em = fontMetrics.maxWidth(); 00320 maxPixels -= fontMetrics.width("..."); 00321 00322 while (maxPixels < nameWidth && !tmp.isEmpty()) 00323 { 00324 int delta = (nameWidth - maxPixels) / em; 00325 delta = kClamp(delta, 1, delta); // no max 00326 00327 tmp.remove(0, delta); 00328 nameWidth = fontMetrics.width(tmp); 00329 } 00330 00331 return ("..." + tmp); 00332 } 00333 00334 return name; 00335 } 00336 00337 QString KStringHandler::cEmSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxlen) 00338 { 00339 return cPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); 00340 } 00341 00342 QString KStringHandler::cPixelSqueeze(const QString& s, const QFontMetrics& fm, uint width) 00343 { 00344 if ( s.isEmpty() || uint( fm.width( s ) ) <= width ) { 00345 return s; 00346 } 00347 00348 const unsigned int length = s.length(); 00349 if ( length == 2 ) { 00350 return s; 00351 } 00352 00353 const int maxWidth = width - fm.width( '.' ) * 3; 00354 if ( maxWidth <= 0 ) { 00355 return "..."; 00356 } 00357 00358 unsigned int leftIdx = 0, rightIdx = length; 00359 unsigned int leftWidth = fm.charWidth( s, leftIdx++ ); 00360 unsigned int rightWidth = fm.charWidth( s, --rightIdx ); 00361 while ( leftWidth + rightWidth < uint( maxWidth ) ) { 00362 while ( leftWidth <= rightWidth && leftWidth + rightWidth < uint( maxWidth ) ) { 00363 leftWidth += fm.charWidth( s, leftIdx++ ); 00364 } 00365 while ( rightWidth <= leftWidth && leftWidth + rightWidth < uint( maxWidth ) ) { 00366 rightWidth += fm.charWidth( s, --rightIdx ); 00367 } 00368 } 00369 00370 if ( leftWidth > rightWidth ) { 00371 --leftIdx; 00372 } else { 00373 ++rightIdx; 00374 } 00375 00376 rightIdx = length - rightIdx; 00377 if ( leftIdx == 0 && rightIdx == 1 || leftIdx == 1 && rightIdx == 0 ) { 00378 return "..."; 00379 } 00380 00381 return s.left( leftIdx ) + "..." + s.right( rightIdx ); 00382 } 00383 00384 QString KStringHandler::rEmSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxlen) 00385 { 00386 return rPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); 00387 } 00388 00389 QString KStringHandler::rPixelSqueeze(const QString& name, const QFontMetrics& fontMetrics, uint maxPixels) 00390 { 00391 uint nameWidth = fontMetrics.width(name); 00392 00393 if (maxPixels < nameWidth) 00394 { 00395 QString tmp = name; 00396 const uint em = fontMetrics.maxWidth(); 00397 maxPixels -= fontMetrics.width("..."); 00398 00399 while (maxPixels < nameWidth && !tmp.isEmpty()) 00400 { 00401 int length = tmp.length(); 00402 int delta = (nameWidth - maxPixels) / em; 00403 delta = kClamp(delta, 1, length) ; 00404 00405 tmp.remove(length - delta, delta); 00406 nameWidth = fontMetrics.width(tmp); 00407 } 00408 00409 return (tmp + "..."); 00410 } 00411 00412 return name; 00413 } 00414 00416 00417 bool KStringHandler::matchFileName( const QString& filename, const QString& pattern ) 00418 { 00419 int len = filename.length(); 00420 int pattern_len = pattern.length(); 00421 00422 if (!pattern_len) 00423 return false; 00424 00425 // Patterns like "Makefile*" 00426 if ( pattern[ pattern_len - 1 ] == '*' && len + 1 >= pattern_len ) { 00427 if ( pattern[ 0 ] == '*' ) 00428 { 00429 return filename.find(pattern.mid(1, pattern_len - 2)) != -1; 00430 } 00431 00432 const QChar *c1 = pattern.unicode(); 00433 const QChar *c2 = filename.unicode(); 00434 int cnt = 1; 00435 while ( cnt < pattern_len && *c1++ == *c2++ ) 00436 ++cnt; 00437 return cnt == pattern_len; 00438 } 00439 00440 // Patterns like "*~", "*.extension" 00441 if ( pattern[ 0 ] == '*' && len + 1 >= pattern_len ) 00442 { 00443 const QChar *c1 = pattern.unicode() + pattern_len - 1; 00444 const QChar *c2 = filename.unicode() + len - 1; 00445 int cnt = 1; 00446 while ( cnt < pattern_len && *c1-- == *c2-- ) 00447 ++cnt; 00448 return cnt == pattern_len; 00449 } 00450 00451 // Patterns like "Makefile" 00452 return ( filename == pattern ); 00453 } 00454 00455 QStringList 00456 KStringHandler::perlSplit(const QString & sep, const QString & s, uint max) 00457 { 00458 bool ignoreMax = 0 == max; 00459 00460 QStringList l; 00461 00462 int searchStart = 0; 00463 00464 int tokenStart = s.find(sep, searchStart); 00465 00466 while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) 00467 { 00468 if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) 00469 l << s.mid(searchStart, tokenStart - searchStart); 00470 00471 searchStart = tokenStart + sep.length(); 00472 tokenStart = s.find(sep, searchStart); 00473 } 00474 00475 if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) 00476 l << s.mid(searchStart, s.length() - searchStart); 00477 00478 return l; 00479 } 00480 00481 QStringList 00482 KStringHandler::perlSplit(const QChar & sep, const QString & s, uint max) 00483 { 00484 bool ignoreMax = 0 == max; 00485 00486 QStringList l; 00487 00488 int searchStart = 0; 00489 00490 int tokenStart = s.find(sep, searchStart); 00491 00492 while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) 00493 { 00494 if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) 00495 l << s.mid(searchStart, tokenStart - searchStart); 00496 00497 searchStart = tokenStart + 1; 00498 tokenStart = s.find(sep, searchStart); 00499 } 00500 00501 if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) 00502 l << s.mid(searchStart, s.length() - searchStart); 00503 00504 return l; 00505 } 00506 00507 QStringList 00508 KStringHandler::perlSplit(const QRegExp & sep, const QString & s, uint max) 00509 { 00510 bool ignoreMax = 0 == max; 00511 00512 QStringList l; 00513 00514 int searchStart = 0; 00515 int tokenStart = sep.search(s, searchStart); 00516 int len = sep.matchedLength(); 00517 00518 while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) 00519 { 00520 if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) 00521 l << s.mid(searchStart, tokenStart - searchStart); 00522 00523 searchStart = tokenStart + len; 00524 tokenStart = sep.search(s, searchStart); 00525 len = sep.matchedLength(); 00526 } 00527 00528 if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) 00529 l << s.mid(searchStart, s.length() - searchStart); 00530 00531 return l; 00532 } 00533 00534 QString 00535 KStringHandler::tagURLs( const QString& text ) 00536 { 00537 /*static*/ QRegExp urlEx("(www\\.(?!\\.)|(fish|(f|ht)tp(|s))://)[\\d\\w\\./,:_~\\?=&;#@\\-\\+\\%]+[\\d\\w/]"); 00538 00539 QString richText( text ); 00540 int urlPos = 0, urlLen; 00541 while ((urlPos = urlEx.search(richText, urlPos)) >= 0) 00542 { 00543 urlLen = urlEx.matchedLength(); 00544 QString href = richText.mid( urlPos, urlLen ); 00545 // Qt doesn't support (?<=pattern) so we do it here 00546 if((urlPos > 0) && richText[urlPos-1].isLetterOrNumber()){ 00547 urlPos++; 00548 continue; 00549 } 00550 // Don't use QString::arg since %01, %20, etc could be in the string 00551 QString anchor = "<a href=\"" + href + "\">" + href + "</a>"; 00552 richText.replace( urlPos, urlLen, anchor ); 00553 00554 00555 urlPos += anchor.length(); 00556 } 00557 return richText; 00558 } 00559 00560 QString KStringHandler::obscure( const QString &str ) 00561 { 00562 QString result; 00563 const QChar *unicode = str.unicode(); 00564 for ( uint i = 0; i < str.length(); ++i ) 00565 result += ( unicode[ i ].unicode() < 0x20 ) ? unicode[ i ] : 00566 QChar( 0x1001F - unicode[ i ].unicode() ); 00567 00568 return result; 00569 } 00570 00571 bool KStringHandler::isUtf8(const char *buf) 00572 { 00573 int i, n; 00574 register unsigned char c; 00575 bool gotone = false; 00576 00577 if (!buf) 00578 return true; // whatever, just don't crash 00579 00580 #define F 0 /* character never appears in text */ 00581 #define T 1 /* character appears in plain ASCII text */ 00582 #define I 2 /* character appears in ISO-8859 text */ 00583 #define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */ 00584 00585 static const unsigned char text_chars[256] = { 00586 /* BEL BS HT LF FF CR */ 00587 F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */ 00588 /* ESC */ 00589 F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */ 00590 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */ 00591 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */ 00592 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */ 00593 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */ 00594 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */ 00595 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */ 00596 /* NEL */ 00597 X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */ 00598 X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */ 00599 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */ 00600 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */ 00601 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */ 00602 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */ 00603 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */ 00604 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */ 00605 }; 00606 00607 /* *ulen = 0; */ 00608 for (i = 0; (c = buf[i]); i++) { 00609 if ((c & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */ 00610 /* 00611 * Even if the whole file is valid UTF-8 sequences, 00612 * still reject it if it uses weird control characters. 00613 */ 00614 00615 if (text_chars[c] != T) 00616 return false; 00617 00618 } else if ((c & 0x40) == 0) { /* 10xxxxxx never 1st byte */ 00619 return false; 00620 } else { /* 11xxxxxx begins UTF-8 */ 00621 int following; 00622 00623 if ((c & 0x20) == 0) { /* 110xxxxx */ 00624 following = 1; 00625 } else if ((c & 0x10) == 0) { /* 1110xxxx */ 00626 following = 2; 00627 } else if ((c & 0x08) == 0) { /* 11110xxx */ 00628 following = 3; 00629 } else if ((c & 0x04) == 0) { /* 111110xx */ 00630 following = 4; 00631 } else if ((c & 0x02) == 0) { /* 1111110x */ 00632 following = 5; 00633 } else 00634 return false; 00635 00636 for (n = 0; n < following; n++) { 00637 i++; 00638 if (!(c = buf[i])) 00639 goto done; 00640 00641 if ((c & 0x80) == 0 || (c & 0x40)) 00642 return false; 00643 } 00644 gotone = true; 00645 } 00646 } 00647 done: 00648 return gotone; /* don't claim it's UTF-8 if it's all 7-bit */ 00649 } 00650 00651 #undef F 00652 #undef T 00653 #undef I 00654 #undef X 00655 00656 QString KStringHandler::from8Bit( const char *str ) 00657 { 00658 if (!str) 00659 return QString::null; 00660 if (!*str) { 00661 static const QString &emptyString = KGlobal::staticQString(""); 00662 return emptyString; 00663 } 00664 return KStringHandler::isUtf8( str ) ? 00665 QString::fromUtf8( str ) : 00666 QString::fromLocal8Bit( str ); 00667 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:03:33 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003