00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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, int flags )
00033 {
00034 StyleMap::iterator it = m_styleMap.find( style );
00035 if ( it == m_styleMap.end() ) {
00036
00037
00038 if ( !style.parentName().isEmpty() ) {
00039 KoGenStyle testStyle( style );
00040 const KoGenStyle* parentStyle = this->style( style.parentName() );
00041 if( !parentStyle ) {
00042 kdDebug(30003) << "KoGenStyles::lookup(" << name << "): parent style '" << style.parentName() << "' not found in collection" << endl;
00043 } else {
00044 if ( testStyle.m_familyName != parentStyle->m_familyName )
00045 {
00046 kdWarning(30003) << "KoGenStyles::lookup(" << name << ", family=" << testStyle.m_familyName << ") parent style '" << style.parentName() << "' has a different family: " << parentStyle->m_familyName << endl;
00047 }
00048
00049 testStyle.m_parentName = parentStyle->m_parentName;
00050
00051
00052 testStyle.m_type = parentStyle->m_type;
00053
00054
00055 QMap<QString, QString>::const_iterator it = parentStyle->m_attributes.find( "style:display-name" );
00056 if ( it != parentStyle->m_attributes.end() )
00057 testStyle.addAttribute( "style:display-name", *it );
00058
00059 if ( *parentStyle == testStyle )
00060 return style.parentName();
00061 }
00062 }
00063
00064 QString styleName( name );
00065 if ( styleName.isEmpty() ) {
00066 styleName = 'A';
00067 flags &= ~DontForceNumbering;
00068 }
00069 styleName = makeUniqueName( styleName, flags );
00070 if ( style.autoStyleInStylesDotXml() )
00071 m_autoStylesInStylesDotXml.insert( styleName, true );
00072 else
00073 m_styleNames.insert( styleName, true );
00074 it = m_styleMap.insert( style, styleName );
00075 NamedStyle s;
00076 s.style = &it.key();
00077 s.name = styleName;
00078 m_styleArray.append( s );
00079 }
00080 return it.data();
00081 }
00082
00083 QString KoGenStyles::makeUniqueName( const QString& base, int flags ) const
00084 {
00085
00086 if ( ( flags & DontForceNumbering )
00087 && m_autoStylesInStylesDotXml.find( base ) == m_autoStylesInStylesDotXml.end()
00088 && m_styleNames.find( base ) == m_styleNames.end() )
00089 return base;
00090 int num = 1;
00091 QString name;
00092 do {
00093 name = base;
00094 name += QString::number( num++ );
00095 } while ( m_autoStylesInStylesDotXml.find( name ) != m_autoStylesInStylesDotXml.end()
00096 || m_styleNames.find( name ) != m_styleNames.end() );
00097 return name;
00098 }
00099
00100 QValueList<KoGenStyles::NamedStyle> KoGenStyles::styles( int type, bool markedForStylesXml ) const
00101 {
00102 QValueList<KoGenStyles::NamedStyle> lst;
00103 const NameMap& nameMap = markedForStylesXml ? m_autoStylesInStylesDotXml : m_styleNames;
00104 StyleArray::const_iterator it = m_styleArray.begin();
00105 const StyleArray::const_iterator end = m_styleArray.end();
00106 for ( ; it != end ; ++it ) {
00107
00108 if ( (*it).style->type() == type && nameMap.find((*it).name) != nameMap.end() ) {
00109 lst.append( *it );
00110 }
00111 }
00112 return lst;
00113 }
00114
00115 const KoGenStyle* KoGenStyles::style( const QString& name ) const
00116 {
00117 StyleArray::const_iterator it = m_styleArray.begin();
00118 const StyleArray::const_iterator end = m_styleArray.end();
00119 for ( ; it != end ; ++it ) {
00120 if ( (*it).name == name )
00121 return (*it).style;
00122 }
00123 return 0;
00124 }
00125
00126 KoGenStyle* KoGenStyles::styleForModification( const QString& name )
00127 {
00128 return const_cast<KoGenStyle *>( style( name ) );
00129 }
00130
00131 void KoGenStyles::markStyleForStylesXml( const QString& name )
00132 {
00133 Q_ASSERT( m_styleNames.find( name ) != m_styleNames.end() );
00134 m_styleNames.remove( name );
00135 m_autoStylesInStylesDotXml.insert( name, true );
00136 styleForModification( name )->setAutoStyleInStylesDotXml( true );
00137 }
00138
00139 void KoGenStyles::dump()
00140 {
00141 kdDebug() << "Style array:" << endl;
00142 StyleArray::const_iterator it = m_styleArray.begin();
00143 const StyleArray::const_iterator end = m_styleArray.end();
00144 for ( ; it != end ; ++it ) {
00145 kdDebug() << (*it).name << endl;
00146 }
00147 for ( NameMap::const_iterator it = m_styleNames.begin(); it != m_styleNames.end(); ++it ) {
00148 kdDebug() << "style: " << it.key() << endl;
00149 }
00150 for ( NameMap::const_iterator it = m_autoStylesInStylesDotXml.begin(); it != m_autoStylesInStylesDotXml.end(); ++it ) {
00151 kdDebug() << "auto style for style.xml: " << it.key() << endl;
00152 const KoGenStyle* s = style( it.key() );
00153 Q_ASSERT( s );
00154 Q_ASSERT( s->autoStyleInStylesDotXml() );
00155 }
00156 }
00157
00158
00159 static int compareMap( const QMap<QString, QString>& map1, const QMap<QString, QString>& map2 )
00160 {
00161 QMap<QString, QString>::const_iterator it = map1.begin();
00162 QMap<QString, QString>::const_iterator oit = map2.begin();
00163 for ( ; it != map1.end(); ++it, ++oit ) {
00164 if ( it.key() != oit.key() )
00165 return it.key() < oit.key() ? -1 : +1;
00166 if ( it.data() != oit.data() )
00167 return it.data() < oit.data() ? -1 : +1;
00168 }
00169 return 0;
00170 }
00171
00173
00174
00175 KoGenStyle::KoGenStyle( int type, const char* familyName,
00176 const QString& parentName )
00177 : m_type( type ), m_familyName( familyName ), m_parentName( parentName ),
00178 m_autoStyleInStylesDotXml( false ), m_defaultStyle( false )
00179 {
00180 }
00181
00182 KoGenStyle::~KoGenStyle()
00183 {
00184 }
00185
00186 void KoGenStyle::writeStyleProperties( KoXmlWriter* writer, PropertyType i,
00187 const char* elementName, const KoGenStyle* parentStyle ) const
00188 {
00189 if ( !m_properties[i].isEmpty() ) {
00190 writer->startElement( elementName );
00191 QMap<QString, QString>::const_iterator it = m_properties[i].begin();
00192 const QMap<QString, QString>::const_iterator end = m_properties[i].end();
00193 for ( ; it != end; ++it ) {
00194 if ( !parentStyle || parentStyle->property( it.key(), i ) != it.data() )
00195 writer->addAttribute( it.key().utf8(), it.data().utf8() );
00196 }
00197 writer->endElement();
00198 }
00199 }
00200
00201 void KoGenStyle::writeStyle( KoXmlWriter* writer, KoGenStyles& styles, const char* elementName, const QString& name, const char* propertiesElementName, bool closeElement, bool drawElement ) const
00202 {
00203
00204 writer->startElement( elementName );
00205 const KoGenStyle* parentStyle = 0;
00206 if ( !m_defaultStyle ) {
00207 if ( !drawElement )
00208 writer->addAttribute( "style:name", name );
00209 else
00210 writer->addAttribute( "draw:name", name );
00211 if ( !m_parentName.isEmpty() ) {
00212 parentStyle = styles.style( m_parentName );
00213 if ( parentStyle && m_familyName.isEmpty() ) {
00214
00215
00216 const_cast<KoGenStyle *>( this )->
00217 m_familyName = parentStyle->attribute( "style:family" ).latin1();
00218
00219 }
00220 writer->addAttribute( "style:parent-style-name", m_parentName );
00221 }
00222 } else {
00223 Q_ASSERT( qstrcmp( elementName, "style:default-style" ) == 0 );
00224 Q_ASSERT( m_parentName.isEmpty() );
00225 }
00226 if ( !m_familyName.isEmpty() )
00227 const_cast<KoGenStyle *>( this )->
00228 addAttribute( "style:family", QString::fromLatin1( m_familyName ) );
00229 else {
00230 if ( qstrcmp( elementName, "style:style" ) == 0 )
00231 kdWarning(30003) << "User style " << name << " is without family - invalid. m_type=" << m_type << endl;
00232 }
00233
00234 #if 0 // #ifndef NDEBUG
00235 kdDebug() << "style: " << name << endl;
00236 printDebug();
00237 if ( parentStyle ) {
00238 kdDebug() << " parent: " << m_parentName << endl;
00239 parentStyle->printDebug();
00240 }
00241 #endif
00242
00243
00244
00245
00246
00247 QMap<QString, QString>::const_iterator it = m_attributes.begin();
00248 for ( ; it != m_attributes.end(); ++it ) {
00249 bool writeit = true;
00250 if ( parentStyle && it.key() != "style:family"
00251 && parentStyle->attribute( it.key() ) == it.data() )
00252 writeit = false;
00253 if ( writeit )
00254 writer->addAttribute( it.key().utf8(), it.data().utf8() );
00255 }
00256 bool createPropertiesTag = propertiesElementName && propertiesElementName[0] != '\0';
00257 KoGenStyle::PropertyType i = KoGenStyle::DefaultType;
00258 if ( !m_properties[i].isEmpty() ||
00259 !m_properties[KoGenStyle::ChildElement].isEmpty() ) {
00260 if ( createPropertiesTag )
00261 writer->startElement( propertiesElementName );
00262 it = m_properties[i].begin();
00263 for ( ; it != m_properties[i].end(); ++it ) {
00264 if ( !parentStyle || parentStyle->property( it.key(), i ) != it.data() )
00265 writer->addAttribute( it.key().utf8(), it.data().utf8() );
00266 }
00267 i = KoGenStyle::ChildElement;
00268 it = m_properties[i].begin();
00269 for ( ; it != m_properties[i].end(); ++it ) {
00270 if ( !parentStyle || parentStyle->property( it.key(), i ) != it.data() ) {
00271 writer->addCompleteElement( it.data().utf8() );
00272 }
00273 }
00274 if ( createPropertiesTag )
00275 writer->endElement();
00276 }
00277 writeStyleProperties( writer, KoGenStyle::GraphicType, "style:graphic-properties", parentStyle );
00278 writeStyleProperties( writer, KoGenStyle::TextType, "style:text-properties", parentStyle );
00279 writeStyleProperties( writer, KoGenStyle::ParagraphType, "style:paragraph-properties", parentStyle );
00280
00281
00282 for ( uint i = 0; i < m_maps.count(); ++i ) {
00283 bool writeit = true;
00284 if ( parentStyle && compareMap( m_maps[i], parentStyle->m_maps[i] ) == 0 )
00285 writeit = false;
00286 if ( writeit ) {
00287 writer->startElement( "style:map" );
00288 QMap<QString, QString>::const_iterator it = m_maps[i].begin();
00289 for ( ; it != m_maps[i].end(); ++it ) {
00290 writer->addAttribute( it.key().utf8(), it.data().utf8() );
00291 }
00292 writer->endElement();
00293 }
00294 }
00295 if ( closeElement )
00296 writer->endElement();
00297 }
00298
00299 void KoGenStyle::addPropertyPt( const QString& propName, double propValue, PropertyType type )
00300 {
00301 QString str;
00302 str.setNum( propValue, 'g', DBL_DIG );
00303 str += "pt";
00304 m_properties[type].insert( propName, str );
00305 }
00306
00307 void KoGenStyle::addAttributePt( const QString& attrName, double attrValue )
00308 {
00309 QString str;
00310 str.setNum( attrValue, 'g', DBL_DIG );
00311 str += "pt";
00312 m_attributes.insert( attrName, str );
00313 }
00314
00315 #ifndef NDEBUG
00316 void KoGenStyle::printDebug() const
00317 {
00318 int i = DefaultType;
00319 kdDebug() << m_properties[i].count() << " properties." << endl;
00320 for( QMap<QString,QString>::ConstIterator it = m_properties[i].begin(); it != m_properties[i].end(); ++it ) {
00321 kdDebug() << " " << it.key() << " = " << it.data() << endl;
00322 }
00323 i = TextType;
00324 kdDebug() << m_properties[i].count() << " text properties." << endl;
00325 for( QMap<QString,QString>::ConstIterator it = m_properties[i].begin(); it != m_properties[i].end(); ++it ) {
00326 kdDebug() << " " << it.key() << " = " << it.data() << endl;
00327 }
00328 i = ParagraphType;
00329 kdDebug() << m_properties[i].count() << " paragraph properties." << endl;
00330 for( QMap<QString,QString>::ConstIterator it = m_properties[i].begin(); it != m_properties[i].end(); ++it ) {
00331 kdDebug() << " " << it.key() << " = " << it.data() << endl;
00332 }
00333 i = ChildElement;
00334 kdDebug() << m_properties[i].count() << " child elements." << endl;
00335 for( QMap<QString,QString>::ConstIterator it = m_properties[i].begin(); it != m_properties[i].end(); ++it ) {
00336 kdDebug() << " " << it.key() << " = " << it.data() << endl;
00337 }
00338 kdDebug() << m_attributes.count() << " attributes." << endl;
00339 for( QMap<QString,QString>::ConstIterator it = m_attributes.begin(); it != m_attributes.end(); ++it ) {
00340 kdDebug() << " " << it.key() << " = " << it.data() << endl;
00341 }
00342 kdDebug() << m_maps.count() << " maps." << endl;
00343 for ( uint i = 0; i < m_maps.count(); ++i ) {
00344 kdDebug() << "map " << i << ":" << endl;
00345 for( QMap<QString,QString>::ConstIterator it = m_maps[i].begin(); it != m_maps[i].end(); ++it ) {
00346 kdDebug() << " " << it.key() << " = " << it.data() << endl;
00347 }
00348 }
00349 kdDebug() << endl;
00350 }
00351 #endif
00352
00353 bool KoGenStyle::operator<( const KoGenStyle &other ) const
00354 {
00355 if ( m_type != other.m_type ) return m_type < other.m_type;
00356 if ( m_parentName != other.m_parentName ) return m_parentName < other.m_parentName;
00357 if ( m_autoStyleInStylesDotXml != other.m_autoStyleInStylesDotXml ) return m_autoStyleInStylesDotXml;
00358 for ( uint i = 0 ; i < N_NumTypes ; ++i )
00359 if ( m_properties[i].count() != other.m_properties[i].count() )
00360 return m_properties[i].count() < other.m_properties[i].count();
00361 if ( m_attributes.count() != other.m_attributes.count() ) return m_attributes.count() < other.m_attributes.count();
00362 if ( m_maps.count() != other.m_maps.count() ) return m_maps.count() < other.m_maps.count();
00363
00364 for ( uint i = 0 ; i < N_NumTypes ; ++i ) {
00365 int comp = compareMap( m_properties[i], other.m_properties[i] );
00366 if ( comp != 0 )
00367 return comp < 0;
00368 }
00369 int comp = compareMap( m_attributes, other.m_attributes );
00370 if ( comp != 0 )
00371 return comp < 0;
00372 for ( uint i = 0 ; i < m_maps.count() ; ++i ) {
00373 int comp = compareMap( m_maps[i], other.m_maps[i] );
00374 if ( comp != 0 )
00375 return comp < 0;
00376 }
00377 return false;
00378 }
00379
00380 bool KoGenStyle::operator==( const KoGenStyle &other ) const
00381 {
00382 if ( m_type != other.m_type ) return false;
00383 if ( m_parentName != other.m_parentName ) return false;
00384 if ( m_autoStyleInStylesDotXml != other.m_autoStyleInStylesDotXml ) return false;
00385 for ( uint i = 0 ; i < N_NumTypes ; ++i )
00386 if ( m_properties[i].count() != other.m_properties[i].count() )
00387 return false;
00388 if ( m_attributes.count() != other.m_attributes.count() ) return false;
00389 if ( m_maps.count() != other.m_maps.count() ) return false;
00390
00391 for ( uint i = 0 ; i < N_NumTypes ; ++i ) {
00392 int comp = compareMap( m_properties[i], other.m_properties[i] );
00393 if ( comp != 0 )
00394 return false;
00395 }
00396 int comp = compareMap( m_attributes, other.m_attributes );
00397 if ( comp != 0 )
00398 return false;
00399 for ( uint i = 0 ; i < m_maps.count() ; ++i ) {
00400 int comp = compareMap( m_maps[i], other.m_maps[i] );
00401 if ( comp != 0 )
00402 return false;
00403 }
00404 return true;
00405 }