lib Library API Documentation

koparagcounter.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Shaheed Haque <srhaque@iee.org>
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 #include "koparagcounter.h"
00021 #include "kozoomhandler.h"
00022 #include "kotextformat.h"
00023 #include "kotextdocument.h"
00024 #include <kdebug.h>
00025 #include <qdom.h>
00026 
00027 static KoTextParag * const INVALID_PARAG = (KoTextParag *)-1;
00028 
00029 KoParagCounter::KoParagCounter()
00030 {
00031     m_numbering = NUM_NONE;
00032     m_style = STYLE_NONE;
00033     m_depth = 0;
00034     m_startNumber = 1;
00035     m_displayLevels = 1;
00036     m_restartCounter = false;
00037     m_customBulletChar = QChar( '-' );
00038     m_customBulletFont = QString::null;
00039     m_align = Qt::AlignAuto;
00040     invalidate();
00041 }
00042 
00043 bool KoParagCounter::operator==( const KoParagCounter & c2 ) const
00044 {
00045     // ## This is kinda wrong. Unused fields (depending on the counter style) shouldn't be compared.
00046     return (m_numbering==c2.m_numbering &&
00047             m_style==c2.m_style &&
00048             m_depth==c2.m_depth &&
00049             m_startNumber==c2.m_startNumber &&
00050             m_displayLevels==c2.m_displayLevels &&
00051             m_restartCounter==c2.m_restartCounter &&
00052             m_prefix==c2.m_prefix &&
00053             m_suffix==c2.m_suffix &&
00054             m_customBulletChar==c2.m_customBulletChar &&
00055             m_customBulletFont==c2.m_customBulletFont &&
00056             m_align==c2.m_align &&
00057             m_custom==c2.m_custom);
00058 
00059 }
00060 
00061 QString KoParagCounter::custom() const
00062 {
00063     return m_custom;
00064 }
00065 
00066 QChar KoParagCounter::customBulletCharacter() const
00067 {
00068     return m_customBulletChar;
00069 }
00070 
00071 QString KoParagCounter::customBulletFont() const
00072 {
00073     return m_customBulletFont;
00074 }
00075 
00076 unsigned int KoParagCounter::depth() const
00077 {
00078     return m_depth;
00079 }
00080 
00081 void KoParagCounter::invalidate()
00082 {
00083     m_cache.number = -1;
00084     m_cache.text = QString::null;
00085     m_cache.width = -1;
00086     m_cache.parent = INVALID_PARAG;
00087     m_cache.counterFormat = 0;
00088 }
00089 
00090 bool KoParagCounter::isBullet( Style style ) // static
00091 {
00092     switch ( style )
00093     {
00094     case STYLE_DISCBULLET:
00095     case STYLE_SQUAREBULLET:
00096     case STYLE_BOXBULLET:
00097     case STYLE_CIRCLEBULLET:
00098     case STYLE_CUSTOMBULLET:
00099         return true;
00100     default:
00101         return false;
00102     }
00103 }
00104 
00105 bool KoParagCounter::isBullet() const
00106 {
00107     return isBullet( static_cast<Style>(m_style) );
00108 }
00109 
00110 void KoParagCounter::load( QDomElement & element )
00111 {
00112     m_numbering = static_cast<Numbering>( element.attribute("numberingtype", "2").toInt() );
00113     m_style = static_cast<Style>( element.attribute("type").toInt() );
00114     // Old docs have this:
00115     if ( (Numbering)m_numbering == NUM_LIST && (Style)m_style == STYLE_NONE )
00116         m_numbering = NUM_NONE;
00117     m_depth = element.attribute("depth").toInt();
00118     m_customBulletChar = QChar( element.attribute("bullet").toInt() );
00119     m_prefix = element.attribute("lefttext");
00120     if ( m_prefix.lower() == "(null)" ) // very old kword thing
00121         m_prefix = QString::null;
00122     m_suffix = element.attribute("righttext");
00123     if ( m_suffix.lower() == "(null)" )
00124         m_suffix = QString::null;
00125     QString s = element.attribute("start");
00126     if ( s.isEmpty() )
00127         m_startNumber = 1;
00128     else if ( s[0].isDigit() )
00129         m_startNumber = s.toInt();
00130     else // support for very-old files
00131         m_startNumber = s.lower()[0].latin1() - 'a' + 1;
00132     s = element.attribute("display-levels");
00133     if ( !s.isEmpty() )
00134         m_displayLevels = QMIN( s.toInt(), m_depth+1 ); // can't be > depth+1
00135     else // Not specified -> compat with koffice-1.2: make equal to depth+1
00136         m_displayLevels = m_depth+1;
00137     m_customBulletFont = element.attribute("bulletfont");
00138     m_custom = element.attribute("customdef");
00139     m_align = element.attribute("align", "0").toInt(); //AlignAuto as defeult
00140     QString restart = element.attribute("restart");
00141     m_restartCounter = (restart == "true") || (restart == "1");
00142     invalidate();
00143 }
00144 
00145 int KoParagCounter::number( const KoTextParag *paragraph )
00146 {
00147     // Return cached value if possible.
00148     if ( m_cache.number != -1 )
00149         return m_cache.number;
00150 
00151     // Should we start a new list?
00152     if ( m_restartCounter ) {
00153         m_cache.number = m_startNumber;
00154         return m_startNumber;
00155     }
00156 
00157     // Go looking for another paragraph at the same level or higher level.
00158     // (This code shares logic with parent())
00159     KoTextParag *otherParagraph = paragraph->prev();
00160     KoParagCounter *otherCounter;
00161 
00162     switch ( m_numbering )
00163     {
00164     case NUM_NONE:
00165         // This should not occur!
00166     case NUM_FOOTNOTE:
00167         m_cache.number = 0;
00168         break;
00169     case NUM_CHAPTER:
00170         m_cache.number = m_startNumber;
00171         // Go upwards...
00172         while ( otherParagraph )
00173         {
00174             otherCounter = otherParagraph->counter();
00175             if ( otherCounter &&               // ...look at numbered paragraphs only
00176                 ( (Numbering)otherCounter->m_numbering == NUM_CHAPTER ) &&     // ...same number type.
00177                 ( otherCounter->m_depth <= m_depth ) )        // ...same or higher level.
00178             {
00179                 if ( ( otherCounter->m_depth == m_depth ) &&
00180                    ( otherCounter->m_style == m_style ) )
00181                 {
00182                     // Found a preceding paragraph of exactly our type!
00183                     m_cache.number = otherCounter->number( otherParagraph ) + 1;
00184                 }
00185                 else
00186                 {
00187                     // Found a preceding paragraph of higher level!
00188                     m_cache.number = m_startNumber;
00189                 }
00190                 break;
00191             }
00192             otherParagraph = otherParagraph->prev();
00193         }
00194         break;
00195     case NUM_LIST:
00196         m_cache.number = m_startNumber;
00197         // Go upwards...
00198         while ( otherParagraph )
00199         {
00200             otherCounter = otherParagraph->counter();
00201             if ( otherCounter )                                         // look at numbered paragraphs only
00202             {
00203                 if ( ( (Numbering)otherCounter->m_numbering == NUM_LIST ) &&       // ...same number type.
00204                      !isBullet( static_cast<Style>(otherCounter->m_style) ) &&    // ...not a bullet
00205                     ( otherCounter->m_depth <= m_depth ) )    // ...same or higher level.
00206                 {
00207                     if ( ( otherCounter->m_depth == m_depth ) &&
00208                        ( otherCounter->m_style == m_style ) )
00209                     {
00210                         // Found a preceding paragraph of exactly our type!
00211                         m_cache.number = otherCounter->number( otherParagraph ) + 1;
00212                     }
00213                     else
00214                     {
00215                         // Found a preceding paragraph of higher level!
00216                         m_cache.number = m_startNumber;
00217                     }
00218                     break;
00219                 }
00220                 else
00221                 if ( (Numbering)otherCounter->m_numbering == NUM_CHAPTER )        // ...heading number type.
00222                 {
00223                     m_cache.number = m_startNumber;
00224                     break;
00225                 }
00226             }
00227 /*            else
00228             {
00229                 // There is no counter at all.
00230                 m_cache.number = m_startNumber;
00231                 break;
00232             }*/
00233             otherParagraph = otherParagraph->prev();
00234         }
00235         break;
00236     }
00237     return m_cache.number;
00238 }
00239 
00240 KoParagCounter::Numbering KoParagCounter::numbering() const
00241 {
00242     return static_cast<Numbering>(m_numbering);
00243 }
00244 
00245 // Go looking for another paragraph at a higher level.
00246 KoTextParag *KoParagCounter::parent( const KoTextParag *paragraph )
00247 {
00248     // Return cached value if possible.
00249     if ( m_cache.parent != INVALID_PARAG )
00250         return m_cache.parent;
00251 
00252     KoTextParag *otherParagraph = paragraph->prev();
00253     KoParagCounter *otherCounter;
00254 
00255     // (This code shares logic with number())
00256     switch ( (Numbering)m_numbering )
00257     {
00258     case NUM_NONE:
00259         // This should not occur!
00260     case NUM_FOOTNOTE:
00261         otherParagraph = 0L;
00262         break;
00263     case NUM_CHAPTER:
00264         // Go upwards while...
00265         while ( otherParagraph )
00266         {
00267             otherCounter = otherParagraph->counter();
00268             if ( otherCounter &&                                        // ...numbered paragraphs.
00269                 ( (Numbering)otherCounter->m_numbering == NUM_CHAPTER ) &&         // ...same number type.
00270                 ( otherCounter->m_depth < m_depth ) )         // ...higher level.
00271             {
00272                 break;
00273             }
00274             otherParagraph = otherParagraph->prev();
00275         }
00276         break;
00277     case NUM_LIST:
00278         // Go upwards while...
00279         while ( otherParagraph )
00280         {
00281             otherCounter = otherParagraph->counter();
00282             if ( otherCounter )                                         // ...numbered paragraphs.
00283             {
00284                 if ( ( (Numbering)otherCounter->m_numbering == NUM_LIST ) &&       // ...same number type.
00285                      !isBullet( static_cast<Style>(otherCounter->m_style) ) &&    // ...not a bullet
00286                     ( otherCounter->m_depth < m_depth ) )     // ...higher level.
00287                 {
00288                     break;
00289                 }
00290                 else
00291                 if ( (Numbering)otherCounter->m_numbering == NUM_CHAPTER )         // ...heading number type.
00292                 {
00293                     otherParagraph = 0L;
00294                     break;
00295                 }
00296             }
00297             otherParagraph = otherParagraph->prev();
00298         }
00299         break;
00300     }
00301     m_cache.parent = otherParagraph;
00302     return m_cache.parent;
00303 }
00304 
00305 QString KoParagCounter::prefix() const
00306 {
00307     return m_prefix;
00308 }
00309 
00310 void KoParagCounter::save( QDomElement & element )
00311 {
00312     element.setAttribute( "type", static_cast<int>( m_style ) );
00313     element.setAttribute( "depth", m_depth );
00314     if ( (Style)m_style == STYLE_CUSTOMBULLET )
00315     {
00316         element.setAttribute( "bullet", m_customBulletChar.unicode() );
00317         if ( !m_customBulletFont.isEmpty() )
00318             element.setAttribute( "bulletfont", m_customBulletFont );
00319     }
00320     if ( !m_prefix.isEmpty() )
00321         element.setAttribute( "lefttext", m_prefix );
00322     if ( !m_suffix.isEmpty() )
00323         element.setAttribute( "righttext", m_suffix );
00324     if ( m_startNumber != 1 )
00325         element.setAttribute( "start", m_startNumber );
00326     //if ( m_displayLevels != m_depth ) // see load()
00327         element.setAttribute( "display-levels", m_displayLevels );
00328     // Don't need to save NUM_FOOTNOTE, it's updated right after loading
00329     if ( (Numbering)m_numbering != NUM_NONE && (Numbering)m_numbering != NUM_FOOTNOTE )
00330         element.setAttribute( "numberingtype", static_cast<int>( m_numbering ) );
00331     if ( !m_custom.isEmpty() )
00332         element.setAttribute( "customdef", m_custom );
00333     if ( m_restartCounter )
00334         element.setAttribute( "restart", "true" );
00335     if ( !m_cache.text.isEmpty() )
00336         element.setAttribute( "text", m_cache.text );
00337     element.setAttribute( "align", m_align );
00338 }
00339 
00340 void KoParagCounter::setCustom( QString c )
00341 {
00342     m_custom = c;
00343     invalidate();
00344 }
00345 
00346 void KoParagCounter::setCustomBulletCharacter( QChar c )
00347 {
00348     m_customBulletChar = c;
00349     invalidate();
00350 }
00351 
00352 void KoParagCounter::setCustomBulletFont( QString f )
00353 {
00354     m_customBulletFont = f;
00355     invalidate();
00356 }
00357 
00358 void KoParagCounter::setDepth( unsigned int d )
00359 {
00360     m_depth = d;
00361     invalidate();
00362 }
00363 
00364 void KoParagCounter::setNumbering( Numbering n )
00365 {
00366     m_numbering = n;
00367     invalidate();
00368 }
00369 
00370 void KoParagCounter::setPrefix( QString p )
00371 {
00372     m_prefix = p;
00373     invalidate();
00374 }
00375 void KoParagCounter::setStartNumber( int s )
00376 {
00377     m_startNumber = s;
00378     invalidate();
00379 }
00380 
00381 void KoParagCounter::setDisplayLevels( int l )
00382 {
00383     m_displayLevels = l;
00384     invalidate();
00385 }
00386 
00387 void KoParagCounter::setAlignment( int a )
00388 {
00389     m_align = a;
00390     invalidate();
00391 }
00392 
00393 void KoParagCounter::setStyle( Style s )
00394 {
00395     m_style = s;
00396     invalidate();
00397 }
00398 
00399 void KoParagCounter::setSuffix( QString s )
00400 {
00401     m_suffix = s;
00402     invalidate();
00403 }
00404 
00405 int KoParagCounter::startNumber() const
00406 {
00407     return m_startNumber;
00408 }
00409 
00410 int KoParagCounter::displayLevels() const
00411 {
00412     return m_displayLevels;
00413 }
00414 
00415 int KoParagCounter::alignment() const
00416 {
00417     return m_align;
00418 }
00419 
00420 KoParagCounter::Style KoParagCounter::style() const
00421 {
00422     return static_cast<Style>(m_style);
00423 }
00424 
00425 QString KoParagCounter::suffix() const
00426 {
00427     return m_suffix;
00428 }
00429 
00430 bool KoParagCounter::restartCounter() const
00431 {
00432     return m_restartCounter;
00433 }
00434 
00435 void KoParagCounter::setRestartCounter( bool restart )
00436 {
00437     m_restartCounter = restart;
00438     invalidate();
00439 }
00440 
00441 // Return the text for that level only
00442 QString KoParagCounter::levelText( const KoTextParag *paragraph )
00443 {
00444     bool bullet = isBullet( static_cast<Style>(m_style) );
00445 
00446     if ( bullet && (Numbering)m_numbering == NUM_CHAPTER ) {
00447         // Shome mishtake surely! (not sure how it can happen though)
00448         m_style = STYLE_NUM;
00449         bullet = false;
00450     }
00451 
00452     QString text;
00453     if ( !bullet )
00454     {
00455         // Ensure paragraph number is valid.
00456         number( paragraph );
00457 
00458         switch ( m_style )
00459         {
00460         case STYLE_NONE:
00461         if ( (Numbering)m_numbering == NUM_LIST )
00462             text = ' ';
00463         break;
00464         case STYLE_NUM:
00465             text.setNum( m_cache.number );
00466             break;
00467         case STYLE_ALPHAB_L:
00468             text = makeAlphaLowerNumber( m_cache.number );
00469             break;
00470         case STYLE_ALPHAB_U:
00471             text = makeAlphaUpperNumber( m_cache.number );
00472             break;
00473         case STYLE_ROM_NUM_L:
00474             text = makeRomanNumber( m_cache.number ).lower();
00475             break;
00476         case STYLE_ROM_NUM_U:
00477             text = makeRomanNumber( m_cache.number ).upper();
00478             break;
00479         case STYLE_CUSTOM:
00480         default: // shut up compiler
00482             text.setNum( m_cache.number );
00483             break;
00484         }
00485     }
00486     else
00487     {
00488         switch ( m_style )
00489         {
00490             // --- these are used in export filters but are ignored by KoTextParag::drawLabel (for bulleted lists - which they are :))  ---
00491         case KoParagCounter::STYLE_DISCBULLET:
00492             text = '*';
00493             break;
00494         case KoParagCounter::STYLE_SQUAREBULLET:
00495             text = '#';
00496             break;
00497         case KoParagCounter::STYLE_BOXBULLET:
00498             text = '=';  // think up a better character
00499             break;
00500         case KoParagCounter::STYLE_CIRCLEBULLET:
00501             text = 'o';
00502             break;
00503         case KoParagCounter::STYLE_CUSTOMBULLET:
00504             text = m_customBulletChar;
00505             break;
00506         default: // shut up compiler
00507             break;
00508         }
00509     }
00510     return text;
00511 }
00512 
00513 // Return the full text to be displayed
00514 QString KoParagCounter::text( const KoTextParag *paragraph )
00515 {
00516     // Return cached value if possible.
00517     if ( !m_cache.text.isNull() )
00518         return m_cache.text;
00519 
00520     // If necessary, grab the text of the preceding levels.
00521     if ( m_displayLevels > 1 )
00522     {
00523         KoTextParag* p = parent( paragraph );
00524         int displayLevels = QMIN( m_displayLevels, m_depth+1 ); // can't be >depth+1
00525         for ( int level = 1 ; level < displayLevels ; ++level )  {
00526             //kdDebug() << "additional level=" << level << "/" << displayLevels-1 << endl;
00527             if ( p )
00528             {
00529                 KoParagCounter* counter = p->counter();
00530                 QString str = counter->levelText( p );
00531                 // If the preceding level is a bullet, replace it with blanks.
00532                 if ( counter->isBullet() )
00533                     for ( unsigned i = 0; i < str.length(); i++ )
00534                         str[i] = ' ';
00535 
00536                 str.append('.'); // hardcoded on purpose (like OO) until anyone complains
00537 
00538                 // Find the number of missing parents, and add dummy text for them.
00539                 int missingParents = m_depth - level - p->counter()->m_depth;
00540                 //kdDebug() << "levelText = " << str << " missingParents=" << missingParents << endl;
00541                 level += missingParents;
00542                 for ( ; missingParents > 0 ; --missingParents )
00543                     // Each missing level adds a "0"
00544                     str.append( "0." );
00545 
00546                 m_cache.text.prepend( str );
00547                 // Prepare next iteration
00548                 if ( level < displayLevels ) // no need to calc it if we won't use it
00549                     p = counter->parent( p );
00550             }
00551             else // toplevel parents are missing
00552             {
00553                 // Special case for one-paragraph-documents like preview widgets
00554                 KoTextDocument* textdoc = paragraph->textDocument();
00555                 if ( paragraph == textdoc->firstParag() && paragraph == textdoc->lastParag() )
00556                     m_cache.text.prepend( "1." );
00557                 else
00558                     m_cache.text.prepend( "0." );
00559             }
00560         }
00561 
00562     }
00563 
00564     //kdDebug() << "result: " << m_cache.text << " + " << levelText( paragraph ) << endl;
00565     // Now add text for this level.
00566     m_cache.text.append( levelText( paragraph ) );
00567 
00568     // Now apply prefix and suffix
00569     // We want the '.' to be before the number in a RTL parag,
00570     // but we can't paint the whole string using QPainter::RTL direction, otherwise
00571     // '10' becomes '01'.
00572     m_cache.text.prepend( paragraph->string()->isRightToLeft() ? suffix() : prefix() );
00573     m_cache.text.append( paragraph->string()->isRightToLeft() ? prefix() : suffix() );
00574     return m_cache.text;
00575 }
00576 
00577 int KoParagCounter::width( const KoTextParag *paragraph )
00578 {
00579     // Return cached value if possible.
00580     if ( m_cache.width != -1 && counterFormat( paragraph ) == m_cache.counterFormat )
00581         return m_cache.width;
00582 
00583     // Ensure paragraph text is valid.
00584     if ( m_cache.text.isNull() )
00585         text( paragraph );
00586 
00587     // Now calculate width.
00588     if ( m_cache.counterFormat )
00589         m_cache.counterFormat->removeRef();
00590     m_cache.counterFormat = counterFormat( paragraph );
00591     m_cache.counterFormat->addRef();
00592     m_cache.width = 0;
00593     QString text = m_cache.text;
00594     if (  style() ==KoParagCounter::STYLE_CUSTOMBULLET && !text.isEmpty())
00595     {
00596         text.append( "  " ); // append a trailing space, see KoTextParag::drawLabel
00597     }
00598     else if ( !text.isEmpty() )
00599         text.append( ' ' ); // append a trailing space, see KoTextParag::drawLabel
00600     QFontMetrics fm = m_cache.counterFormat->refFontMetrics();
00601     for ( unsigned int i = 0; i < text.length(); i++ )
00602         //m_cache.width += m_cache.counterFormat->width( text, i );
00603         m_cache.width += fm.width( text[i] );
00604     // Now go from 100%-zoom to LU
00605     m_cache.width = KoTextZoomHandler::ptToLayoutUnitPt( m_cache.width );
00606 
00607     //kdDebug(32500) << "KoParagCounter::width recalculated parag=" << paragraph << " text='" << text << "' width=" << m_cache.width << endl;
00608     return m_cache.width;
00609 }
00610 
00611 int KoParagCounter::bulletX()
00612 {
00613     // width() must have been called first
00614     Q_ASSERT( m_cache.width != -1 );
00615     Q_ASSERT( m_cache.counterFormat );
00616     int x = 0;
00617     QFontMetrics fm = m_cache.counterFormat->refFontMetrics();
00618     QString text = prefix();
00619     for (  unsigned int i = 0; i < text.length(); i++ )
00620         x += fm.width( text[i] );
00621     // Now go from 100%-zoom to LU
00622     return KoTextZoomHandler::ptToLayoutUnitPt( x );
00623 }
00624 
00625 // Only exists to centralize code. Does no caching.
00626 KoTextFormat* KoParagCounter::counterFormat( const KoTextParag *paragraph )
00627 {
00628     KoTextFormat* refFormat = paragraph->at( 0 )->format();
00629     KoTextFormat format( *refFormat );
00630     format.setVAlign( KoTextFormat::AlignNormal );
00631     return paragraph->textDocument()->formatCollection()->format( &format );
00632     /*paragraph->paragFormat()*/
00633 }
00634 
00636 
00637 const QCString RNUnits[] = {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"};
00638 const QCString RNTens[] = {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"};
00639 const QCString RNHundreds[] = {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"};
00640 const QCString RNThousands[] = {"", "m", "mm", "mmm"};
00641 
00642 QString KoParagCounter::makeRomanNumber( int n )
00643 {
00644     return QString::fromLatin1( RNThousands[ ( n / 1000 ) ] +
00645                                 RNHundreds[ ( n / 100 ) % 10 ] +
00646                                 RNTens[ ( n / 10 ) % 10 ] +
00647                                 RNUnits[ ( n ) % 10 ] );
00648 }
00649 
00650 QString KoParagCounter::makeAlphaUpperNumber( int n )
00651 {
00652     QString tmp;
00653     char bottomDigit;
00654     while ( n > 26 )
00655     {
00656         bottomDigit = (n-1) % 26;
00657         n = (n-1) / 26;
00658         tmp.prepend( QChar( 'A' + bottomDigit  ) );
00659     }
00660     tmp.prepend( QChar( 'A' + n -1 ) );
00661     return tmp;
00662 }
00663 
00664 QString KoParagCounter::makeAlphaLowerNumber( int n )
00665 {
00666     QString tmp;
00667     char bottomDigit;
00668     while ( n > 26 )
00669     {
00670         bottomDigit = (n-1) % 26;
00671         n = (n-1) / 26;
00672         tmp.prepend( QChar( 'a' + bottomDigit  ) );
00673     }
00674     tmp.prepend( QChar( 'a' + n - 1 ) );
00675     return tmp;
00676 }
00677 
00678 int KoParagCounter::fromRomanNumber( const QString &string )
00679 {
00680     int ret = 0;
00681     int stringStart = 0;
00682     const int stringLen = string.length();
00683 
00684     for (int base = 1000; base >= 1 && stringStart < stringLen; base /= 10)
00685     {
00686         const QCString *rn;
00687         int rnNum;
00688         switch (base)
00689         {
00690             case 1000:
00691                 rn = RNThousands;
00692                 rnNum = sizeof (RNThousands) / sizeof (const QCString);
00693                 break;
00694             case 100:
00695                 rn = RNHundreds;
00696                 rnNum = sizeof (RNHundreds) / sizeof (const QCString);
00697                 break;
00698             case 10:
00699                 rn = RNTens;
00700                 rnNum = sizeof (RNTens) / sizeof (const QCString);
00701                 break;
00702             case 1:
00703             default:
00704                 rn = RNUnits;
00705                 rnNum = sizeof (RNUnits) / sizeof (const QCString);
00706                 break;
00707         }
00708 
00709         // I _think_ this will work :) - Clarence
00710         for (int i = rnNum - 1; i >= 1; i--)
00711         {
00712             const int rnLength = rn[i].length();
00713             if (string.mid(stringStart,rnLength) == (const char*)rn[i])
00714             {
00715                 ret += i * base;
00716                 stringStart += rnLength;
00717                 break;
00718             }
00719         }
00720     }
00721 
00722     return (ret == 0 || stringStart != stringLen) ? -1 /*invalid value*/ : ret;
00723 }
00724 
00725 int KoParagCounter::fromAlphaUpperNumber( const QString &string )
00726 {
00727     int ret = 0;
00728 
00729     const int len = string.length();
00730     for (int i = 0; i < len; i++)
00731     {
00732         const int add = char(string[i]) - 'A' + 1;
00733 
00734         if (add >= 1 && add <= 26) // _not_ < 26
00735             ret = ret * 26 + add;
00736         else
00737         {
00738             ret = -1; // invalid character
00739             break;
00740         }
00741     }
00742 
00743     return (ret == 0) ? -1 /*invalid value*/ : ret;
00744 }
00745 
00746 int KoParagCounter::fromAlphaLowerNumber( const QString &string )
00747 {
00748     int ret = 0;
00749 
00750     const int len = string.length();
00751     for (int i = 0; i < len; i++)
00752     {
00753         const int add = char(string[i]) - 'a' + 1;
00754 
00755         if (add >= 1 && add <= 26) // _not_ < 26
00756             ret = ret * 26 + add;
00757         else
00758         {
00759             ret = -1; // invalid character
00760             break;
00761         }
00762     }
00763 
00764     return (ret == 0) ? -1 /*invalid value*/ : ret;
00765 }
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Nov 17 13:19:23 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2003