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 )
182 const TQDomElement listStyle = context.listStyleStack().currentListStyle();
183 const TQDomElement listStyleProperties = context.listStyleStack().currentListStyleProperties();
184 const TQDomElement listStyleTextProperties = context.listStyleStack().currentListStyleTextProperties();
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();
350 KoParagCounter *otherCounter;
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.
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...