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, bool forceNumbering )
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 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';
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
00098
00099
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
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 ) {
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;
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
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
00152
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
00175
00176
00177
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"
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 );
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
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();
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
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
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 }