00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "KoParagCounter.h"
00021 #include "KoTextParag.h"
00022 #include "KoTextZoomHandler.h"
00023 #include "KoTextFormat.h"
00024 #include "KoTextDocument.h"
00025 #include "KoOasisContext.h"
00026 #include <KoXmlWriter.h>
00027 #include <KoGenStyles.h>
00028 #include <KoXmlNS.h>
00029 #include <kdebug.h>
00030 #include <qdom.h>
00031 #include <QBuffer>
00032
00033 #include <QByteArray>
00034
00035 static KoTextParag * const INVALID_PARAG = (KoTextParag *)-1;
00036
00037 KoParagCounter::KoParagCounter()
00038 {
00039 m_numbering = NUM_NONE;
00040 m_style = STYLE_NONE;
00041 m_depth = 0;
00042 m_startNumber = 1;
00043 m_displayLevels = 1;
00044 m_restartCounter = false;
00045 m_customBulletChar = QChar( '-' );
00046 m_customBulletFont = QString::null;
00047 m_align = Qt::AlignLeft;
00048 invalidate();
00049 }
00050
00051 bool KoParagCounter::operator==( const KoParagCounter & c2 ) const
00052 {
00053
00054 return (m_numbering==c2.m_numbering &&
00055 m_style==c2.m_style &&
00056 m_depth==c2.m_depth &&
00057 m_startNumber==c2.m_startNumber &&
00058 m_displayLevels==c2.m_displayLevels &&
00059 m_restartCounter==c2.m_restartCounter &&
00060 m_prefix==c2.m_prefix &&
00061 m_suffix==c2.m_suffix &&
00062 m_customBulletChar==c2.m_customBulletChar &&
00063 m_customBulletFont==c2.m_customBulletFont &&
00064 m_align==c2.m_align &&
00065 m_custom==c2.m_custom);
00066 }
00067
00068 QString KoParagCounter::custom() const
00069 {
00070 return m_custom;
00071 }
00072
00073 QChar KoParagCounter::customBulletCharacter() const
00074 {
00075 return m_customBulletChar;
00076 }
00077
00078 QString KoParagCounter::customBulletFont() const
00079 {
00080 return m_customBulletFont;
00081 }
00082
00083 unsigned int KoParagCounter::depth() const
00084 {
00085 return m_depth;
00086 }
00087
00088 void KoParagCounter::invalidate()
00089 {
00090 m_cache.number = -1;
00091 m_cache.text = QString::null;
00092 m_cache.width = -1;
00093 m_cache.parent = INVALID_PARAG;
00094 m_cache.counterFormat = 0;
00095 }
00096
00097 bool KoParagCounter::isBullet( Style style )
00098 {
00099 switch ( style )
00100 {
00101 case STYLE_DISCBULLET:
00102 case STYLE_SQUAREBULLET:
00103 case STYLE_BOXBULLET:
00104 case STYLE_CIRCLEBULLET:
00105 case STYLE_CUSTOMBULLET:
00106 return true;
00107 default:
00108 return false;
00109 }
00110 }
00111
00112 bool KoParagCounter::isBullet() const
00113 {
00114 return isBullet( m_style );
00115 }
00116
00117 void KoParagCounter::load( QDomElement & element )
00118 {
00119 m_numbering = static_cast<Numbering>( element.attribute("numberingtype", "2").toInt() );
00120 m_style = static_cast<Style>( element.attribute("type").toInt() );
00121
00122 if ( m_numbering == NUM_LIST && m_style == STYLE_NONE )
00123 m_numbering = NUM_NONE;
00124 m_depth = element.attribute("depth").toInt();
00125 m_customBulletChar = QChar( element.attribute("bullet").toInt() );
00126 m_prefix = element.attribute("lefttext");
00127 if ( m_prefix.toLower() == "(null)" )
00128 m_prefix = QString::null;
00129 m_suffix = element.attribute("righttext");
00130 if ( m_suffix.toLower() == "(null)" )
00131 m_suffix = QString::null;
00132 QString s = element.attribute("start");
00133 if ( s.isEmpty() )
00134 m_startNumber = 1;
00135 else if ( s[0].isDigit() )
00136 m_startNumber = s.toInt();
00137 else
00138 m_startNumber = s.toLower()[0].toLatin1() - 'a' + 1;
00139 s = element.attribute("display-levels");
00140 if ( !s.isEmpty() )
00141 m_displayLevels = qMin( s.toInt(), m_depth+1 );
00142 else
00143 m_displayLevels = m_depth+1;
00144 m_customBulletFont = element.attribute("bulletfont");
00145 m_custom = element.attribute("customdef");
00146 m_align = element.attribute("align", "0").toInt();
00147 QString restart = element.attribute("restart");
00148 m_restartCounter = (restart == "true") || (restart == "1");
00149 invalidate();
00150 }
00151
00152 static int importCounterType( QChar numFormat )
00153 {
00154 if ( numFormat == '1' )
00155 return KoParagCounter::STYLE_NUM;
00156 if ( numFormat == 'a' )
00157 return KoParagCounter::STYLE_ALPHAB_L;
00158 if ( numFormat == 'A' )
00159 return KoParagCounter::STYLE_ALPHAB_U;
00160 if ( numFormat == 'i' )
00161 return KoParagCounter::STYLE_ROM_NUM_L;
00162 if ( numFormat == 'I' )
00163 return KoParagCounter::STYLE_ROM_NUM_U;
00164 return KoParagCounter::STYLE_NONE;
00165 }
00166
00167
00168 static QChar exportCounterType( KoParagCounter::Style style )
00169 {
00170 static const int s_oasisCounterTypes[] =
00171 { '\0', '1', 'a', 'A', 'i', 'I',
00172 '\0', '\0',
00173 0x2022,
00174 0xE00A,
00175 0x25CF,
00176 0x27A2
00177 };
00178 return QChar( s_oasisCounterTypes[ style ] );
00179 }
00180
00181 void KoParagCounter::loadOasis( KoOasisContext& context, int restartNumbering,
00182 bool orderedList, bool heading, int level, bool loadingStyle )
00183 {
00184 const QDomElement listStyle = context.listStyleStack().currentListStyle();
00185 const QDomElement listStyleProperties = context.listStyleStack().currentListStyleProperties();
00186 const QDomElement listStyleTextProperties = context.listStyleStack().currentListStyleTextProperties();
00187 loadOasisListStyle( listStyle, listStyleProperties, listStyleTextProperties,
00188 restartNumbering, orderedList, heading, level, loadingStyle );
00189 }
00190
00191 void KoParagCounter::loadOasisListStyle( const QDomElement& listStyle,
00192 const QDomElement& listStyleProperties,
00193 const QDomElement& listStyleTextProperties,
00194 int restartNumbering,
00195 bool orderedList, bool heading, int level,
00196 bool loadingStyle )
00197 {
00198 m_numbering = heading ? NUM_CHAPTER : NUM_LIST;
00199 m_depth = level - 1;
00200
00201 if ( restartNumbering == -1 && listStyle.hasAttributeNS( KoXmlNS::text, "start-value" ) )
00202 restartNumbering = listStyle.attributeNS( KoXmlNS::text, "start-value", QString::null ).toInt();
00203
00204
00205 m_restartCounter = loadingStyle ? false : ( restartNumbering != -1 );
00206 m_startNumber = ( restartNumbering != -1 ) ? restartNumbering : 1;
00207
00208
00209 m_prefix = listStyle.attributeNS( KoXmlNS::style, "num-prefix", QString::null );
00210 m_suffix = listStyle.attributeNS( KoXmlNS::style, "num-suffix", QString::null );
00211
00212 if ( orderedList || heading ) {
00213 m_style = static_cast<Style>( importCounterType( listStyle.attributeNS( KoXmlNS::style, "num-format", QString::null)[0] ) );
00214 QString dl = listStyle.attributeNS( KoXmlNS::text, "display-levels", QString::null );
00215 m_displayLevels = dl.isEmpty() ? 1 : dl.toInt();
00216 } else {
00217 m_style = STYLE_CUSTOMBULLET;
00218 QString bulletChar = listStyle.attributeNS( KoXmlNS::text, "bullet-char", QString::null );
00219 if ( !bulletChar.isEmpty() ) {
00220
00221 switch( bulletChar[0].unicode() ) {
00222 case 0x2022:
00223 m_style = STYLE_CIRCLEBULLET;
00224 break;
00225 case 0x25CF:
00226 case 0xF0B7:
00227 m_style = STYLE_DISCBULLET;
00228 break;
00229 case 0xE00C:
00230 m_style = STYLE_BOXBULLET;
00231 break;
00232 case 0xE00A:
00233 m_style = STYLE_SQUAREBULLET;
00234 break;
00235 case 0x27A2:
00236
00237 m_style = STYLE_BOXBULLET;
00238 break;
00239 default:
00240 kDebug() << "Unhandled bullet code 0x" << QString::number( (uint)m_customBulletChar.unicode(), 16 ) << endl;
00241
00242 case 0x2794:
00243 case 0x2717:
00244 case 0x2714:
00245 m_customBulletChar = bulletChar[0];
00246
00247 if ( listStyleProperties.hasAttributeNS( KoXmlNS::style, "font-name" ) )
00248 {
00249 m_customBulletFont = listStyleProperties.attributeNS( KoXmlNS::style, "font-name", QString::null );
00250 kDebug() << "m_customBulletFont style:font-name = " << listStyleProperties.attributeNS( KoXmlNS::style, "font-name", QString::null ) << endl;
00251 }
00252 else if ( listStyleTextProperties.hasAttributeNS( KoXmlNS::fo, "font-family" ) )
00253 {
00254 m_customBulletFont = listStyleTextProperties.attributeNS( KoXmlNS::fo, "font-family", QString::null );
00255 kDebug() << "m_customBulletFont fo:font-family = " << listStyleTextProperties.attributeNS( KoXmlNS::fo, "font-family", QString::null ) << endl;
00256 }
00257
00258 break;
00259 }
00260 } else {
00261 m_style = STYLE_DISCBULLET;
00262 }
00263 }
00264 invalidate();
00265 }
00266
00267 void KoParagCounter::saveOasis( KoGenStyle& listStyle, bool savingStyle ) const
00268 {
00269 Q_ASSERT( (Style)m_style != STYLE_NONE );
00270
00271
00272 QBuffer buffer;
00273 buffer.open( QIODevice::WriteOnly );
00274 KoXmlWriter listLevelWriter( &buffer, 3 );
00275 const char* tagName = isBullet() ? "text:list-level-style-bullet" : "text:list-level-style-number";
00276 listLevelWriter.startElement( tagName );
00277
00278 saveOasisListLevel( listLevelWriter, true, savingStyle );
00279
00280 listLevelWriter.endElement();
00281 const QString listLevelContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
00282 listStyle.addChildElement( tagName, listLevelContents );
00283 }
00284
00285 void KoParagCounter::saveOasisListLevel( KoXmlWriter& listLevelWriter, bool includeLevelAndProperties, bool savingStyle ) const
00286 {
00287 if ( includeLevelAndProperties )
00288 listLevelWriter.addAttribute( "text:level", (int)m_depth + 1 );
00289
00290
00291
00292 if ( isBullet() )
00293 {
00294 QChar bulletChar;
00295 if ( (Style)m_style == STYLE_CUSTOMBULLET )
00296 {
00297 bulletChar = m_customBulletChar;
00298
00299 }
00300 else
00301 {
00302 bulletChar = exportCounterType( (Style)m_style );
00303 }
00304 listLevelWriter.addAttribute( "text:bullet-char", QString( bulletChar ) );
00305 }
00306 else
00307 {
00308 if ( includeLevelAndProperties )
00309 listLevelWriter.addAttribute( "text:display-levels", m_displayLevels );
00310 if ( (Style)m_style == STYLE_CUSTOM )
00311 ;
00312 else
00313 listLevelWriter.addAttribute( "style:num-format", QString( exportCounterType( (Style)m_style ) ) );
00314
00315
00316 if ( savingStyle && m_restartCounter ) {
00317 listLevelWriter.addAttribute( "text:start-value", m_startNumber );
00318 }
00319
00320 }
00321
00322
00323 listLevelWriter.addAttribute( "style:num-prefix", m_prefix );
00324 listLevelWriter.addAttribute( "style:num-suffix", m_suffix );
00325
00326 if ( includeLevelAndProperties )
00327 {
00328 listLevelWriter.startElement( "style:list-level-properties" );
00329 listLevelWriter.addAttribute( "fo:text-align", KoParagLayout::saveOasisAlignment( (Qt::AlignmentFlag)m_align ) );
00330
00331
00332 listLevelWriter.endElement();
00333 }
00334 }
00335
00336 int KoParagCounter::number( const KoTextParag *paragraph )
00337 {
00338
00339 if ( m_cache.number != -1 )
00340 return m_cache.number;
00341
00342
00343 if ( m_restartCounter ) {
00344 Q_ASSERT( m_startNumber != -1 );
00345 m_cache.number = m_startNumber;
00346 return m_startNumber;
00347 }
00348
00349
00350
00351 KoTextParag *otherParagraph = paragraph->prev();
00352 KoParagCounter *otherCounter;
00353
00354 switch ( m_numbering )
00355 {
00356 case NUM_NONE:
00357
00358 case NUM_FOOTNOTE:
00359 m_cache.number = 0;
00360 break;
00361 case NUM_CHAPTER:
00362 m_cache.number = m_startNumber;
00363
00364 while ( otherParagraph )
00365 {
00366 otherCounter = otherParagraph->counter();
00367 if ( otherCounter &&
00368 ( otherCounter->m_numbering == NUM_CHAPTER ) &&
00369 ( otherCounter->m_depth <= m_depth ) )
00370 {
00371 if ( ( otherCounter->m_depth == m_depth ) &&
00372 ( otherCounter->m_style == m_style ) )
00373 {
00374
00375 m_cache.number = otherCounter->number( otherParagraph ) + 1;
00376 }
00377 else
00378 {
00379
00380 m_cache.number = m_startNumber;
00381 }
00382 break;
00383 }
00384 otherParagraph = otherParagraph->prev();
00385 }
00386 break;
00387 case NUM_LIST:
00388 m_cache.number = m_startNumber;
00389
00390 while ( otherParagraph )
00391 {
00392 otherCounter = otherParagraph->counter();
00393 if ( otherCounter )
00394 {
00395 if ( ( otherCounter->m_numbering == NUM_LIST ) &&
00396 !isBullet( otherCounter->m_style ) &&
00397 ( otherCounter->m_depth <= m_depth ) )
00398 {
00399 if ( ( otherCounter->m_depth == m_depth ) &&
00400 ( otherCounter->m_style == m_style ) )
00401 {
00402
00403 m_cache.number = otherCounter->number( otherParagraph ) + 1;
00404 }
00405 else
00406 {
00407
00408 m_cache.number = m_startNumber;
00409 }
00410 break;
00411 }
00412 else
00413 if ( otherCounter->m_numbering == NUM_CHAPTER )
00414 {
00415 m_cache.number = m_startNumber;
00416 break;
00417 }
00418 }
00419
00420
00421
00422
00423
00424
00425 otherParagraph = otherParagraph->prev();
00426 }
00427 break;
00428 }
00429 Q_ASSERT( m_cache.number != -1 );
00430 return m_cache.number;
00431 }
00432
00433 KoParagCounter::Numbering KoParagCounter::numbering() const
00434 {
00435 return m_numbering;
00436 }
00437
00438
00439 KoTextParag *KoParagCounter::parent( const KoTextParag *paragraph )
00440 {
00441
00442 if ( m_cache.parent != INVALID_PARAG )
00443 return m_cache.parent;
00444
00445 KoTextParag *otherParagraph = paragraph->prev();
00446 KoParagCounter *otherCounter;
00447
00448
00449 switch ( m_numbering )
00450 {
00451 case NUM_NONE:
00452
00453 case NUM_FOOTNOTE:
00454 otherParagraph = 0L;
00455 break;
00456 case NUM_CHAPTER:
00457
00458 while ( otherParagraph )
00459 {
00460 otherCounter = otherParagraph->counter();
00461 if ( otherCounter &&
00462 ( otherCounter->m_numbering == NUM_CHAPTER ) &&
00463 ( otherCounter->m_depth < m_depth ) )
00464 {
00465 break;
00466 }
00467 otherParagraph = otherParagraph->prev();
00468 }
00469 break;
00470 case NUM_LIST:
00471
00472 while ( otherParagraph )
00473 {
00474 otherCounter = otherParagraph->counter();
00475 if ( otherCounter )
00476 {
00477 if ( ( otherCounter->m_numbering == NUM_LIST ) &&
00478 !isBullet( otherCounter->m_style ) &&
00479 ( otherCounter->m_depth < m_depth ) )
00480 {
00481 break;
00482 }
00483 else
00484 if ( otherCounter->m_numbering == NUM_CHAPTER )
00485 {
00486 otherParagraph = 0L;
00487 break;
00488 }
00489 }
00490 otherParagraph = otherParagraph->prev();
00491 }
00492 break;
00493 }
00494 m_cache.parent = otherParagraph;
00495 return m_cache.parent;
00496 }
00497
00498 QString KoParagCounter::prefix() const
00499 {
00500 return m_prefix;
00501 }
00502
00503 void KoParagCounter::save( QDomElement & element )
00504 {
00505 element.setAttribute( "type", static_cast<int>( m_style ) );
00506 element.setAttribute( "depth", m_depth );
00507 if ( (Style)m_style == STYLE_CUSTOMBULLET )
00508 {
00509 element.setAttribute( "bullet", m_customBulletChar.unicode() );
00510 if ( !m_customBulletFont.isEmpty() )
00511 element.setAttribute( "bulletfont", m_customBulletFont );
00512 }
00513 if ( !m_prefix.isEmpty() )
00514 element.setAttribute( "lefttext", m_prefix );
00515 if ( !m_suffix.isEmpty() )
00516 element.setAttribute( "righttext", m_suffix );
00517 if ( m_startNumber != 1 )
00518 element.setAttribute( "start", m_startNumber );
00519
00520 element.setAttribute( "display-levels", m_displayLevels );
00521
00522 if ( m_numbering != NUM_NONE && m_numbering != NUM_FOOTNOTE )
00523 element.setAttribute( "numberingtype", static_cast<int>( m_numbering ) );
00524 if ( !m_custom.isEmpty() )
00525 element.setAttribute( "customdef", m_custom );
00526 if ( m_restartCounter )
00527 element.setAttribute( "restart", "true" );
00528 if ( !m_cache.text.isEmpty() )
00529 element.setAttribute( "text", m_cache.text );
00530 element.setAttribute( "align", m_align );
00531 }
00532
00533 void KoParagCounter::setCustom( const QString & c )
00534 {
00535 m_custom = c;
00536 invalidate();
00537 }
00538
00539 void KoParagCounter::setCustomBulletCharacter( QChar c )
00540 {
00541 m_customBulletChar = c;
00542 invalidate();
00543 }
00544
00545 void KoParagCounter::setCustomBulletFont( const QString & f )
00546 {
00547 m_customBulletFont = f;
00548 invalidate();
00549 }
00550
00551 void KoParagCounter::setDepth( unsigned int d )
00552 {
00553 m_depth = d;
00554 invalidate();
00555 }
00556
00557 void KoParagCounter::setNumbering( Numbering n )
00558 {
00559 m_numbering = n;
00560 invalidate();
00561 }
00562
00563 void KoParagCounter::setPrefix( const QString & p )
00564 {
00565 m_prefix = p;
00566 invalidate();
00567 }
00568 void KoParagCounter::setStartNumber( int s )
00569 {
00570 m_startNumber = s;
00571 invalidate();
00572 }
00573
00574 void KoParagCounter::setDisplayLevels( int l )
00575 {
00576 m_displayLevels = l;
00577 invalidate();
00578 }
00579
00580 void KoParagCounter::setAlignment( int a )
00581 {
00582 m_align = a;
00583 invalidate();
00584 }
00585
00586 void KoParagCounter::setStyle( Style s )
00587 {
00588 m_style = s;
00589 invalidate();
00590 }
00591
00592 void KoParagCounter::setSuffix( const QString & s )
00593 {
00594 m_suffix = s;
00595 invalidate();
00596 }
00597
00598 int KoParagCounter::startNumber() const
00599 {
00600 return m_startNumber;
00601 }
00602
00603 int KoParagCounter::displayLevels() const
00604 {
00605 return m_displayLevels;
00606 }
00607
00608 int KoParagCounter::alignment() const
00609 {
00610 return m_align;
00611 }
00612
00613 KoParagCounter::Style KoParagCounter::style() const
00614 {
00615 return m_style;
00616 }
00617
00618 QString KoParagCounter::suffix() const
00619 {
00620 return m_suffix;
00621 }
00622
00623 bool KoParagCounter::restartCounter() const
00624 {
00625 return m_restartCounter;
00626 }
00627
00628 void KoParagCounter::setRestartCounter( bool restart )
00629 {
00630 m_restartCounter = restart;
00631 invalidate();
00632 }
00633
00634
00635 QString KoParagCounter::levelText( const KoTextParag *paragraph )
00636 {
00637 if ( m_numbering == NUM_NONE )
00638 return "";
00639
00640 bool bullet = isBullet( m_style );
00641
00642 if ( bullet && m_numbering == NUM_CHAPTER ) {
00643
00644 m_style = STYLE_NUM;
00645 bullet = false;
00646 }
00647
00648 QString text;
00649 if ( !bullet )
00650 {
00651
00652 number( paragraph );
00653
00654 switch ( m_style )
00655 {
00656 case STYLE_NONE:
00657 if ( m_numbering == NUM_LIST )
00658 text = ' ';
00659 break;
00660 case STYLE_NUM:
00661 text.setNum( m_cache.number );
00662 break;
00663 case STYLE_ALPHAB_L:
00664 text = makeAlphaLowerNumber( m_cache.number );
00665 break;
00666 case STYLE_ALPHAB_U:
00667 text = makeAlphaUpperNumber( m_cache.number );
00668 break;
00669 case STYLE_ROM_NUM_L:
00670 text = makeRomanNumber( m_cache.number ).toLower();
00671 break;
00672 case STYLE_ROM_NUM_U:
00673 text = makeRomanNumber( m_cache.number ).toUpper();
00674 break;
00675 case STYLE_CUSTOM:
00677 default:
00678 text.setNum( m_cache.number );
00679 break;
00680 }
00681 }
00682 else
00683 {
00684 switch ( m_style )
00685 {
00686
00687 case KoParagCounter::STYLE_DISCBULLET:
00688 text = '*';
00689 break;
00690 case KoParagCounter::STYLE_SQUAREBULLET:
00691 text = '#';
00692 break;
00693 case KoParagCounter::STYLE_BOXBULLET:
00694 text = '=';
00695 break;
00696 case KoParagCounter::STYLE_CIRCLEBULLET:
00697 text = 'o';
00698 break;
00699 case KoParagCounter::STYLE_CUSTOMBULLET:
00700 text = m_customBulletChar;
00701 break;
00702 default:
00703 break;
00704 }
00705 }
00706 return text;
00707 }
00708
00709
00710 QString KoParagCounter::text( const KoTextParag *paragraph )
00711 {
00712
00713 if ( !m_cache.text.isNull() )
00714 return m_cache.text;
00715
00716
00717 if ( m_displayLevels > 1 && m_numbering != NUM_NONE )
00718 {
00719 KoTextParag* p = parent( paragraph );
00720 int displayLevels = qMin( (int)m_displayLevels, m_depth+1 );
00721 for ( int level = 1 ; level < displayLevels ; ++level ) {
00722
00723 if ( p )
00724 {
00725 KoParagCounter* counter = p->counter();
00726 QString str = counter->levelText( p );
00727
00728 if ( counter->isBullet() )
00729 for ( unsigned i = 0; i < str.length(); i++ )
00730 str[i] = ' ';
00731
00732 str.append('.');
00733
00734
00735 int missingParents = m_depth - level - p->counter()->m_depth;
00736
00737 level += missingParents;
00738 for ( ; missingParents > 0 ; --missingParents )
00739
00740 str.append( "0." );
00741
00742 m_cache.text.prepend( str );
00743
00744 if ( level < displayLevels )
00745 p = counter->parent( p );
00746 }
00747 else
00748 {
00749
00750 KoTextDocument* textdoc = paragraph->textDocument();
00751 if ( paragraph == textdoc->firstParag() && paragraph == textdoc->lastParag() )
00752 m_cache.text.prepend( "1." );
00753 else
00754 m_cache.text.prepend( "0." );
00755 }
00756 }
00757
00758 }
00759
00760
00761
00762 m_cache.text.append( levelText( paragraph ) );
00763
00764
00765
00766
00767
00768 m_cache.text.prepend( paragraph->string()->isRightToLeft() ? suffix() : prefix() );
00769 m_cache.text.append( paragraph->string()->isRightToLeft() ? prefix() : suffix() );
00770 return m_cache.text;
00771 }
00772
00773 int KoParagCounter::width( const KoTextParag *paragraph )
00774 {
00775
00776 if ( m_cache.width != -1 && counterFormat( paragraph ) == m_cache.counterFormat )
00777 return m_cache.width;
00778
00779
00780 if ( m_cache.text.isNull() )
00781 text( paragraph );
00782
00783
00784 if ( m_cache.counterFormat )
00785 m_cache.counterFormat->removeRef();
00786 m_cache.counterFormat = counterFormat( paragraph );
00787 m_cache.counterFormat->addRef();
00788 m_cache.width = 0;
00789 if ( m_style != STYLE_NONE || m_numbering == NUM_FOOTNOTE)
00790 {
00791 QString text = m_cache.text;
00792 if ( m_style == STYLE_CUSTOMBULLET && !text.isEmpty() )
00793 {
00794 text.append( " " );
00795 }
00796 else if ( !text.isEmpty() )
00797 text.append( ' ' );
00798 QFontMetrics fm = m_cache.counterFormat->refFontMetrics();
00799 for ( unsigned int i = 0; i < text.length(); i++ )
00800
00801 m_cache.width += fm.width( text[i] );
00802 }
00803
00804 m_cache.width = KoTextZoomHandler::ptToLayoutUnitPt( m_cache.width );
00805
00806
00807 return m_cache.width;
00808 }
00809
00810 int KoParagCounter::bulletX()
00811 {
00812
00813 Q_ASSERT( m_cache.width != -1 );
00814 Q_ASSERT( m_cache.counterFormat );
00815 int x = 0;
00816 QFontMetrics fm = m_cache.counterFormat->refFontMetrics();
00817 QString text = prefix();
00818 for ( unsigned int i = 0; i < text.length(); i++ )
00819 x += fm.width( text[i] );
00820
00821 return KoTextZoomHandler::ptToLayoutUnitPt( x );
00822 }
00823
00824
00825 KoTextFormat* KoParagCounter::counterFormat( const KoTextParag *paragraph )
00826 {
00827 KoTextFormat* refFormat = paragraph->at( 0 )->format();
00828 KoTextFormat format( *refFormat );
00829 format.setVAlign( KoTextFormat::AlignNormal );
00830 return paragraph->textDocument()->formatCollection()->format( &format );
00831
00832 }
00833
00835
00836 const QByteArray RNUnits[] = {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"};
00837 const QByteArray RNTens[] = {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"};
00838 const QByteArray RNHundreds[] = {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"};
00839 const QByteArray RNThousands[] = {"", "m", "mm", "mmm"};
00840
00841 QString KoParagCounter::makeRomanNumber( int n )
00842 {
00843 if ( n >= 0 )
00844 return QString::fromLatin1( RNThousands[ ( n / 1000 ) ] +
00845 RNHundreds[ ( n / 100 ) % 10 ] +
00846 RNTens[ ( n / 10 ) % 10 ] +
00847 RNUnits[ ( n ) % 10 ] );
00848 else {
00849 kWarning(32500) << "makeRomanNumber: n=" << n << endl;
00850 return QString::number( n );
00851 }
00852 }
00853
00854 QString KoParagCounter::makeAlphaUpperNumber( int n )
00855 {
00856 QString tmp;
00857 char bottomDigit;
00858 while ( n > 26 )
00859 {
00860 bottomDigit = (n-1) % 26;
00861 n = (n-1) / 26;
00862 tmp.prepend( QChar( 'A' + bottomDigit ) );
00863 }
00864 tmp.prepend( QChar( 'A' + n -1 ) );
00865 return tmp;
00866 }
00867
00868 QString KoParagCounter::makeAlphaLowerNumber( int n )
00869 {
00870 QString tmp;
00871 char bottomDigit;
00872 while ( n > 26 )
00873 {
00874 bottomDigit = (n-1) % 26;
00875 n = (n-1) / 26;
00876 tmp.prepend( QChar( 'a' + bottomDigit ) );
00877 }
00878 tmp.prepend( QChar( 'a' + n - 1 ) );
00879 return tmp;
00880 }
00881
00882 int KoParagCounter::fromRomanNumber( const QString &string )
00883 {
00884 int ret = 0;
00885 int stringStart = 0;
00886 const int stringLen = string.length();
00887
00888 for (int base = 1000; base >= 1 && stringStart < stringLen; base /= 10)
00889 {
00890 const QByteArray *rn;
00891 int rnNum;
00892 switch (base)
00893 {
00894 case 1000:
00895 rn = RNThousands;
00896 rnNum = sizeof (RNThousands) / sizeof (const QByteArray);
00897 break;
00898 case 100:
00899 rn = RNHundreds;
00900 rnNum = sizeof (RNHundreds) / sizeof (const QByteArray);
00901 break;
00902 case 10:
00903 rn = RNTens;
00904 rnNum = sizeof (RNTens) / sizeof (const QByteArray);
00905 break;
00906 case 1:
00907 default:
00908 rn = RNUnits;
00909 rnNum = sizeof (RNUnits) / sizeof (const QByteArray);
00910 break;
00911 }
00912
00913
00914 for (int i = rnNum - 1; i >= 1; i--)
00915 {
00916 const int rnLength = rn[i].length();
00917 if (string.mid(stringStart,rnLength) == (const char*)rn[i])
00918 {
00919 ret += i * base;
00920 stringStart += rnLength;
00921 break;
00922 }
00923 }
00924 }
00925
00926 return (ret == 0 || stringStart != stringLen) ? -1 : ret;
00927 }
00928
00929 int KoParagCounter::fromAlphaUpperNumber( const QString &string )
00930 {
00931 int ret = 0;
00932
00933 const int len = string.length();
00934 for (int i = 0; i < len; i++)
00935 {
00936 const int add = (string[i]).toLatin1() - 'A' + 1;
00937
00938 if (add >= 1 && add <= 26)
00939 ret = ret * 26 + add;
00940 else
00941 {
00942 ret = -1;
00943 break;
00944 }
00945 }
00946
00947 return (ret == 0) ? -1 : ret;
00948 }
00949
00950 int KoParagCounter::fromAlphaLowerNumber( const QString &string )
00951 {
00952 int ret = 0;
00953
00954 const int len = string.length();
00955 for (int i = 0; i < len; i++)
00956 {
00957 const int add = (string[i]).toLatin1() - 'a' + 1;
00958
00959 if (add >= 1 && add <= 26)
00960 ret = ret * 26 + add;
00961 else
00962 {
00963 ret = -1;
00964 break;
00965 }
00966 }
00967
00968 return (ret == 0) ? -1 : ret;
00969 }
00970
00971 #ifndef NDEBUG
00972 void KoParagCounter::printRTDebug( KoTextParag* parag )
00973 {
00974 QString additionalInfo;
00975 if ( restartCounter() )
00976 additionalInfo = "[restartCounter]";
00977 if ( m_style == STYLE_CUSTOMBULLET )
00978 additionalInfo += " [customBullet: " + QString::number( m_customBulletChar.unicode() )
00979 + " in font '" + m_customBulletFont + "']";
00980 static const char * const s_numbering[] = { "List", "Chapter", "None", "Footnote" };
00981 kDebug(32500) << " Counter style=" << style()
00982 << " numbering=" << s_numbering[ numbering() ]
00983 << " depth=" << depth()
00984 << " number=" << number( parag )
00985 << " text='" << text( parag ) << "'"
00986 << " width=" << width( parag )
00987 << additionalInfo << endl;
00988 }
00989 #endif