|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
|
|
|
|
Copyright (c) 2003 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 as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
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 "KoStyleStack.h"
|
|
|
|
#include "KoUnit.h"
|
|
|
|
#include "KoDom.h"
|
|
|
|
#include "KoXmlNS.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
//#define DEBUG_STYLESTACK
|
|
|
|
|
|
|
|
KoStyleStack::KoStyleStack()
|
|
|
|
: m_styleNSURI( KoXmlNS::style ), m_foNSURI( KoXmlNS::fo )
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
KoStyleStack::KoStyleStack( const char* styleNSURI, const char* foNSURI )
|
|
|
|
: m_propertiesTagName( "properties" ), m_styleNSURI( styleNSURI ), m_foNSURI( foNSURI )
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
KoStyleStack::~KoStyleStack()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoStyleStack::clear()
|
|
|
|
{
|
|
|
|
m_stack.clear();
|
|
|
|
#ifdef DEBUG_STYLESTACK
|
|
|
|
kdDebug(30003) << "clear!" << endl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoStyleStack::save()
|
|
|
|
{
|
|
|
|
m_marks.push( m_stack.count() );
|
|
|
|
#ifdef DEBUG_STYLESTACK
|
|
|
|
kdDebug(30003) << "save (level " << m_marks.count() << ") -> index " << m_stack.count() << endl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoStyleStack::restore()
|
|
|
|
{
|
|
|
|
Q_ASSERT( !m_marks.isEmpty() );
|
|
|
|
int toIndex = m_marks.pop();
|
|
|
|
#ifdef DEBUG_STYLESTACK
|
|
|
|
kdDebug(30003) << "restore (level " << m_marks.count()+1 << ") -> to index " << toIndex << endl;
|
|
|
|
#endif
|
|
|
|
Q_ASSERT( toIndex > -1 );
|
|
|
|
Q_ASSERT( toIndex <= (int)m_stack.count() ); // If equal, nothing to remove. If greater, bug.
|
|
|
|
for ( int index = (int)m_stack.count() - 1; index >= toIndex; --index )
|
|
|
|
m_stack.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoStyleStack::pop()
|
|
|
|
{
|
|
|
|
Q_ASSERT( !m_stack.isEmpty() );
|
|
|
|
m_stack.pop_back();
|
|
|
|
#ifdef DEBUG_STYLESTACK
|
|
|
|
kdDebug(30003) << "pop -> count=" << m_stack.count() << endl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoStyleStack::push( const TQDomElement& style )
|
|
|
|
{
|
|
|
|
m_stack.append( style );
|
|
|
|
#ifdef DEBUG_STYLESTACK
|
|
|
|
kdDebug(30003) << "pushed " << style.attributeNS( m_styleNSURI, "name", TQString() ) << " -> count=" << m_stack.count() << endl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoStyleStack::hasAttribute( const TQString& name, const TQString& detail ) const
|
|
|
|
{
|
|
|
|
TQString fullName( name );
|
|
|
|
if ( !detail.isEmpty() )
|
|
|
|
{
|
|
|
|
fullName += '-';
|
|
|
|
fullName += detail;
|
|
|
|
}
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
|
|
|
|
if ( properties.hasAttribute( name ) ||
|
|
|
|
( !detail.isEmpty() && properties.hasAttribute( fullName ) ) )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KoStyleStack::attribute( const TQString& name, const TQString& detail ) const
|
|
|
|
{
|
|
|
|
TQString fullName( name );
|
|
|
|
if ( !detail.isEmpty() )
|
|
|
|
{
|
|
|
|
fullName += '-';
|
|
|
|
fullName += detail;
|
|
|
|
}
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
|
|
|
|
if ( properties.hasAttribute( name ) )
|
|
|
|
return properties.attribute( name );
|
|
|
|
if ( !detail.isEmpty() && properties.hasAttribute( fullName ) )
|
|
|
|
return properties.attribute( fullName );
|
|
|
|
}
|
|
|
|
return TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KoStyleStack::attributeNS( const char* nsURI, const char* name, const char* detail ) const
|
|
|
|
{
|
|
|
|
TQString fullName( name );
|
|
|
|
if ( detail )
|
|
|
|
{
|
|
|
|
fullName += '-';
|
|
|
|
fullName += detail;
|
|
|
|
}
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
|
|
|
|
if ( properties.hasAttributeNS( nsURI, name ) )
|
|
|
|
return properties.attributeNS( nsURI, name, TQString() );
|
|
|
|
if ( detail && properties.hasAttributeNS( nsURI, fullName ) )
|
|
|
|
return properties.attributeNS( nsURI, fullName, TQString() );
|
|
|
|
}
|
|
|
|
return TQString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoStyleStack::hasAttributeNS( const char* nsURI, const char* name, const char* detail ) const
|
|
|
|
{
|
|
|
|
TQString fullName( name );
|
|
|
|
if ( detail )
|
|
|
|
{
|
|
|
|
fullName += '-';
|
|
|
|
fullName += detail;
|
|
|
|
}
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
|
|
|
|
if ( properties.hasAttributeNS( nsURI, name ) ||
|
|
|
|
( detail && properties.hasAttributeNS( nsURI, fullName ) ) )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Font size is a bit special. "115%" applies to "the fontsize of the parent style".
|
|
|
|
// This can be generalized though (hasAttributeThatCanBePercentOfParent() ? :)
|
|
|
|
// Although, if we also add support for fo:font-size-rel here then it's not general anymore.
|
|
|
|
double KoStyleStack::fontSize() const
|
|
|
|
{
|
|
|
|
const TQString name = "font-size";
|
|
|
|
double percent = 1;
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end(); // reverse iterator
|
|
|
|
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName ).toElement();
|
|
|
|
if ( properties.hasAttributeNS( m_foNSURI, name ) ) {
|
|
|
|
const TQString value = properties.attributeNS( m_foNSURI, name, TQString() );
|
|
|
|
if ( value.endsWith( "%" ) )
|
|
|
|
percent *= value.left( value.length() - 1 ).toDouble() / 100.0;
|
|
|
|
else
|
|
|
|
return percent * KoUnit::parseValue( value ); // e.g. 12pt
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoStyleStack::hasChildNode(const TQString & name) const
|
|
|
|
{
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
|
|
|
|
if ( !properties.namedItem( name ).isNull() )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDomElement KoStyleStack::childNode(const TQString & name) const
|
|
|
|
{
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
|
|
|
|
if ( !properties.namedItem( name ).isNull() )
|
|
|
|
return properties.namedItem( name ).toElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
return TQDomElement(); // a null element
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoStyleStack::hasChildNodeNS( const char* nsURI, const char* localName ) const
|
|
|
|
{
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
|
|
|
|
if ( !KoDom::namedItemNS( properties, nsURI, localName ).isNull() )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDomElement KoStyleStack::childNodeNS( const char* nsURI, const char* localName) const
|
|
|
|
{
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
TQDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
|
|
|
|
TQDomElement e = KoDom::namedItemNS( properties, nsURI, localName );
|
|
|
|
if ( !e.isNull() )
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TQDomElement(); // a null element
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KoStyleStack::isUserStyle( const TQDomElement& e, const TQString& family ) const
|
|
|
|
{
|
|
|
|
if ( e.attributeNS( m_styleNSURI, "family", TQString() ) != family )
|
|
|
|
return false;
|
|
|
|
const TQDomElement parent = e.parentNode().toElement();
|
|
|
|
//kdDebug(30003) << k_funcinfo << "tagName=" << e.tagName() << " parent-tagName=" << parent.tagName() << endl;
|
|
|
|
return parent.localName() == "styles" /*&& parent.namespaceURI() == KoXmlNS::office*/;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KoStyleStack::userStyleName( const TQString& family ) const
|
|
|
|
{
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
//kdDebug(30003) << k_funcinfo << (*it).attributeNS( m_styleNSURI, "name", TQString()) << endl;
|
|
|
|
if ( isUserStyle( *it, family ) )
|
|
|
|
return (*it).attributeNS( m_styleNSURI, "name", TQString() );
|
|
|
|
}
|
|
|
|
// Can this ever happen?
|
|
|
|
return "Standard";
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KoStyleStack::userStyleDisplayName( const TQString& family ) const
|
|
|
|
{
|
|
|
|
TQValueList<TQDomElement>::ConstIterator it = m_stack.end();
|
|
|
|
while ( it != m_stack.begin() )
|
|
|
|
{
|
|
|
|
--it;
|
|
|
|
//kdDebug(30003) << k_funcinfo << (*it).attributeNS( m_styleNSURI, "display-name") << endl;
|
|
|
|
if ( isUserStyle( *it, family ) )
|
|
|
|
return (*it).attributeNS( m_styleNSURI, "display-name", TQString() );
|
|
|
|
}
|
|
|
|
return TQString(); // no display name, this can happen since it's optional
|
|
|
|
}
|
|
|
|
|
|
|
|
void KoStyleStack::setTypeProperties( const char* typeProperties )
|
|
|
|
{
|
|
|
|
m_propertiesTagName = typeProperties == 0 ? TQCString( "properties" ) : ( TQCString( typeProperties ) + "-properties" );
|
|
|
|
}
|