lib Library API Documentation

koGenStyles.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2004 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00016    Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include "koGenStyles.h"
00020 #include <koxmlwriter.h>
00021 #include <float.h>
00022 #include <kdebug.h>
00023 
00024 KoGenStyles::KoGenStyles()
00025 {
00026 }
00027 
00028 KoGenStyles::~KoGenStyles()
00029 {
00030 }
00031 
00032 QString KoGenStyles::lookup( const KoGenStyle& style, const QString& name, bool forceNumbering )
00033 {
00034     StyleMap::iterator it = m_styleMap.find( style );
00035     if ( it == m_styleMap.end() ) {
00036         // Not found, try if this style is in fact equal to its parent (the find above
00037         // wouldn't have found it, due to m_parentName being set).
00038         if ( !style.parentName().isEmpty() ) {
00039             KoGenStyle testStyle( style );
00040             const KoGenStyle* parentStyle = this->style( style.parentName() ); // ## linear search
00041             if( !parentStyle ) {
00042                 kdDebug(30003) << "KoGenStyles::lookup(" << name << "): parent style '" << style.parentName() << "' not found in collection" << endl;
00043             } else {
00044                 testStyle.m_parentName = parentStyle->m_parentName;
00045                 if ( *parentStyle == testStyle )
00046                     return style.parentName();
00047             }
00048         }
00049 
00050         QString styleName( name );
00051         if ( styleName.isEmpty() ) {
00052             styleName = 'A'; // for "auto".
00053             forceNumbering = true;
00054         }
00055         styleName = makeUniqueName( styleName, forceNumbering );
00056         m_styleNames.insert( styleName, false );
00057         it = m_styleMap.insert( style, styleName );
00058         NamedStyle s;
00059         s.style = &it.key();
00060         s.name = styleName;
00061         m_styleArray.append( s );
00062     }
00063     return it.data();
00064 }
00065 
00066 QString KoGenStyles::makeUniqueName( const QString& base, bool forceNumbering ) const
00067 {
00068     if ( !forceNumbering && m_styleNames.find( base ) == m_styleNames.end() )
00069         return base;
00070     int num = 1;
00071     QString name;
00072     do {
00073         name = base;
00074         name += QString::number( num++ );
00075     } while ( m_styleNames.find( name ) != m_styleNames.end() );
00076     return name;
00077 }
00078 
00079 
00080 void KoGenStyles::markStyleForStylesXml( const QString& name )
00081 {
00082     NameMap::iterator it = m_styleNames.find( name );
00083     if ( it == m_styleNames.end() ) {
00084         kdWarning(30003) << "Style to be marked was not found:" << name << endl;
00085         return;
00086     }
00087     it.data() = true;
00088 }
00089 
00090 QValueList<KoGenStyles::NamedStyle> KoGenStyles::styles( int type, bool markedForStylesXml ) const
00091 {
00092     QValueList<KoGenStyles::NamedStyle> lst;
00093     StyleArray::const_iterator it = m_styleArray.begin();
00094     StyleArray::const_iterator end = m_styleArray.end();
00095     for ( ; it != end ; ++it ) {
00096         if ( (*it).style->type() == type && m_styleNames[(*it).name] == markedForStylesXml ) {
00097             //NamedStyle s;
00098             //s.style = (*it).style;
00099             //s.name = (*it).name;
00100             lst.append( *it );
00101         }
00102     }
00103     return lst;
00104 }
00105 
00106 const KoGenStyle* KoGenStyles::style( const QString& name ) const
00107 {
00108     StyleArray::const_iterator it = m_styleArray.begin();
00109     const StyleArray::const_iterator end = m_styleArray.end();
00110     for ( ; it != end ; ++it ) {
00111         if ( (*it).name == name )
00112             return (*it).style;
00113     }
00114     return 0;
00115 }
00116 
00117 KoGenStyle* KoGenStyles::styleForModification( const QString& name )
00118 {
00119     return const_cast<KoGenStyle *>( style( name ) );
00120 }
00121 
00122 // Returns -1, 0 (equal) or 1
00123 static int compareMap( const QMap<QString, QString>& map1, const QMap<QString, QString>& map2 )
00124 {
00125     QMap<QString, QString>::const_iterator it = map1.begin();
00126     QMap<QString, QString>::const_iterator oit = map2.begin();
00127     for ( ; it != map1.end(); ++it, ++oit ) { // both maps have been checked for size already
00128         if ( it.key() != oit.key() )
00129             return it.key() < oit.key() ? -1 : +1;
00130         if ( it.data() != oit.data() )
00131             return it.data() < oit.data() ? -1 : +1;
00132     }
00133     return 0; // equal
00134 }
00135 
00137 
00138 void KoGenStyle::writeStyle( KoXmlWriter* writer, KoGenStyles& styles, const char* elementName, const QString& name, const char* propertiesElementName, bool closeElement, bool drawElement ) const
00139 {
00140     //kdDebug(30003) << "writing out style " << name << " " << m_attributes["style:display-name"] << " " << m_familyName << endl;
00141     writer->startElement( elementName );
00142     if ( !drawElement )
00143         writer->addAttribute( "style:name", name );
00144     else
00145         writer->addAttribute( "draw:name", name );
00146     const KoGenStyle* parentStyle = 0;
00147     if ( !m_parentName.isEmpty() ) {
00148         writer->addAttribute( "style:parent-style-name", m_parentName );
00149         parentStyle = styles.style( m_parentName );
00150         if ( parentStyle && m_familyName.isEmpty() ) {
00151             // get family from parent style, just in case
00152             // Note: this is saving code, don't convert to attributeNS!
00153             const_cast<KoGenStyle *>( this )->
00154                 m_familyName = parentStyle->attribute( "style:family" ).latin1();
00155         }
00156     }
00157     if ( !m_familyName.isEmpty() )
00158         const_cast<KoGenStyle *>( this )->
00159             addAttribute( "style:family", QString::fromLatin1( m_familyName ) );
00160     else {
00161         if ( qstrcmp( elementName, "style:style" ) == 0 )
00162             kdWarning(30003) << "User style " << name << " is without family - invalid. m_type=" << m_type << endl;
00163     }
00164 
00165 #if 0 // #ifndef NDEBUG
00166     kdDebug() << "style: " << name << endl;
00167     printDebug();
00168     if ( parentStyle ) {
00169         kdDebug() << " parent: " << m_parentName << endl;
00170         parentStyle->printDebug();
00171     }
00172 #endif
00173 
00174     // Write attributes [which differ from the parent style]
00175     // We only look at the direct parent style because we assume
00176     // that styles are fully specified, i.e. the inheritance is
00177     // only in the final file, not in the caller's code.
00178     QMap<QString, QString>::const_iterator it = m_attributes.begin();
00179     for ( ; it != m_attributes.end(); ++it ) {
00180         bool writeit = true;
00181         if ( parentStyle && it.key() != "style:family" // always write the family out
00182              && parentStyle->attribute( it.key() ) == it.data() )
00183             writeit = false;
00184         if ( writeit )
00185             writer->addAttribute( it.key().utf8(), it.data().utf8() );
00186     }
00187     bool createPropertiesTag = propertiesElementName && propertiesElementName[0] != '\0';
00188     KoGenStyle::PropertyType i = KoGenStyle::DefaultType;
00189     if ( !m_properties[i].isEmpty() ||
00190          !m_properties[KoGenStyle::ChildElement].isEmpty() ) {
00191         if ( createPropertiesTag )
00192             writer->startElement( propertiesElementName ); // e.g. paragraph-properties
00193         it = m_properties[i].begin();
00194         for ( ; it != m_properties[i].end(); ++it ) {
00195             if ( !parentStyle || parentStyle->property( it.key(), i ) != it.data() )
00196                 writer->addAttribute( it.key().utf8(), it.data().utf8() );
00197         }
00198         i = KoGenStyle::ChildElement;
00199         it = m_properties[i].begin();
00200         for ( ; it != m_properties[i].end(); ++it ) {
00201             if ( !parentStyle || parentStyle->property( it.key(), i ) != it.data() ) {
00202                 writer->addCompleteElement( it.data().utf8() );
00203             }
00204         }
00205         if ( createPropertiesTag )
00206             writer->endElement();
00207     }
00208     i = KoGenStyle::TextType;
00209     if ( !m_properties[i].isEmpty() ) {
00210         writer->startElement( "style:text-properties" );
00211         it = m_properties[i].begin();
00212         for ( ; it != m_properties[i].end(); ++it ) {
00213             if ( !parentStyle || parentStyle->property( it.key(), i ) != it.data() )
00214                 writer->addAttribute( it.key().utf8(), it.data().utf8() );
00215         }
00216         writer->endElement();
00217     }
00218     i = KoGenStyle::ParagraphType;
00219     if ( !m_properties[i].isEmpty() ) {
00220         writer->startElement( "style:paragraph-properties" );
00221         it = m_properties[i].begin();
00222         for ( ; it != m_properties[i].end(); ++it ) {
00223             if ( !parentStyle || parentStyle->property( it.key(), i ) != it.data() )
00224                 writer->addAttribute( it.key().utf8(), it.data().utf8() );
00225         }
00226         writer->endElement();
00227     }   
00228     // And now the style maps
00229     for ( uint i = 0; i < m_maps.count(); ++i ) {
00230         bool writeit = true;
00231         if ( parentStyle && compareMap( m_maps[i], parentStyle->m_maps[i] ) == 0 )
00232             writeit = false;
00233         if ( writeit ) {
00234             writer->startElement( "style:map" );
00235             QMap<QString, QString>::const_iterator it = m_maps[i].begin();
00236             for ( ; it != m_maps[i].end(); ++it ) {
00237                 writer->addAttribute( it.key().utf8(), it.data().utf8() );
00238             }
00239             writer->endElement(); // style:map
00240         }
00241     }
00242     if ( closeElement )
00243         writer->endElement();
00244 }
00245 
00246 void KoGenStyle::addPropertyPt( const QString& propName, double propValue, PropertyType type )
00247 {
00248     QString str;
00249     str.setNum( propValue, 'g', DBL_DIG );
00250     str += "pt";
00251     m_properties[type].insert( propName, str );
00252 }
00253 
00254 void KoGenStyle::addAttributePt( const QString& attrName, double attrValue )
00255 {
00256     QString str;
00257     str.setNum( attrValue, 'g', DBL_DIG );
00258     str += "pt";
00259     m_attributes.insert( attrName, str );
00260 }
00261 
00262 #ifndef NDEBUG
00263 void KoGenStyle::printDebug() const
00264 {
00265     int i = DefaultType;
00266     kdDebug() << m_properties[i].count() << " properties." << endl;
00267     for( QMap<QString,QString>::ConstIterator it = m_properties[i].begin(); it != m_properties[i].end(); ++it ) {
00268         kdDebug() << "     " << it.key() << " = " << it.data() << endl;
00269     }
00270     i = TextType;
00271     kdDebug() << m_properties[i].count() << " text properties." << endl;
00272     for( QMap<QString,QString>::ConstIterator it = m_properties[i].begin(); it != m_properties[i].end(); ++it ) {
00273         kdDebug() << "     " << it.key() << " = " << it.data() << endl;
00274     }
00275     i = ParagraphType;
00276     kdDebug() << m_properties[i].count() << " paragraph properties." << endl;
00277     for( QMap<QString,QString>::ConstIterator it = m_properties[i].begin(); it != m_properties[i].end(); ++it ) {
00278         kdDebug() << "     " << it.key() << " = " << it.data() << endl;
00279     }
00280     i = ChildElement;
00281     kdDebug() << m_properties[i].count() << " child elements." << endl;
00282     for( QMap<QString,QString>::ConstIterator it = m_properties[i].begin(); it != m_properties[i].end(); ++it ) {
00283         kdDebug() << "     " << it.key() << " = " << it.data() << endl;
00284     }
00285     kdDebug() << m_attributes.count() << " attributes." << endl;
00286     for( QMap<QString,QString>::ConstIterator it = m_attributes.begin(); it != m_attributes.end(); ++it ) {
00287         kdDebug() << "     " << it.key() << " = " << it.data() << endl;
00288     }
00289     kdDebug() << m_maps.count() << " maps." << endl;
00290     for ( uint i = 0; i < m_maps.count(); ++i ) {
00291         kdDebug() << "map " << i << ":" << endl;
00292         for( QMap<QString,QString>::ConstIterator it = m_maps[i].begin(); it != m_maps[i].end(); ++it ) {
00293             kdDebug() << "     " << it.key() << " = " << it.data() << endl;
00294         }
00295     }
00296     kdDebug() << endl;
00297 }
00298 #endif
00299 
00300 bool KoGenStyle::operator<( const KoGenStyle &other ) const
00301 {
00302     if ( m_type != other.m_type ) return m_type < other.m_type;
00303     if ( m_parentName != other.m_parentName ) return m_parentName < other.m_parentName;
00304     for ( uint i = 0 ; i < N_NumTypes ; ++i )
00305         if ( m_properties[i].count() != other.m_properties[i].count() )
00306             return m_properties[i].count() < other.m_properties[i].count();
00307     if ( m_attributes.count() != other.m_attributes.count() ) return m_attributes.count() < other.m_attributes.count();
00308     if ( m_maps.count() != other.m_maps.count() ) return m_maps.count() < other.m_maps.count();
00309     // Same number of properties and attributes, no other choice than iterating
00310     for ( uint i = 0 ; i < N_NumTypes ; ++i ) {
00311         int comp = compareMap( m_properties[i], other.m_properties[i] );
00312         if ( comp != 0 )
00313             return comp < 0;
00314     }
00315     int comp = compareMap( m_attributes, other.m_attributes );
00316     if ( comp != 0 )
00317         return comp < 0;
00318     for ( uint i = 0 ; i < m_maps.count() ; ++i ) {
00319         int comp = compareMap( m_maps[i], other.m_maps[i] );
00320         if ( comp != 0 )
00321             return comp < 0;
00322     }
00323     return false;
00324 }
00325 
00326 bool KoGenStyle::operator==( const KoGenStyle &other ) const
00327 {
00328     if ( m_type != other.m_type ) return false;
00329     if ( m_parentName != other.m_parentName ) return false;
00330     for ( uint i = 0 ; i < N_NumTypes ; ++i )
00331         if ( m_properties[i].count() != other.m_properties[i].count() )
00332             return false;
00333     if ( m_attributes.count() != other.m_attributes.count() ) return false;
00334     if ( m_maps.count() != other.m_maps.count() ) return false;
00335     // Same number of properties and attributes, no other choice than iterating
00336     for ( uint i = 0 ; i < N_NumTypes ; ++i ) {
00337         int comp = compareMap( m_properties[i], other.m_properties[i] );
00338         if ( comp != 0 )
00339             return false;
00340     }
00341     int comp = compareMap( m_attributes, other.m_attributes );
00342     if ( comp != 0 )
00343         return false;
00344     for ( uint i = 0 ; i < m_maps.count() ; ++i ) {
00345         int comp = compareMap( m_maps[i], other.m_maps[i] );
00346         if ( comp != 0 )
00347             return false;
00348     }
00349     return true;
00350 }
KDE Logo
This file is part of the documentation for lib Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:40:01 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003