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