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