|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2001-2005 David Faure <faure@kde.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "KoParagStyle.h"
|
|
|
|
#include "KoOasisContext.h"
|
|
|
|
#include "KoParagCounter.h"
|
|
|
|
|
|
|
|
#include <KoGenStyles.h>
|
|
|
|
#include <KoXmlWriter.h>
|
|
|
|
#include <KoXmlNS.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
|
|
|
|
#include <tqdom.h>
|
|
|
|
|
|
|
|
KoCharStyle::KoCharStyle( const TQString & name )
|
|
|
|
: KoUserStyle( name )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
const KoTextFormat & KoCharStyle::format() const
|
|
|
|
{
|
|
|
|
return m_format;
|
|
|
|
}
|
|
|
|
|
|
|
|
KoTextFormat & KoCharStyle::format()
|
|
|
|
{
|
|
|
|
return m_format;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
|
|
|
|
KoParagStyle::KoParagStyle( const TQString & name )
|
|
|
|
: KoCharStyle( name )
|
|
|
|
{
|
|
|
|
m_followingStyle = this;
|
|
|
|
|
|
|
|
// This way, KoTextParag::setParagLayout also sets the style pointer, to this style
|
|
|
|
m_paragLayout.style = this;
|
|
|
|
m_parentStyle = 0L;
|
|
|
|
m_inheritedParagLayoutFlag = 0;
|
|
|
|
m_inheritedFormatFlag = 0;
|
|
|
|
m_bOutline = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
KoParagStyle::KoParagStyle( const KoParagStyle & rhs )
|
|
|
|
: KoCharStyle( rhs)
|
|
|
|
{
|
|
|
|
*this = rhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
KoParagStyle::~KoParagStyle()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoParagStyle::operator=( const KoParagStyle &rhs )
|
|
|
|
{
|
|
|
|
KoCharStyle::operator=( rhs );
|
|
|
|
m_paragLayout = rhs.m_paragLayout;
|
|
|
|
m_followingStyle = rhs.m_followingStyle;
|
|
|
|
m_paragLayout.style = this; // must always be "this"
|
|
|
|
m_parentStyle = rhs.m_parentStyle;
|
|
|
|
m_inheritedParagLayoutFlag = rhs.m_inheritedParagLayoutFlag;
|
|
|
|
m_inheritedFormatFlag = rhs.m_inheritedFormatFlag;
|
|
|
|
m_bOutline = rhs.m_bOutline;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoParagStyle::setFollowingStyle( KoParagStyle *fst )
|
|
|
|
{
|
|
|
|
m_followingStyle = fst;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoParagStyle::saveStyle( TQDomElement & parentElem )
|
|
|
|
{
|
|
|
|
m_paragLayout.saveParagLayout( parentElem, m_paragLayout.alignment );
|
|
|
|
|
|
|
|
if ( followingStyle() )
|
|
|
|
{
|
|
|
|
TQDomElement element = parentElem.ownerDocument().createElement( "FOLLOWING" );
|
|
|
|
parentElem.appendChild( element );
|
|
|
|
element.setAttribute( "name", followingStyle()->displayName() );
|
|
|
|
}
|
|
|
|
// TODO save parent style, and inherited flags.
|
|
|
|
|
|
|
|
parentElem.setAttribute( "outline", m_bOutline ? "true" : "false" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoParagStyle::loadStyle( TQDomElement & parentElem, int docVersion )
|
|
|
|
{
|
|
|
|
KoParagLayout layout;
|
|
|
|
KoParagLayout::loadParagLayout( layout, parentElem, docVersion );
|
|
|
|
|
|
|
|
// This way, KoTextParag::setParagLayout also sets the style pointer, to this style
|
|
|
|
layout.style = this;
|
|
|
|
m_paragLayout = layout;
|
|
|
|
|
|
|
|
// Load name
|
|
|
|
TQDomElement nameElem = parentElem.namedItem("NAME").toElement();
|
|
|
|
if ( !nameElem.isNull() ) {
|
|
|
|
m_name = nameElem.attribute("value");
|
|
|
|
m_displayName = i18n( "Style name", m_name.utf8() );
|
|
|
|
} else
|
|
|
|
kdWarning() << "No NAME tag in LAYOUT -> no name for this style!" << endl;
|
|
|
|
|
|
|
|
// The followingStyle stuff has to be done after loading all styles.
|
|
|
|
|
|
|
|
m_bOutline = parentElem.attribute( "outline" ) == "true";
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoParagStyle::loadStyle( TQDomElement & styleElem, KoOasisContext& context )
|
|
|
|
{
|
|
|
|
// Load name
|
|
|
|
m_name = styleElem.attributeNS( KoXmlNS::style, "name", TQString() );
|
|
|
|
m_displayName = styleElem.attributeNS( KoXmlNS::style, "display-name", TQString() );
|
|
|
|
if ( m_displayName.isEmpty() )
|
|
|
|
m_displayName = m_name;
|
|
|
|
|
|
|
|
// OOo hack
|
|
|
|
//m_bOutline = m_name.startsWith( "Heading" );
|
|
|
|
// real OASIS solution:
|
|
|
|
m_bOutline = styleElem.hasAttributeNS( KoXmlNS::style, "default-outline-level" );
|
|
|
|
|
|
|
|
context.styleStack().save();
|
|
|
|
context.addStyles( &styleElem, "paragraph" ); // Load all parents - only because we don't support inheritance.
|
|
|
|
KoParagLayout layout;
|
|
|
|
KoParagLayout::loadOasisParagLayout( layout, context );
|
|
|
|
|
|
|
|
// loadOasisParagLayout doesn't load the counter. It's modelled differently for parags and for styles.
|
|
|
|
int level = 0;
|
|
|
|
bool listOK = false;
|
|
|
|
const TQString listStyleName = styleElem.attributeNS( KoXmlNS::style, "list-style-name", TQString() );
|
|
|
|
if ( m_bOutline ) {
|
|
|
|
level = styleElem.attributeNS( KoXmlNS::style, "default-outline-level", TQString() ).toInt(); // 1-based
|
|
|
|
listOK = context.pushOutlineListLevelStyle( level );
|
|
|
|
// allow overriding the outline numbering, see http://lists.oasis-open.org/archives/office/200310/msg00033.html
|
|
|
|
if ( !listStyleName.isEmpty() )
|
|
|
|
context.pushListLevelStyle( listStyleName, level );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// ######## BIG difference here. In the OOo/OASIS format, one list style has infos for 10 list levels...
|
|
|
|
// ###### so we can't know a level at this point...
|
|
|
|
|
|
|
|
// The only solution I can think of, to preserve document content when importing OO but
|
|
|
|
// not necessarily the styles used when editing, is:
|
|
|
|
// 1) when importing from OOo, convert each non-heading style with numbering
|
|
|
|
// into 10 kotext styles (at least those used by the document) [TODO]
|
|
|
|
// 2) for KWord's own loading/saving, to add a hack into the file format, say
|
|
|
|
// style:default-level.
|
|
|
|
// Note that default-level defaults to "1", i.e. works for non-nested OOo lists too.
|
|
|
|
level = styleElem.attributeNS( KoXmlNS::style, "default-level", "1" ).toInt(); // 1-based
|
|
|
|
listOK = !listStyleName.isEmpty();
|
|
|
|
if ( listOK )
|
|
|
|
listOK = context.pushListLevelStyle( listStyleName, level );
|
|
|
|
}
|
|
|
|
if ( listOK ) {
|
|
|
|
const TQDomElement listStyle = context.listStyleStack().currentListStyle();
|
|
|
|
// The tag is either text:list-level-style-number or text:list-level-style-bullet
|
|
|
|
const bool ordered = listStyle.localName() == "list-level-style-number";
|
|
|
|
Q_ASSERT( !layout.counter );
|
|
|
|
layout.counter = new KoParagCounter;
|
|
|
|
layout.counter->loadOasis( context, -1, ordered, m_bOutline, level, true );
|
|
|
|
context.listStyleStack().pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// This way, KoTextParag::setParagLayout also sets the style pointer, to this style
|
|
|
|
layout.style = this;
|
|
|
|
m_paragLayout = layout;
|
|
|
|
|
|
|
|
m_format.load( context );
|
|
|
|
|
|
|
|
context.styleStack().restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KoParagStyle::saveStyle( KoGenStyles& genStyles, int styleType, const TQString& parentStyleName, KoSavingContext& context ) const
|
|
|
|
{
|
|
|
|
KoGenStyle gs( styleType, "paragraph", parentStyleName );
|
|
|
|
|
|
|
|
gs.addAttribute( "style:display-name", m_displayName );
|
|
|
|
if ( m_paragLayout.counter ) {
|
|
|
|
if ( m_bOutline )
|
|
|
|
gs.addAttribute( "style:default-outline-level", (int)m_paragLayout.counter->depth() + 1 );
|
|
|
|
else if ( m_paragLayout.counter->depth() )
|
|
|
|
// ### kword-specific attribute, see loadOasis
|
|
|
|
gs.addAttribute( "style:default-level", (int)m_paragLayout.counter->depth() + 1 );
|
|
|
|
|
|
|
|
if ( m_paragLayout.counter->numbering() != KoParagCounter::NUM_NONE &&
|
|
|
|
m_paragLayout.counter->style() != KoParagCounter::STYLE_NONE )
|
|
|
|
{
|
|
|
|
KoGenStyle listStyle( KoGenStyle::STYLE_LIST /*, no family*/ );
|
|
|
|
m_paragLayout.counter->saveOasis( listStyle, true );
|
|
|
|
// This display-name will probably look nicer in OO, but this also means
|
|
|
|
// no re-use possible between list styles...
|
|
|
|
listStyle.addAttribute( "style:display-name",
|
|
|
|
i18n( "Numbering Style for %1" ).arg( m_displayName ) );
|
|
|
|
|
|
|
|
TQString autoListStyleName = genStyles.lookup( listStyle, "L", KoGenStyles::ForceNumbering );
|
|
|
|
gs.addAttribute( "style:list-style-name", autoListStyleName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_paragLayout.saveOasis( gs, context, true );
|
|
|
|
|
|
|
|
m_format.save( gs, context );
|
|
|
|
|
|
|
|
// try to preserve existing internal name, if it looks adequate (no spaces)
|
|
|
|
// ## TODO: check XML-Schemacs NCName conformity
|
|
|
|
bool nameIsConform = !m_name.isEmpty() && m_name.find( ' ' ) == -1;
|
|
|
|
TQString newName;
|
|
|
|
if ( nameIsConform )
|
|
|
|
newName = genStyles.lookup( gs, m_name, KoGenStyles::DontForceNumbering );
|
|
|
|
else
|
|
|
|
newName = genStyles.lookup( gs, "U", KoGenStyles::ForceNumbering );
|
|
|
|
const_cast<KoParagStyle*>( this )->m_name = newName;
|
|
|
|
return m_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
const KoParagLayout & KoParagStyle::paragLayout() const
|
|
|
|
{
|
|
|
|
return m_paragLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
KoParagLayout & KoParagStyle::paragLayout()
|
|
|
|
{
|
|
|
|
return m_paragLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoParagStyle::propagateChanges( int paragLayoutFlag, int /*formatFlag*/ )
|
|
|
|
{
|
|
|
|
if ( !m_parentStyle )
|
|
|
|
return;
|
|
|
|
if ( !(paragLayoutFlag & KoParagLayout::Alignment) )
|
|
|
|
m_paragLayout.alignment = m_parentStyle->paragLayout().alignment;
|
|
|
|
if ( !(paragLayoutFlag & KoParagLayout::Margins) )
|
|
|
|
for ( int i = 0 ; i < 5 ; ++i )
|
|
|
|
m_paragLayout.margins[i] = m_parentStyle->paragLayout().margins[i];
|
|
|
|
if ( !(paragLayoutFlag & KoParagLayout::LineSpacing) )
|
|
|
|
{
|
|
|
|
m_paragLayout.setLineSpacingValue(m_parentStyle->paragLayout().lineSpacingValue());
|
|
|
|
m_paragLayout.lineSpacingType = m_parentStyle->paragLayout().lineSpacingType;
|
|
|
|
}
|
|
|
|
if ( !(paragLayoutFlag & KoParagLayout::Borders) )
|
|
|
|
{
|
|
|
|
m_paragLayout.leftBorder = m_parentStyle->paragLayout().leftBorder;
|
|
|
|
m_paragLayout.rightBorder = m_parentStyle->paragLayout().rightBorder;
|
|
|
|
m_paragLayout.topBorder = m_parentStyle->paragLayout().topBorder;
|
|
|
|
m_paragLayout.bottomBorder = m_parentStyle->paragLayout().bottomBorder;
|
|
|
|
m_paragLayout.joinBorder = m_parentStyle->paragLayout().joinBorder;
|
|
|
|
}
|
|
|
|
if ( !(paragLayoutFlag & KoParagLayout::BulletNumber) )
|
|
|
|
m_paragLayout.counter = m_parentStyle->paragLayout().counter;
|
|
|
|
if ( !(paragLayoutFlag & KoParagLayout::Tabulator) )
|
|
|
|
m_paragLayout.setTabList(m_parentStyle->paragLayout().tabList());
|
|
|
|
#if 0
|
|
|
|
if ( paragLayoutFlag == KoParagLayout::All )
|
|
|
|
{
|
|
|
|
setDirection( static_cast<TQChar::Direction>(layout.direction) );
|
|
|
|
// Don't call applyStyle from here, it would overwrite any paragraph-specific settings
|
|
|
|
setStyle( layout.style );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// TODO a flag for the "is outline" bool? Otherwise we have no way to inherit
|
|
|
|
// that property (and possibly reset it).
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoParagStyle::setOutline( bool b )
|
|
|
|
{
|
|
|
|
m_bOutline = b;
|
|
|
|
}
|