lib

KoParagStyle.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001-2005 David Faure <faure@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*/
18
19#include "KoParagStyle.h"
20#include "KoOasisContext.h"
21#include "KoParagCounter.h"
22
23#include <KoGenStyles.h>
24#include <KoXmlWriter.h>
25#include <KoXmlNS.h>
26
27#include <kdebug.h>
28#include <tdelocale.h>
29
30#include <tqdom.h>
31
32KoCharStyle::KoCharStyle( const TQString & name )
33 : KoUserStyle( name )
34{
35}
36
38{
39 return m_format;
40}
41
43{
44 return m_format;
45}
46
48
49KoParagStyle::KoParagStyle( const TQString & name )
50 : KoCharStyle( name )
51{
52 m_followingStyle = this;
53
54 // This way, KoTextParag::setParagLayout also sets the style pointer, to this style
55 m_paragLayout.style = this;
56 m_parentStyle = 0L;
57 m_inheritedParagLayoutFlag = 0;
58 m_inheritedFormatFlag = 0;
59 m_bOutline = false;
60}
61
63 : KoCharStyle( rhs)
64{
65 *this = rhs;
66}
67
68KoParagStyle::~KoParagStyle()
69{
70}
71
72void KoParagStyle::operator=( const KoParagStyle &rhs )
73{
74 KoCharStyle::operator=( rhs );
75 m_paragLayout = rhs.m_paragLayout;
76 m_followingStyle = rhs.m_followingStyle;
77 m_paragLayout.style = this; // must always be "this"
78 m_parentStyle = rhs.m_parentStyle;
79 m_inheritedParagLayoutFlag = rhs.m_inheritedParagLayoutFlag;
80 m_inheritedFormatFlag = rhs.m_inheritedFormatFlag;
81 m_bOutline = rhs.m_bOutline;
82}
83
84void KoParagStyle::setFollowingStyle( KoParagStyle *fst )
85{
86 m_followingStyle = fst;
87}
88
89void KoParagStyle::saveStyle( TQDomElement & parentElem )
90{
91 m_paragLayout.saveParagLayout( parentElem, m_paragLayout.alignment );
92
93 if ( followingStyle() )
94 {
95 TQDomElement element = parentElem.ownerDocument().createElement( "FOLLOWING" );
96 parentElem.appendChild( element );
97 element.setAttribute( "name", followingStyle()->displayName() );
98 }
99 // TODO save parent style, and inherited flags.
100
101 parentElem.setAttribute( "outline", m_bOutline ? "true" : "false" );
102}
103
104void KoParagStyle::loadStyle( TQDomElement & parentElem, int docVersion )
105{
106 KoParagLayout layout;
107 KoParagLayout::loadParagLayout( layout, parentElem, docVersion );
108
109 // This way, KoTextParag::setParagLayout also sets the style pointer, to this style
110 layout.style = this;
111 m_paragLayout = layout;
112
113 // Load name
114 TQDomElement nameElem = parentElem.namedItem("NAME").toElement();
115 if ( !nameElem.isNull() ) {
116 m_name = nameElem.attribute("value");
117 m_displayName = i18n( "Style name", m_name.utf8() );
118 } else
119 kdWarning() << "No NAME tag in LAYOUT -> no name for this style!" << endl;
120
121 // The followingStyle stuff has to be done after loading all styles.
122
123 m_bOutline = parentElem.attribute( "outline" ) == "true";
124}
125
126void KoParagStyle::loadStyle( TQDomElement & styleElem, KoOasisContext& context )
127{
128 // Load name
129 m_name = styleElem.attributeNS( KoXmlNS::style, "name", TQString() );
130 m_displayName = styleElem.attributeNS( KoXmlNS::style, "display-name", TQString() );
131 if ( m_displayName.isEmpty() )
132 m_displayName = m_name;
133
134 // OOo hack
135 //m_bOutline = m_name.startsWith( "Heading" );
136 // real OASIS solution:
137 m_bOutline = styleElem.hasAttributeNS( KoXmlNS::style, "default-outline-level" );
138
139 context.styleStack().save();
140 context.addStyles( &styleElem, "paragraph" ); // Load all parents - only because we don't support inheritance.
141 KoParagLayout layout;
142 KoParagLayout::loadOasisParagLayout( layout, context );
143
144 // loadOasisParagLayout doesn't load the counter. It's modelled differently for parags and for styles.
145 int level = 0;
146 bool listOK = false;
147 const TQString listStyleName = styleElem.attributeNS( KoXmlNS::style, "list-style-name", TQString() );
148 if ( m_bOutline ) {
149 level = styleElem.attributeNS( KoXmlNS::style, "default-outline-level", TQString() ).toInt(); // 1-based
150 listOK = context.pushOutlineListLevelStyle( level );
151 // allow overriding the outline numbering, see http://lists.oasis-open.org/archives/office/200310/msg00033.html
152 if ( !listStyleName.isEmpty() )
153 context.pushListLevelStyle( listStyleName, level );
154 }
155 else {
156 // ######## BIG difference here. In the OOo/OASIS format, one list style has infos for 10 list levels...
157 // ###### so we can't know a level at this point...
158
159 // The only solution I can think of, to preserve document content when importing OO but
160 // not necessarily the styles used when editing, is:
161 // 1) when importing from OOo, convert each non-heading style with numbering
162 // into 10 kotext styles (at least those used by the document) [TODO]
163 // 2) for KWord's own loading/saving, to add a hack into the file format, say
164 // style:default-level.
165 // Note that default-level defaults to "1", i.e. works for non-nested OOo lists too.
166 level = styleElem.attributeNS( KoXmlNS::style, "default-level", "1" ).toInt(); // 1-based
167 listOK = !listStyleName.isEmpty();
168 if ( listOK )
169 listOK = context.pushListLevelStyle( listStyleName, level );
170 }
171 if ( listOK ) {
172 const TQDomElement listStyle = context.listStyleStack().currentListStyle();
173 // The tag is either text:list-level-style-number or text:list-level-style-bullet
174 const bool ordered = listStyle.localName() == "list-level-style-number";
175 Q_ASSERT( !layout.counter );
176 layout.counter = new KoParagCounter;
177 layout.counter->loadOasis( context, -1, ordered, m_bOutline, level, true );
178 context.listStyleStack().pop();
179 }
180
181 // This way, KoTextParag::setParagLayout also sets the style pointer, to this style
182 layout.style = this;
183 m_paragLayout = layout;
184
185 m_format.load( context );
186
187 context.styleStack().restore();
188}
189
190TQString KoParagStyle::saveStyle( KoGenStyles& genStyles, int styleType, const TQString& parentStyleName, KoSavingContext& context ) const
191{
192 KoGenStyle gs( styleType, "paragraph", parentStyleName );
193
194 gs.addAttribute( "style:display-name", m_displayName );
195 if ( m_paragLayout.counter ) {
196 if ( m_bOutline )
197 gs.addAttribute( "style:default-outline-level", (int)m_paragLayout.counter->depth() + 1 );
198 else if ( m_paragLayout.counter->depth() )
199 // ### kword-specific attribute, see loadOasis
200 gs.addAttribute( "style:default-level", (int)m_paragLayout.counter->depth() + 1 );
201
202 if ( m_paragLayout.counter->numbering() != KoParagCounter::NUM_NONE &&
203 m_paragLayout.counter->style() != KoParagCounter::STYLE_NONE )
204 {
205 KoGenStyle listStyle( KoGenStyle::STYLE_LIST /*, no family*/ );
206 m_paragLayout.counter->saveOasis( listStyle, true );
207 // This display-name will probably look nicer in OO, but this also means
208 // no re-use possible between list styles...
209 listStyle.addAttribute( "style:display-name",
210 i18n( "Numbering Style for %1" ).arg( m_displayName ) );
211
212 TQString autoListStyleName = genStyles.lookup( listStyle, "L", KoGenStyles::ForceNumbering );
213 gs.addAttribute( "style:list-style-name", autoListStyleName );
214 }
215 }
216
217 m_paragLayout.saveOasis( gs, context, true );
218
219 m_format.save( gs, context );
220
221 // try to preserve existing internal name, if it looks adequate (no spaces)
222 // ## TODO: check XML-Schemacs NCName conformity
223 bool nameIsConform = !m_name.isEmpty() && m_name.find( ' ' ) == -1;
224 TQString newName;
225 if ( nameIsConform )
226 newName = genStyles.lookup( gs, m_name, KoGenStyles::DontForceNumbering );
227 else
228 newName = genStyles.lookup( gs, "U", KoGenStyles::ForceNumbering );
229 const_cast<KoParagStyle*>( this )->m_name = newName;
230 return m_name;
231}
232
233const KoParagLayout & KoParagStyle::paragLayout() const
234{
235 return m_paragLayout;
236}
237
238KoParagLayout & KoParagStyle::paragLayout()
239{
240 return m_paragLayout;
241}
242
243void KoParagStyle::propagateChanges( int paragLayoutFlag, int /*formatFlag*/ )
244{
245 if ( !m_parentStyle )
246 return;
247 if ( !(paragLayoutFlag & KoParagLayout::Alignment) )
248 m_paragLayout.alignment = m_parentStyle->paragLayout().alignment;
249 if ( !(paragLayoutFlag & KoParagLayout::Margins) )
250 for ( int i = 0 ; i < 5 ; ++i )
251 m_paragLayout.margins[i] = m_parentStyle->paragLayout().margins[i];
252 if ( !(paragLayoutFlag & KoParagLayout::LineSpacing) )
253 {
254 m_paragLayout.setLineSpacingValue(m_parentStyle->paragLayout().lineSpacingValue());
255 m_paragLayout.lineSpacingType = m_parentStyle->paragLayout().lineSpacingType;
256 }
257 if ( !(paragLayoutFlag & KoParagLayout::Borders) )
258 {
259 m_paragLayout.leftBorder = m_parentStyle->paragLayout().leftBorder;
260 m_paragLayout.rightBorder = m_parentStyle->paragLayout().rightBorder;
261 m_paragLayout.topBorder = m_parentStyle->paragLayout().topBorder;
262 m_paragLayout.bottomBorder = m_parentStyle->paragLayout().bottomBorder;
263 m_paragLayout.joinBorder = m_parentStyle->paragLayout().joinBorder;
264 }
265 if ( !(paragLayoutFlag & KoParagLayout::BulletNumber) )
266 m_paragLayout.counter = m_parentStyle->paragLayout().counter;
267 if ( !(paragLayoutFlag & KoParagLayout::Tabulator) )
268 m_paragLayout.setTabList(m_parentStyle->paragLayout().tabList());
269#if 0
270 if ( paragLayoutFlag == KoParagLayout::All )
271 {
272 setDirection( static_cast<TQChar::Direction>(layout.direction) );
273 // Don't call applyStyle from here, it would overwrite any paragraph-specific settings
274 setStyle( layout.style );
275 }
276#endif
277 // TODO a flag for the "is outline" bool? Otherwise we have no way to inherit
278 // that property (and possibly reset it).
279}
280
281void KoParagStyle::setOutline( bool b )
282{
283 m_bOutline = b;
284}
A KoCharStyle is a set of formatting attributes (font, color, etc.) to be applied to a run of text.
KoCharStyle(const TQString &name)
Create a blank style (with default attributes)
const KoTextFormat & format() const
Return a format.
A generic style, i.e.
void addAttribute(const TQString &attrName, const TQString &attrValue)
Add an attribute to the style The difference between property and attributes is a bit oasis-format-sp...
Repository of styles used during saving of OASIS/OOo file.
Definition KoGenStyles.h:60
TQString lookup(const KoGenStyle &style, const TQString &name=TQString(), int flags=NoFlag)
Look up a style in the collection, inserting it if necessary.
void pop()
Removes the style on top of the stack.
TQDomElement currentListStyle() const
Used during loading of Oasis format (and discarded at the end of the loading).
bool pushListLevelStyle(const TQString &listStyleName, int level)
Used for lists (numbered paragraphs)
bool pushOutlineListLevelStyle(int level)
Used for outline levels.
void addStyles(const TQDomElement *style, const char *family, bool usingStylesAutoStyles=false)
Add style to the stack, as well as all its parent styles and the default style for this style family.
This is the structure associated with a paragraph (KoTextParag), to define the bullet or numbering of...
unsigned int depth() const
The level of the numbering.
void loadOasis(KoOasisContext &context, int restartNumbering, bool orderedList, bool heading, int level, bool loadingStyle=false)
Load from OASIS XML.
void saveOasis(KoGenStyle &listStyle, bool savingStyle=false) const
Save as OASIS XML.
Numbering numbering() const
Numbering type and style.
This class holds the paragraph-specific formatting information It's separated from KoTextParag so tha...
static void loadOasisParagLayout(KoParagLayout &layout, KoOasisContext &context)
Load this parag layout from Oasis XML.
void saveOasis(KoGenStyle &gs, KoSavingContext &context, bool savingStyle) const
Save this parag layout to Oasis XML.
static void loadParagLayout(KoParagLayout &layout, const TQDomElement &parentElem, int docVersion=2)
Load this parag layout from XML.
double margins[5]
left, right, top, bottom, firstLineSpacing - in pt
KoParagCounter * counter
can be 0 if no counter set
char alignment
Alignment flag (AlignAuto/AlignLeft/AlignRight/AlignJustify)
void saveParagLayout(TQDomElement &parentElem, int alignment) const
Save this parag layout to XML.
A paragraph style is a combination of a character style and paragraph-layout attributes,...
void saveStyle(TQDomElement &parentElem)
Saves the name, layout, the following style and the outline bool.
KoParagStyle(const TQString &name)
Create a blank style (with default attributes)
void loadStyle(TQDomElement &parentElem, int docVersion=2)
Loads the name, layout and the outline bool.
Used during saving to Oasis format (and discarded at the end of the saving).
void save()
Save the current state of the stack.
void restore()
Restore the stack to the state it was at the corresponding save() call.
Each character (KoTextStringChar) points to a KoTextFormat that defines the formatting of that charac...
void save(KoGenStyle &gs, KoSavingContext &context, KoTextFormat *refFormat=0) const
Save a text format to OASIS XML Only saves what differs from @refFormat, if set.
void load(KoOasisContext &context)
Load a text format from OASIS XML.
Base class for any kind of style that the user can create/modify/delete/display.
Definition KoUserStyle.h:34
TQString displayName() const
The user-visible name (e.g. translated, or set by the user)