lib

KoStyleStack.cpp

00001 /* This file is part of the KDE project
00002    Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
00003    Copyright (c) 2003 David Faure <faure@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "KoStyleStack.h"
00022 #include "KoUnit.h"
00023 #include "KoDom.h"
00024 #include "KoXmlNS.h"
00025 
00026 #include <kdebug.h>
00027 
00028 //#define DEBUG_STYLESTACK
00029 
00030 KoStyleStack::KoStyleStack()
00031     : m_styleNSURI( KoXmlNS::style ), m_foNSURI( KoXmlNS::fo )
00032 {
00033     clear();
00034 }
00035 
00036 KoStyleStack::KoStyleStack( const char* styleNSURI, const char* foNSURI )
00037     : m_propertiesTagName( "properties" ), m_styleNSURI( styleNSURI ), m_foNSURI( foNSURI )
00038 {
00039     clear();
00040 }
00041 
00042 KoStyleStack::~KoStyleStack()
00043 {
00044 }
00045 
00046 void KoStyleStack::clear()
00047 {
00048     m_stack.clear();
00049 #ifdef DEBUG_STYLESTACK
00050     kdDebug(30003) << "clear!" << endl;
00051 #endif
00052 }
00053 
00054 void KoStyleStack::save()
00055 {
00056     m_marks.push( m_stack.count() );
00057 #ifdef DEBUG_STYLESTACK
00058     kdDebug(30003) << "save (level " << m_marks.count() << ") -> index " << m_stack.count() << endl;
00059 #endif
00060 }
00061 
00062 void KoStyleStack::restore()
00063 {
00064     Q_ASSERT( !m_marks.isEmpty() );
00065     int toIndex = m_marks.pop();
00066 #ifdef DEBUG_STYLESTACK
00067     kdDebug(30003) << "restore (level " << m_marks.count()+1 << ") -> to index " << toIndex << endl;
00068 #endif
00069     Q_ASSERT( toIndex > -1 );
00070     Q_ASSERT( toIndex <= (int)m_stack.count() ); // If equal, nothing to remove. If greater, bug.
00071     for ( int index = (int)m_stack.count() - 1; index >= toIndex; --index )
00072         m_stack.pop_back();
00073 }
00074 
00075 void KoStyleStack::pop()
00076 {
00077     Q_ASSERT( !m_stack.isEmpty() );
00078     m_stack.pop_back();
00079 #ifdef DEBUG_STYLESTACK
00080     kdDebug(30003) << "pop -> count=" << m_stack.count() << endl;
00081 #endif
00082 }
00083 
00084 void KoStyleStack::push( const QDomElement& style )
00085 {
00086     m_stack.append( style );
00087 #ifdef DEBUG_STYLESTACK
00088     kdDebug(30003) << "pushed " << style.attributeNS( m_styleNSURI, "name", QString::null ) << " -> count=" << m_stack.count() << endl;
00089 #endif
00090 }
00091 
00092 bool KoStyleStack::hasAttribute( const QString& name, const QString& detail ) const
00093 {
00094     QString fullName( name );
00095     if ( !detail.isEmpty() )
00096     {
00097         fullName += '-';
00098         fullName += detail;
00099     }
00100     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00101     while ( it != m_stack.begin() )
00102     {
00103         --it;
00104         QDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
00105         if ( properties.hasAttribute( name ) ||
00106              ( !detail.isEmpty() && properties.hasAttribute( fullName ) ) )
00107             return true;
00108     }
00109     return false;
00110 }
00111 
00112 QString KoStyleStack::attribute( const QString& name, const QString& detail ) const
00113 {
00114     QString fullName( name );
00115     if ( !detail.isEmpty() )
00116     {
00117         fullName += '-';
00118         fullName += detail;
00119     }
00120     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00121     while ( it != m_stack.begin() )
00122     {
00123         --it;
00124         QDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
00125         if ( properties.hasAttribute( name ) )
00126             return properties.attribute( name );
00127         if ( !detail.isEmpty() && properties.hasAttribute( fullName ) )
00128             return properties.attribute( fullName );
00129     }
00130     return QString::null;
00131 }
00132 
00133 QString KoStyleStack::attributeNS( const char* nsURI, const char* name, const char* detail ) const
00134 {
00135     QString fullName( name );
00136     if ( detail )
00137     {
00138         fullName += '-';
00139         fullName += detail;
00140     }
00141     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00142     while ( it != m_stack.begin() )
00143     {
00144         --it;
00145         QDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
00146         if ( properties.hasAttributeNS( nsURI, name ) )
00147             return properties.attributeNS( nsURI, name, QString::null );
00148         if ( detail && properties.hasAttributeNS( nsURI, fullName ) )
00149             return properties.attributeNS( nsURI, fullName, QString::null );
00150     }
00151     return QString::null;
00152 }
00153 
00154 bool KoStyleStack::hasAttributeNS( const char* nsURI, const char* name, const char* detail ) const
00155 {
00156     QString fullName( name );
00157     if ( detail )
00158     {
00159         fullName += '-';
00160         fullName += detail;
00161     }
00162     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00163     while ( it != m_stack.begin() )
00164     {
00165         --it;
00166         QDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
00167         if ( properties.hasAttributeNS( nsURI, name ) ||
00168              ( detail && properties.hasAttributeNS( nsURI, fullName ) ) )
00169             return true;
00170     }
00171     return false;
00172 }
00173 
00174 // Font size is a bit special. "115%" applies to "the fontsize of the parent style".
00175 // This can be generalized though (hasAttributeThatCanBePercentOfParent() ? :)
00176 // Although, if we also add support for fo:font-size-rel here then it's not general anymore.
00177 double KoStyleStack::fontSize() const
00178 {
00179     const QString name = "font-size";
00180     double percent = 1;
00181     QValueList<QDomElement>::ConstIterator it = m_stack.end(); // reverse iterator
00182 
00183     while ( it != m_stack.begin() )
00184     {
00185         --it;
00186         QDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName ).toElement();
00187         if ( properties.hasAttributeNS( m_foNSURI, name ) ) {
00188             const QString value = properties.attributeNS( m_foNSURI, name, QString::null );
00189             if ( value.endsWith( "%" ) )
00190                 percent *= value.left( value.length() - 1 ).toDouble() / 100.0;
00191             else
00192                 return percent * KoUnit::parseValue( value ); // e.g. 12pt
00193         }
00194     }
00195     return 0;
00196 }
00197 
00198 bool KoStyleStack::hasChildNode(const QString & name) const
00199 {
00200     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00201     while ( it != m_stack.begin() )
00202     {
00203         --it;
00204         QDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
00205         if ( !properties.namedItem( name ).isNull() )
00206             return true;
00207     }
00208 
00209     return false;
00210 }
00211 
00212 QDomElement KoStyleStack::childNode(const QString & name) const
00213 {
00214     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00215 
00216     while ( it != m_stack.begin() )
00217     {
00218         --it;
00219         QDomElement properties = (*it).namedItem( "style:"+m_propertiesTagName ).toElement();
00220         if ( !properties.namedItem( name ).isNull() )
00221             return properties.namedItem( name ).toElement();
00222     }
00223 
00224     return QDomElement();          // a null element
00225 }
00226 
00227 bool KoStyleStack::hasChildNodeNS( const char* nsURI, const char* localName ) const
00228 {
00229     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00230     while ( it != m_stack.begin() )
00231     {
00232         --it;
00233         QDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
00234         if ( !KoDom::namedItemNS( properties, nsURI, localName ).isNull() )
00235             return true;
00236     }
00237 
00238     return false;
00239 }
00240 
00241 QDomElement KoStyleStack::childNodeNS( const char* nsURI, const char* localName) const
00242 {
00243     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00244 
00245     while ( it != m_stack.begin() )
00246     {
00247         --it;
00248         QDomElement properties = KoDom::namedItemNS( *it, m_styleNSURI, m_propertiesTagName );
00249         QDomElement e = KoDom::namedItemNS( properties, nsURI, localName );
00250         if ( !e.isNull() )
00251             return e;
00252     }
00253 
00254     return QDomElement();          // a null element
00255 }
00256 
00257 bool KoStyleStack::isUserStyle( const QDomElement& e, const QString& family ) const
00258 {
00259     if ( e.attributeNS( m_styleNSURI, "family", QString::null ) != family )
00260         return false;
00261     const QDomElement parent = e.parentNode().toElement();
00262     //kdDebug(30003) << k_funcinfo << "tagName=" << e.tagName() << " parent-tagName=" << parent.tagName() << endl;
00263     return parent.localName() == "styles" /*&& parent.namespaceURI() == KoXmlNS::office*/;
00264 }
00265 
00266 QString KoStyleStack::userStyleName( const QString& family ) const
00267 {
00268     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00269     while ( it != m_stack.begin() )
00270     {
00271         --it;
00272         //kdDebug(30003) << k_funcinfo << (*it).attributeNS( m_styleNSURI, "name", QString::null) << endl;
00273         if ( isUserStyle( *it, family ) )
00274             return (*it).attributeNS( m_styleNSURI, "name", QString::null );
00275     }
00276     // Can this ever happen?
00277     return "Standard";
00278 }
00279 
00280 QString KoStyleStack::userStyleDisplayName( const QString& family ) const
00281 {
00282     QValueList<QDomElement>::ConstIterator it = m_stack.end();
00283     while ( it != m_stack.begin() )
00284     {
00285         --it;
00286         //kdDebug(30003) << k_funcinfo << (*it).attributeNS( m_styleNSURI, "display-name") << endl;
00287         if ( isUserStyle( *it, family ) )
00288             return (*it).attributeNS( m_styleNSURI, "display-name", QString::null );
00289     }
00290     return QString::null; // no display name, this can happen since it's optional
00291 }
00292 
00293 void KoStyleStack::setTypeProperties( const char* typeProperties )
00294 {
00295     m_propertiesTagName = typeProperties == 0 ? QCString( "properties" ) : ( QCString( typeProperties ) + "-properties" );
00296 }
KDE Home | KDE Accessibility Home | Description of Access Keys