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.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Nov 27 13:41:23 2004 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003