20#include "KoParagCounter.h"
21#include "KoTextParag.h"
22#include "KoTextZoomHandler.h"
23#include "KoTextFormat.h"
24#include "KoTextDocument.h"
25#include "KoOasisContext.h"
26#include <KoXmlWriter.h>
27#include <KoGenStyles.h>
33static KoTextParag *
const INVALID_PARAG = (KoTextParag *)-1;
35KoParagCounter::KoParagCounter()
37 m_numbering = NUM_NONE;
42 m_restartCounter =
false;
43 m_customBulletChar = TQChar(
'-' );
44 m_customBulletFont = TQString();
45 m_align = TQt::AlignAuto;
52 return (m_numbering==c2.m_numbering &&
53 m_style==c2.m_style &&
54 m_depth==c2.m_depth &&
55 m_startNumber==c2.m_startNumber &&
56 m_displayLevels==c2.m_displayLevels &&
57 m_restartCounter==c2.m_restartCounter &&
58 m_prefix==c2.m_prefix &&
59 m_suffix==c2.m_suffix &&
60 m_customBulletChar==c2.m_customBulletChar &&
61 m_customBulletFont==c2.m_customBulletFont &&
62 m_align==c2.m_align &&
63 m_custom==c2.m_custom);
73 return m_customBulletChar;
76TQString KoParagCounter::customBulletFont()
const
78 return m_customBulletFont;
89 m_cache.text = TQString();
91 m_cache.parent = INVALID_PARAG;
92 m_cache.counterFormat = 0;
99 case STYLE_DISCBULLET:
100 case STYLE_SQUAREBULLET:
101 case STYLE_BOXBULLET:
102 case STYLE_CIRCLEBULLET:
103 case STYLE_CUSTOMBULLET:
117 m_numbering =
static_cast<Numbering
>( element.attribute(
"numberingtype",
"2").toInt() );
118 m_style =
static_cast<Style
>( element.attribute(
"type").toInt() );
120 if ( m_numbering == NUM_LIST && m_style == STYLE_NONE )
121 m_numbering = NUM_NONE;
122 m_depth = element.attribute(
"depth").toInt();
123 m_customBulletChar = TQChar( element.attribute(
"bullet").toInt() );
124 m_prefix = element.attribute(
"lefttext");
125 if ( m_prefix.lower() ==
"(null)" )
126 m_prefix = TQString();
127 m_suffix = element.attribute(
"righttext");
128 if ( m_suffix.lower() ==
"(null)" )
129 m_suffix = TQString();
130 TQString s = element.attribute(
"start");
133 else if ( s[0].isDigit() )
134 m_startNumber = s.toInt();
136 m_startNumber = s.lower()[0].latin1() -
'a' + 1;
137 s = element.attribute(
"display-levels");
139 m_displayLevels = TQMIN( s.toInt(), m_depth+1 );
141 m_displayLevels = m_depth+1;
142 m_customBulletFont = element.attribute(
"bulletfont");
143 m_custom = element.attribute(
"customdef");
144 m_align = element.attribute(
"align",
"0").toInt();
145 TQString restart = element.attribute(
"restart");
146 m_restartCounter = (restart ==
"true") || (restart ==
"1");
150static int importCounterType( TQChar numFormat )
152 if ( numFormat ==
'1' )
153 return KoParagCounter::STYLE_NUM;
154 if ( numFormat ==
'a' )
155 return KoParagCounter::STYLE_ALPHAB_L;
156 if ( numFormat ==
'A' )
157 return KoParagCounter::STYLE_ALPHAB_U;
158 if ( numFormat ==
'i' )
159 return KoParagCounter::STYLE_ROM_NUM_L;
160 if ( numFormat ==
'I' )
161 return KoParagCounter::STYLE_ROM_NUM_U;
162 return KoParagCounter::STYLE_NONE;
166static TQChar exportCounterType( KoParagCounter::Style style )
168 static const int s_oasisCounterTypes[] =
169 {
'\0',
'1',
'a',
'A',
'i',
'I',
176 return TQChar( s_oasisCounterTypes[ style ] );
180 bool orderedList,
bool heading,
int level,
bool loadingStyle )
186 restartNumbering, orderedList, heading, level, loadingStyle );
190 const TQDomElement& listStyleProperties,
191 const TQDomElement& listStyleTextProperties,
192 int restartNumbering,
193 bool orderedList,
bool heading,
int level,
196 m_numbering = heading ? NUM_CHAPTER : NUM_LIST;
199 if ( restartNumbering == -1 && listStyle.hasAttributeNS( KoXmlNS::text,
"start-value" ) )
200 restartNumbering = listStyle.attributeNS( KoXmlNS::text,
"start-value", TQString() ).toInt();
203 m_restartCounter = loadingStyle ? false : ( restartNumbering != -1 );
204 m_startNumber = ( restartNumbering != -1 ) ? restartNumbering : 1;
207 m_prefix = listStyle.attributeNS( KoXmlNS::style,
"num-prefix", TQString() );
208 m_suffix = listStyle.attributeNS( KoXmlNS::style,
"num-suffix", TQString() );
210 if ( orderedList || heading ) {
211 m_style =
static_cast<Style
>( importCounterType( listStyle.attributeNS( KoXmlNS::style,
"num-format", TQString())[0] ) );
212 TQString dl = listStyle.attributeNS( KoXmlNS::text,
"display-levels", TQString() );
213 m_displayLevels = dl.isEmpty() ? 1 : dl.toInt();
215 m_style = STYLE_CUSTOMBULLET;
216 TQString bulletChar = listStyle.attributeNS( KoXmlNS::text,
"bullet-char", TQString() );
217 if ( !bulletChar.isEmpty() ) {
219 switch( bulletChar[0].unicode() ) {
221 m_style = STYLE_CIRCLEBULLET;
225 m_style = STYLE_DISCBULLET;
228 m_style = STYLE_BOXBULLET;
231 m_style = STYLE_SQUAREBULLET;
235 m_style = STYLE_BOXBULLET;
238 kdDebug() <<
"Unhandled bullet code 0x" << TQString::number( (uint)m_customBulletChar.unicode(), 16 ) << endl;
243 m_customBulletChar = bulletChar[0];
245 if ( listStyleProperties.hasAttributeNS( KoXmlNS::style,
"font-name" ) )
247 m_customBulletFont = listStyleProperties.attributeNS( KoXmlNS::style,
"font-name", TQString() );
248 kdDebug() <<
"m_customBulletFont style:font-name = " << listStyleProperties.attributeNS( KoXmlNS::style,
"font-name", TQString() ) << endl;
250 else if ( listStyleTextProperties.hasAttributeNS( KoXmlNS::fo,
"font-family" ) )
252 m_customBulletFont = listStyleTextProperties.attributeNS( KoXmlNS::fo,
"font-family", TQString() );
253 kdDebug() <<
"m_customBulletFont fo:font-family = " << listStyleTextProperties.attributeNS( KoXmlNS::fo,
"font-family", TQString() ) << endl;
259 m_style = STYLE_DISCBULLET;
267 Q_ASSERT( (Style)m_style != STYLE_NONE );
271 buffer.open( IO_WriteOnly );
273 const char* tagName =
isBullet() ?
"text:list-level-style-bullet" :
"text:list-level-style-number";
279 const TQString listLevelContents = TQString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
285 if ( includeLevelAndProperties )
286 listLevelWriter.
addAttribute(
"text:level", (
int)m_depth + 1 );
293 if ( (Style)m_style == STYLE_CUSTOMBULLET )
295 bulletChar = m_customBulletChar;
300 bulletChar = exportCounterType( (Style)m_style );
302 listLevelWriter.
addAttribute(
"text:bullet-char", TQString( bulletChar ) );
306 if ( includeLevelAndProperties )
307 listLevelWriter.
addAttribute(
"text:display-levels", m_displayLevels );
308 if ( (Style)m_style == STYLE_CUSTOM )
311 listLevelWriter.
addAttribute(
"style:num-format", TQString( exportCounterType( (Style)m_style ) ) );
314 if ( savingStyle && m_restartCounter ) {
315 listLevelWriter.
addAttribute(
"text:start-value", m_startNumber );
321 listLevelWriter.
addAttribute(
"style:num-prefix", m_prefix );
322 listLevelWriter.
addAttribute(
"style:num-suffix", m_suffix );
324 if ( includeLevelAndProperties )
326 listLevelWriter.
startElement(
"style:list-level-properties" );
334int KoParagCounter::number(
const KoTextParag *paragraph )
337 if ( m_cache.number != -1 )
338 return m_cache.number;
341 if ( m_restartCounter ) {
342 Q_ASSERT( m_startNumber != -1 );
343 m_cache.number = m_startNumber;
344 return m_startNumber;
349 KoTextParag *otherParagraph = paragraph->prev();
352 switch ( m_numbering )
360 m_cache.number = m_startNumber;
362 while ( otherParagraph )
364 otherCounter = otherParagraph->counter();
366 ( otherCounter->m_numbering == NUM_CHAPTER ) &&
367 ( otherCounter->m_depth <= m_depth ) )
369 if ( ( otherCounter->m_depth == m_depth ) &&
370 ( otherCounter->m_style == m_style ) )
373 m_cache.number = otherCounter->number( otherParagraph ) + 1;
378 m_cache.number = m_startNumber;
382 otherParagraph = otherParagraph->prev();
386 m_cache.number = m_startNumber;
388 while ( otherParagraph )
390 otherCounter = otherParagraph->counter();
393 if ( ( otherCounter->m_numbering == NUM_LIST ) &&
394 !
isBullet( otherCounter->m_style ) &&
395 ( otherCounter->m_depth <= m_depth ) )
397 if ( ( otherCounter->m_depth == m_depth ) &&
398 ( otherCounter->m_style == m_style ) )
401 m_cache.number = otherCounter->number( otherParagraph ) + 1;
406 m_cache.number = m_startNumber;
411 if ( otherCounter->m_numbering == NUM_CHAPTER )
413 m_cache.number = m_startNumber;
423 otherParagraph = otherParagraph->prev();
427 Q_ASSERT( m_cache.number != -1 );
428 return m_cache.number;
437KoTextParag *KoParagCounter::parent(
const KoTextParag *paragraph )
440 if ( m_cache.parent != INVALID_PARAG )
441 return m_cache.parent;
443 KoTextParag *otherParagraph = paragraph->prev();
447 switch ( m_numbering )
456 while ( otherParagraph )
458 otherCounter = otherParagraph->counter();
460 ( otherCounter->m_numbering == NUM_CHAPTER ) &&
461 ( otherCounter->m_depth < m_depth ) )
465 otherParagraph = otherParagraph->prev();
470 while ( otherParagraph )
472 otherCounter = otherParagraph->counter();
475 if ( ( otherCounter->m_numbering == NUM_LIST ) &&
476 !
isBullet( otherCounter->m_style ) &&
477 ( otherCounter->m_depth < m_depth ) )
482 if ( otherCounter->m_numbering == NUM_CHAPTER )
488 otherParagraph = otherParagraph->prev();
492 m_cache.parent = otherParagraph;
493 return m_cache.parent;
503 element.setAttribute(
"type",
static_cast<int>( m_style ) );
504 element.setAttribute(
"depth", m_depth );
505 if ( (Style)m_style == STYLE_CUSTOMBULLET )
507 element.setAttribute(
"bullet", m_customBulletChar.unicode() );
508 if ( !m_customBulletFont.isEmpty() )
509 element.setAttribute(
"bulletfont", m_customBulletFont );
511 if ( !m_prefix.isEmpty() )
512 element.setAttribute(
"lefttext", m_prefix );
513 if ( !m_suffix.isEmpty() )
514 element.setAttribute(
"righttext", m_suffix );
515 if ( m_startNumber != 1 )
516 element.setAttribute(
"start", m_startNumber );
518 element.setAttribute(
"display-levels", m_displayLevels );
520 if ( m_numbering != NUM_NONE && m_numbering != NUM_FOOTNOTE )
521 element.setAttribute(
"numberingtype",
static_cast<int>( m_numbering ) );
522 if ( !m_custom.isEmpty() )
523 element.setAttribute(
"customdef", m_custom );
524 if ( m_restartCounter )
525 element.setAttribute(
"restart",
"true" );
526 if ( !m_cache.text.isEmpty() )
527 element.setAttribute(
"text", m_cache.text );
528 element.setAttribute(
"align", m_align );
531void KoParagCounter::setCustom( TQString c )
537void KoParagCounter::setCustomBulletCharacter( TQChar c )
539 m_customBulletChar = c;
543void KoParagCounter::setCustomBulletFont( TQString f )
545 m_customBulletFont = f;
549void KoParagCounter::setDepth(
unsigned int d )
555void KoParagCounter::setNumbering( Numbering n )
561void KoParagCounter::setPrefix( TQString p )
566void KoParagCounter::setStartNumber(
int s )
572void KoParagCounter::setDisplayLevels(
int l )
578void KoParagCounter::setAlignment(
int a )
584void KoParagCounter::setStyle( Style s )
590void KoParagCounter::setSuffix( TQString s )
598 return m_startNumber;
603 return m_displayLevels;
611KoParagCounter::Style KoParagCounter::style()
const
616TQString KoParagCounter::suffix()
const
623 return m_restartCounter;
626void KoParagCounter::setRestartCounter(
bool restart )
628 m_restartCounter = restart;
635 if ( m_numbering == NUM_NONE )
640 if ( bullet && m_numbering == NUM_CHAPTER ) {
655 if ( m_numbering == NUM_LIST )
659 text.setNum( m_cache.number );
662 text = makeAlphaLowerNumber( m_cache.number );
665 text = makeAlphaUpperNumber( m_cache.number );
667 case STYLE_ROM_NUM_L:
668 text = makeRomanNumber( m_cache.number ).lower();
670 case STYLE_ROM_NUM_U:
671 text = makeRomanNumber( m_cache.number ).upper();
676 text.setNum( m_cache.number );
685 case KoParagCounter::STYLE_DISCBULLET:
688 case KoParagCounter::STYLE_SQUAREBULLET:
691 case KoParagCounter::STYLE_BOXBULLET:
694 case KoParagCounter::STYLE_CIRCLEBULLET:
697 case KoParagCounter::STYLE_CUSTOMBULLET:
698 text = m_customBulletChar;
708TQString KoParagCounter::text(
const KoTextParag *paragraph )
711 if ( !m_cache.text.isNull() )
715 if ( m_displayLevels > 1 && m_numbering != NUM_NONE )
717 KoTextParag* p = parent( paragraph );
727 for (
unsigned i = 0; i < str.length(); i++ )
733 int missingParents = m_depth - level - p->counter()->m_depth;
735 level += missingParents;
736 for ( ; missingParents > 0 ; --missingParents )
740 m_cache.text.prepend( str );
743 p = counter->parent( p );
748 KoTextDocument* textdoc = paragraph->textDocument();
749 if ( paragraph == textdoc->firstParag() && paragraph == textdoc->lastParag() )
750 m_cache.text.prepend(
"1." );
752 m_cache.text.prepend(
"0." );
760 m_cache.text.append(
levelText( paragraph ) );
766 m_cache.text.prepend( paragraph->string()->isRightToLeft() ? suffix() :
prefix() );
767 m_cache.text.append( paragraph->string()->isRightToLeft() ?
prefix() : suffix() );
771int KoParagCounter::width(
const KoTextParag *paragraph )
774 if ( m_cache.width != -1 && counterFormat( paragraph ) == m_cache.counterFormat )
775 return m_cache.width;
778 if ( m_cache.text.isNull() )
782 if ( m_cache.counterFormat )
783 m_cache.counterFormat->removeRef();
784 m_cache.counterFormat = counterFormat( paragraph );
785 m_cache.counterFormat->addRef();
787 if ( m_style != STYLE_NONE || m_numbering == NUM_FOOTNOTE)
789 TQString text = m_cache.text;
790 if ( m_style == STYLE_CUSTOMBULLET && !text.isEmpty() )
794 else if ( !text.isEmpty() )
796 TQFontMetrics fm = m_cache.counterFormat->refFontMetrics();
797 for (
unsigned int i = 0; i < text.length(); i++ )
799 m_cache.width += fm.width( text[i] );
805 return m_cache.width;
811 Q_ASSERT( m_cache.width != -1 );
812 Q_ASSERT( m_cache.counterFormat );
814 TQFontMetrics fm = m_cache.counterFormat->refFontMetrics();
816 for (
unsigned int i = 0; i < text.length(); i++ )
817 x += fm.width( text[i] );
823KoTextFormat* KoParagCounter::counterFormat(
const KoTextParag *paragraph )
827 format.setVAlign( KoTextFormat::AlignNormal );
828 return paragraph->textDocument()->formatCollection()->format( &format );
834const TQCString RNUnits[] = {
"",
"i",
"ii",
"iii",
"iv",
"v",
"vi",
"vii",
"viii",
"ix"};
835const TQCString RNTens[] = {
"",
"x",
"xx",
"xxx",
"xl",
"l",
"lx",
"lxx",
"lxxx",
"xc"};
836const TQCString RNHundreds[] = {
"",
"c",
"cc",
"ccc",
"cd",
"d",
"dc",
"dcc",
"dccc",
"cm"};
837const TQCString RNThousands[] = {
"",
"m",
"mm",
"mmm"};
839TQString KoParagCounter::makeRomanNumber(
int n )
842 return TQString::fromLatin1( RNThousands[ ( n / 1000 ) ] +
843 RNHundreds[ ( n / 100 ) % 10 ] +
844 RNTens[ ( n / 10 ) % 10 ] +
845 RNUnits[ ( n ) % 10 ] );
847 kdWarning(32500) <<
"makeRomanNumber: n=" << n << endl;
848 return TQString::number( n );
852TQString KoParagCounter::makeAlphaUpperNumber(
int n )
858 bottomDigit = (n-1) % 26;
860 tmp.prepend( TQChar(
'A' + bottomDigit ) );
862 tmp.prepend( TQChar(
'A' + n -1 ) );
866TQString KoParagCounter::makeAlphaLowerNumber(
int n )
872 bottomDigit = (n-1) % 26;
874 tmp.prepend( TQChar(
'a' + bottomDigit ) );
876 tmp.prepend( TQChar(
'a' + n - 1 ) );
880int KoParagCounter::fromRomanNumber(
const TQString &
string )
884 const int stringLen =
string.length();
886 for (
int base = 1000; base >= 1 && stringStart < stringLen; base /= 10)
894 rnNum =
sizeof (RNThousands) /
sizeof (
const TQCString);
898 rnNum =
sizeof (RNHundreds) /
sizeof (
const TQCString);
902 rnNum =
sizeof (RNTens) /
sizeof (
const TQCString);
907 rnNum =
sizeof (RNUnits) /
sizeof (
const TQCString);
912 for (
int i = rnNum - 1; i >= 1; i--)
914 const int rnLength = rn[i].length();
915 if (
string.mid(stringStart,rnLength) == (
const char*)rn[i])
918 stringStart += rnLength;
924 return (ret == 0 || stringStart != stringLen) ? -1 : ret;
927int KoParagCounter::fromAlphaUpperNumber(
const TQString &
string )
931 const int len =
string.length();
932 for (
int i = 0; i < len; i++)
934 const int add = char(
string[i]) -
'A' + 1;
936 if (add >= 1 && add <= 26)
937 ret = ret * 26 + add;
945 return (ret == 0) ? -1 : ret;
948int KoParagCounter::fromAlphaLowerNumber(
const TQString &
string )
952 const int len =
string.length();
953 for (
int i = 0; i < len; i++)
955 const int add = char(
string[i]) -
'a' + 1;
957 if (add >= 1 && add <= 26)
958 ret = ret * 26 + add;
966 return (ret == 0) ? -1 : ret;
970void KoParagCounter::printRTDebug( KoTextParag* parag )
972 TQString additionalInfo;
974 additionalInfo =
"[restartCounter]";
975 if ( m_style == STYLE_CUSTOMBULLET )
976 additionalInfo +=
" [customBullet: " + TQString::number( m_customBulletChar.unicode() )
977 +
" in font '" + m_customBulletFont +
"']";
978 static const char *
const s_numbering[] = {
"List",
"Chapter",
"None",
"Footnote" };
979 kdDebug(32500) <<
" Counter style=" << style()
980 <<
" numbering=" << s_numbering[
numbering() ]
981 <<
" depth=" <<
depth()
982 <<
" number=" << number( parag )
983 <<
" text='" << text( parag ) <<
"'"
984 <<
" width=" << width( parag )
985 << additionalInfo << endl;
void addChildElement(const TQString &elementName, const TQString &elementContents)
Add a child element to the style properties.
TQDomElement currentListStyleProperties() const
TQDomElement currentListStyle() const
TQDomElement currentListStyleTextProperties() const
Used during loading of Oasis format (and discarded at the end of the loading).
This is the structure associated with a paragraph (KoTextParag), to define the bullet or numbering of...
TQString custom() const
The string STYLE_CUSTOM.
TQChar customBulletCharacter() const
The character and font for STYLE_CUSTOMBULLET.
unsigned int depth() const
The level of the numbering.
int alignment() const
Counter alignment.
void loadOasis(KoOasisContext &context, int restartNumbering, bool orderedList, bool heading, int level, bool loadingStyle=false)
Load from OASIS XML.
void invalidate()
Invalidate the internal cache.
TQString prefix() const
Prefix and suffix strings.
void saveOasis(KoGenStyle &listStyle, bool savingStyle=false) const
Save as OASIS XML.
void load(TQDomElement &element)
KOffice-1.3 loading code.
void saveOasisListLevel(KoXmlWriter &listLevelWriter, bool includeLevelAndProperties, bool savingStyle=false) const
Part of saveOasis that is shared with KoStyleCollection::saveOasisOutlineStyles and KWVariableSetting...
Numbering numbering() const
Numbering type and style.
void save(TQDomElement &element)
KOffice-1.3 saving code.
int bulletX()
X position of the bullet ( i.e.
void loadOasisListStyle(const TQDomElement &listStyle, const TQDomElement &listStyleProperties, const TQDomElement &listStyleTextProperties, int restartNumbering, bool orderedList, bool heading, int level, bool loadingStyle)
Part of loadOasis that is shared with KWVariableSettings::loadOasis for footnotes/endnotes.
TQString levelText(const KoTextParag *paragraph)
Return the current value of the counter as a text.
int startNumber() const
Starting number.
int displayLevels() const
Number of levels whose numbers are displayed at the current level.
bool isBullet() const
Does this counter have a bullet style?
bool restartCounter() const
Should this counter start at "startNumber" (instead of being the 'last counter of the same type + 1')
static TQCString saveOasisAlignment(TQt::AlignmentFlags alignment)
Convert an alignment flag into an alignment string (save)
Each character (KoTextStringChar) points to a KoTextFormat that defines the formatting of that charac...
static double ptToLayoutUnitPt(double pt)
Not zoom dependent.
A class for writing out XML (to any TQIODevice), with a special attention on performance.
void startElement(const char *tagName, bool indentInside=true)
Start a new element, as a child of the current element.
void endElement()
Terminate the current element.
void addAttribute(const char *attrName, const TQString &value)
Overloaded version of addAttribute( const char*, const char* ), which is a bit slower because it need...