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