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
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}
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.
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...
void loadOasis(KoOasisContext &context, int restartNumbering, bool orderedList, bool heading, int level, bool loadingStyle=false)
Load from OASIS XML.
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.
static void loadParagLayout(KoParagLayout &layout, const TQDomElement &parentElem, int docVersion=2)
Load this parag layout from XML.
KoParagCounter * counter
can be 0 if no counter set
char alignment
Alignment flag (AlignAuto/AlignLeft/AlignRight/AlignJustify).
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).
Each character (KoTextStringChar) points to a KoTextFormat that defines the formatting of that charac...
TQString displayName() const
The user-visible name (e.g. translated, or set by the user).
TQString name() const
The internal name (used for loading/saving, but not shown to the user) Should be unique in a given st...
Definition KoUserStyle.h:40