00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kostyle.h"
00021 #include "kooasiscontext.h"
00022 #include "koparagcounter.h"
00023
00024 #include <koOasisStyles.h>
00025 #include <koGenStyles.h>
00026 #include <koxmlwriter.h>
00027 #include <koxmlns.h>
00028
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031
00032 #include <qdom.h>
00033
00034
00035 int KoStyleCollection::styleNumber = 0;
00036
00037 KoStyleCollection::KoStyleCollection()
00038 {
00039 m_styleList.setAutoDelete( false );
00040 m_deletedStyles.setAutoDelete( true );
00041 m_lastStyle = 0L;
00042 }
00043
00044 KoStyleCollection::~KoStyleCollection()
00045 {
00046 clear();
00047 }
00048
00049 void KoStyleCollection::clear()
00050 {
00051 m_styleList.setAutoDelete( true );
00052 m_styleList.clear();
00053 m_styleList.setAutoDelete( false );
00054 m_deletedStyles.clear();
00055 }
00056
00057 QStringList KoStyleCollection::translatedStyleNames() const
00058 {
00059 QStringList lst;
00060 for( QPtrListIterator<KoParagStyle> p( m_styleList ); *p; ++p )
00061 lst << (*p)->displayName();
00062 return lst;
00063 }
00064
00065 void KoStyleCollection::loadOasisStyleTemplates( KoOasisContext& context )
00066 {
00067 QStringList followingStyles;
00068 QValueVector<QDomElement> userStyles = context.oasisStyles().userStyles();
00069 uint nStyles = userStyles.count();
00070 if( nStyles ) {
00071 KoParagStyle *s = findStyle("Standard");
00072
00073 if(s)
00074 removeStyleTemplate(s);
00075 }
00076 for (unsigned int item = 0; item < nStyles; item++) {
00077 QDomElement styleElem = userStyles[item];
00078 Q_ASSERT( !styleElem.isNull() );
00079
00080
00081 KoParagStyle *sty = new KoParagStyle( QString::null );
00082
00083 sty->loadStyle( styleElem, context );
00084
00085 sty = addStyleTemplate( sty );
00086
00087 sty->setFollowingStyle( sty );
00088
00089 kdDebug() << " Loaded style " << sty->name() << endl;
00090
00091 if(styleList().count() > followingStyles.count() )
00092 {
00093 const QString following = styleElem.attributeNS( KoXmlNS::style, "next-style-name", QString::null );
00094 followingStyles.append( following );
00095 }
00096 else
00097 kdWarning() << "Found duplicate style declaration, overwriting former " << sty->name() << endl;
00098 }
00099
00100 if( followingStyles.count() != styleList().count() ) {
00101 kdDebug() << "Ouch, " << followingStyles.count() << " following-styles, but "
00102 << styleList().count() << " styles in styleList" << endl;
00103 }
00104
00105 unsigned int i=0;
00106 for( QValueList<QString>::ConstIterator it = followingStyles.begin(); it != followingStyles.end(); ++it, ++i ) {
00107 const QString followingStyleName = *it;
00108 if ( !followingStyleName.isEmpty() ) {
00109 KoParagStyle * style = findStyle( followingStyleName );
00110 if ( style )
00111 styleAt(i)->setFollowingStyle( style );
00112 }
00113 }
00114
00115
00116
00117 Q_ASSERT( findStyle( "Standard" ) );
00118 }
00119
00120 QMap<KoParagStyle*, QString> KoStyleCollection::saveOasis( KoGenStyles& styles, int styleType, KoSavingContext& context ) const
00121 {
00122
00123 QMap<KoParagStyle*, QString> autoNames;
00124
00125
00126
00127
00128
00129 QString refStyleName;
00130
00131 for( QPtrListIterator<KoParagStyle> p( m_styleList ); *p; ++p ) {
00132 const QString name = (*p)->saveStyle( styles, styleType, refStyleName, context );
00133 kdDebug() << k_funcinfo << "Saved style " << (*p)->displayName() << " to OASIS format as " << name << endl;
00134 autoNames.insert( *p, name );
00135 if ( refStyleName.isEmpty() )
00136 refStyleName = name;
00137 }
00138
00139
00140
00141
00142 for( QPtrListIterator<KoParagStyle> p( m_styleList ); *p; ++p ) {
00143 KoParagStyle* style = *p;
00144 if ( style->followingStyle() && style->followingStyle() != style ) {
00145 const QString fsname = autoNames[ style->followingStyle() ];
00146 KoGenStyle* gs = styles.styleForModification( autoNames[style] );
00147 Q_ASSERT( gs );
00148 if ( gs )
00149 gs->addAttribute( "style:next-style-name", fsname );
00150 }
00151 }
00152 return autoNames;
00153 }
00154
00155
00156 KoParagStyle* KoStyleCollection::findStyle( const QString & _name ) const
00157 {
00158
00159 if ( m_lastStyle && m_lastStyle->name() == _name )
00160 return m_lastStyle;
00161
00162 QPtrListIterator<KoParagStyle> styleIt( m_styleList );
00163 for ( ; styleIt.current(); ++styleIt )
00164 {
00165 if ( styleIt.current()->name() == _name ) {
00166 m_lastStyle = styleIt.current();
00167 return m_lastStyle;
00168 }
00169 }
00170
00171 if(_name == "Standard") return m_styleList.getFirst();
00172
00173 return 0L;
00174 }
00175
00176
00177 KoParagStyle* KoStyleCollection::findTranslatedStyle( const QString & _name ) const
00178 {
00179
00180 if ( m_lastStyle && m_lastStyle->displayName() == _name )
00181 return m_lastStyle;
00182
00183 QPtrListIterator<KoParagStyle> styleIt( m_styleList );
00184 for ( ; styleIt.current(); ++styleIt )
00185 {
00186 if ( styleIt.current()->displayName() == _name ) {
00187 m_lastStyle = styleIt.current();
00188 return m_lastStyle;
00189 }
00190 }
00191
00192 if ( ( _name == "Standard" ) || ( _name == i18n( "Style name", "Standard" ) ) )
00193 return m_styleList.getFirst();
00194
00195 return 0L;
00196 }
00197
00198
00199 KoParagStyle* KoStyleCollection::findStyleShortCut( const QString & _shortCut ) const
00200 {
00201
00202 if ( m_lastStyle && m_lastStyle->shortCutName() == _shortCut )
00203 return m_lastStyle;
00204
00205 QPtrListIterator<KoParagStyle> styleIt( m_styleList );
00206 for ( ; styleIt.current(); ++styleIt )
00207 {
00208 if ( styleIt.current()->shortCutName() == _shortCut ) {
00209 m_lastStyle = styleIt.current();
00210 return m_lastStyle;
00211 }
00212 }
00213 return 0L;
00214 }
00215
00216 KoParagStyle* KoStyleCollection::addStyleTemplate( KoParagStyle * sty )
00217 {
00218
00219 for ( KoParagStyle* p = m_styleList.first(); p != 0L; p = m_styleList.next() )
00220 {
00221 if ( p->name() == sty->name() ) {
00222 if ( p->displayName() == sty->displayName() ) {
00223
00224
00225 if ( sty != p )
00226 {
00227 *p = *sty;
00228 delete sty;
00229 }
00230 return p;
00231 } else {
00232 sty->setInternalName( generateUniqueName() );
00233 }
00234 }
00235 }
00236 m_styleList.append( sty );
00237
00238 sty->setShortCutName( QString("shortcut_style_%1").arg(styleNumber).latin1());
00239 styleNumber++;
00240 return sty;
00241 }
00242
00243 void KoStyleCollection::removeStyleTemplate ( KoParagStyle *style ) {
00244 if( m_styleList.removeRef(style)) {
00245 if ( m_lastStyle == style )
00246 m_lastStyle = 0L;
00247
00248 m_deletedStyles.append(style);
00249 }
00250 }
00251
00252 void KoStyleCollection::updateStyleListOrder( const QStringList &list )
00253 {
00254 QPtrList<KoParagStyle> orderStyle;
00255 QStringList lst( list );
00256 for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it )
00257 {
00258
00259 bool found = false;
00260 QPtrListIterator<KoParagStyle> style( m_styleList );
00261 for ( ; style.current() ; ++style )
00262 {
00263 if ( style.current()->name() == *it)
00264 {
00265 orderStyle.append( style.current() );
00266 found = true;
00267
00268 break;
00269 }
00270 }
00271 if ( !found )
00272 kdDebug() << "style " << *it << " not found" << endl;
00273 }
00274 m_styleList.setAutoDelete( false );
00275 m_styleList.clear();
00276 m_styleList = orderStyle;
00277 #if 0
00278 QPtrListIterator<KoParagStyle> style( m_styleList );
00279 for ( ; style.current() ; ++style )
00280 {
00281 kdDebug()<<" style.current()->name() :"<<style.current()->name()<<endl;
00282 }
00283 #endif
00284 }
00285
00286 void KoStyleCollection::importStyles( const QPtrList<KoParagStyle>& styleList )
00287 {
00288 QPtrListIterator<KoParagStyle> styleIt( styleList );
00289 QMap<QString, QString> followStyle;
00290 for ( ; styleIt.current() ; ++styleIt )
00291 {
00292 KoParagStyle* style = new KoParagStyle(*styleIt.current());
00293 if ( style->followingStyle() ) {
00294 followStyle.insert( style->name(), style->followingStyle()->name() );
00295 }
00296 style = addStyleTemplate( style );
00297 }
00298
00299 QMapIterator<QString, QString> itFollow = followStyle.begin();
00300 for ( ; itFollow != followStyle.end(); ++itFollow )
00301 {
00302 KoParagStyle * style = findStyle(itFollow.key());
00303 const QString followingStyleName = followStyle[ itFollow.key() ];
00304 KoParagStyle * styleFollow = findStyle(followingStyleName);
00305
00306 Q_ASSERT(styleFollow);
00307 if ( styleFollow )
00308 style->setFollowingStyle( styleFollow );
00309 else
00310 style->setFollowingStyle( style );
00311 }
00312 }
00313
00314 void KoStyleCollection::saveOasisOutlineStyles( KoXmlWriter& writer ) const
00315 {
00316 bool first = true;
00317 QValueVector<KoParagStyle *> styles = outlineStyles();
00318 for ( int i = 0 ; i < 10 ; ++i ) {
00319 if ( styles[i] ) {
00320 if ( first ) {
00321 writer.startElement( "text:outline-style" );
00322 first = false;
00323 }
00324 writer.startElement( "text:outline-level-style" );
00325 styles[i]->paragLayout().counter->saveOasisListLevel( writer, true, true );
00326 writer.endElement();
00327 }
00328 }
00329 if ( !first )
00330 writer.endElement();
00331 }
00332
00333 QValueVector<KoParagStyle *> KoStyleCollection::outlineStyles() const
00334 {
00335 QValueVector<KoParagStyle *> lst( 10, 0 );
00336 for ( int i = 0 ; i < 10 ; ++i ) {
00337 KoParagStyle* style = outlineStyleForLevel( i );
00338 if ( style )
00339 lst[i] = style;
00340 }
00341 return lst;
00342 }
00343
00344
00345 KoParagStyle* KoStyleCollection::outlineStyleForLevel( int level ) const
00346 {
00347 for( QPtrListIterator<KoParagStyle> p( m_styleList ); *p; ++p )
00348 {
00349 if ( (*p)->isOutline() && (*p)->paragLayout().counter )
00350 {
00351 int styleLevel = (*p)->paragLayout().counter->depth();
00352 if ( styleLevel == level )
00353 return *p;
00354 }
00355 }
00356 return 0;
00357 }
00358
00359 KoParagStyle* KoStyleCollection::numberedStyleForLevel( int level ) const
00360 {
00361 for( QPtrListIterator<KoParagStyle> p( m_styleList ); *p; ++p )
00362 {
00363 KoParagCounter* counter = (*p)->paragLayout().counter;
00364 if ( !(*p)->isOutline() && counter
00365 && counter->numbering() != KoParagCounter::NUM_NONE
00366 && !counter->isBullet() )
00367 {
00368 int styleLevel = counter->depth();
00369 if ( styleLevel == level )
00370 return *p;
00371 }
00372 }
00373 return 0;
00374 }
00375
00376
00377 KoParagStyle* KoStyleCollection::defaultStyle() const
00378 {
00379 return findStyle( "Standard" );
00380 }
00381
00382 QString KoStyleCollection::generateUniqueName() const
00383 {
00384 int count = 1;
00385 QString name;
00386 do {
00387 name = "new" + QString::number( count++ );
00388 } while ( findStyle( name ) );
00389 return name;
00390 }
00391
00392 #ifndef NDEBUG
00393 void KoStyleCollection::printDebug() const
00394 {
00395 for( QPtrListIterator<KoParagStyle> p( m_styleList ); *p; ++p )
00396 {
00397 kdDebug() << *p << " " << (*p)->name() << " " << (*p)->displayName() << " followingStyle=" << (*p)->followingStyle() << endl;
00398 }
00399 }
00400 #endif
00401
00403
00404 KoCharStyle::KoCharStyle( const QString & name )
00405 {
00406 m_name = name;
00407 m_displayName = i18n( "Style name", m_name.utf8() );
00408 }
00409
00410 QString KoCharStyle::displayName() const
00411 {
00412 return m_displayName;
00413 }
00414
00415 void KoCharStyle::setDisplayName( const QString& name )
00416 {
00417 m_displayName = name;
00418 }
00419
00420 const KoTextFormat & KoCharStyle::format() const
00421 {
00422 return m_format;
00423 }
00424
00425 KoTextFormat & KoCharStyle::format()
00426 {
00427 return m_format;
00428 }
00429
00431
00432 KoParagStyle::KoParagStyle( const QString & name )
00433 : KoCharStyle( name )
00434 {
00435 m_followingStyle = this;
00436
00437
00438 m_paragLayout.style = this;
00439 m_parentStyle = 0L;
00440 m_inheritedParagLayoutFlag = 0;
00441 m_inheritedFormatFlag = 0;
00442 m_bOutline = false;
00443 }
00444
00445 KoParagStyle::KoParagStyle( const KoParagStyle & rhs )
00446 : KoCharStyle( rhs)
00447 {
00448 *this = rhs;
00449 }
00450
00451 KoParagStyle::~KoParagStyle()
00452 {
00453 }
00454
00455 void KoParagStyle::operator=( const KoParagStyle &rhs )
00456 {
00457 KoCharStyle::operator=( rhs );
00458 m_paragLayout = rhs.m_paragLayout;
00459 m_followingStyle = rhs.m_followingStyle;
00460 m_paragLayout.style = this;
00461 m_parentStyle = rhs.m_parentStyle;
00462 m_inheritedParagLayoutFlag = rhs.m_inheritedParagLayoutFlag;
00463 m_inheritedFormatFlag = rhs.m_inheritedFormatFlag;
00464 m_bOutline = rhs.m_bOutline;
00465 }
00466
00467 void KoParagStyle::setFollowingStyle( KoParagStyle *fst )
00468 {
00469 m_followingStyle = fst;
00470 }
00471
00472 void KoParagStyle::saveStyle( QDomElement & parentElem )
00473 {
00474 m_paragLayout.saveParagLayout( parentElem, m_paragLayout.alignment );
00475
00476 if ( followingStyle() )
00477 {
00478 QDomElement element = parentElem.ownerDocument().createElement( "FOLLOWING" );
00479 parentElem.appendChild( element );
00480 element.setAttribute( "name", followingStyle()->displayName() );
00481 }
00482
00483
00484 parentElem.setAttribute( "outline", m_bOutline ? "true" : "false" );
00485 }
00486
00487 void KoParagStyle::loadStyle( QDomElement & parentElem, int docVersion )
00488 {
00489 KoParagLayout layout;
00490 KoParagLayout::loadParagLayout( layout, parentElem, docVersion );
00491
00492
00493 layout.style = this;
00494 m_paragLayout = layout;
00495
00496
00497 QDomElement nameElem = parentElem.namedItem("NAME").toElement();
00498 if ( !nameElem.isNull() ) {
00499 m_name = nameElem.attribute("value");
00500 m_displayName = i18n( "Style name", m_name.utf8() );
00501 } else
00502 kdWarning() << "No NAME tag in LAYOUT -> no name for this style!" << endl;
00503
00504
00505
00506 m_bOutline = parentElem.attribute( "outline" ) == "true";
00507 }
00508
00509 void KoParagStyle::loadStyle( QDomElement & styleElem, KoOasisContext& context )
00510 {
00511
00512 m_name = styleElem.attributeNS( KoXmlNS::style, "name", QString::null );
00513 m_displayName = styleElem.attributeNS( KoXmlNS::style, "display-name", QString::null );
00514 if ( m_displayName.isEmpty() )
00515 m_displayName = m_name;
00516
00517
00518
00519
00520 m_bOutline = styleElem.hasAttributeNS( KoXmlNS::style, "default-outline-level" );
00521
00522 context.styleStack().save();
00523 context.addStyles( &styleElem );
00524 KoParagLayout layout;
00525 KoParagLayout::loadOasisParagLayout( layout, context );
00526
00527
00528 int level = 0;
00529 bool listOK = false;
00530 const QString listStyleName = styleElem.attributeNS( KoXmlNS::style, "list-style-name", QString::null );
00531 if ( m_bOutline ) {
00532 level = styleElem.attributeNS( KoXmlNS::style, "default-outline-level", QString::null ).toInt();
00533 listOK = context.pushOutlineListLevelStyle( level );
00534
00535 if ( !listStyleName.isEmpty() )
00536 context.pushListLevelStyle( listStyleName, level );
00537 }
00538 else {
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549 level = styleElem.attributeNS( KoXmlNS::style, "default-level", "1" ).toInt();
00550 listOK = !listStyleName.isEmpty();
00551 if ( listOK )
00552 listOK = context.pushListLevelStyle( listStyleName, level );
00553 }
00554 if ( listOK ) {
00555 const QDomElement listStyle = context.listStyleStack().currentListStyle();
00556
00557 const bool ordered = listStyle.localName() == "list-level-style-number";
00558 Q_ASSERT( !layout.counter );
00559 layout.counter = new KoParagCounter;
00560 layout.counter->loadOasis( context, -1, ordered, m_bOutline, level, true );
00561 context.listStyleStack().pop();
00562 }
00563
00564
00565 layout.style = this;
00566 m_paragLayout = layout;
00567
00568 m_format.load( context );
00569
00570 context.styleStack().restore();
00571 }
00572
00573 QString KoParagStyle::saveStyle( KoGenStyles& genStyles, int styleType, const QString& parentStyleName, KoSavingContext& context ) const
00574 {
00575 KoGenStyle gs( styleType, "paragraph", parentStyleName );
00576
00577 gs.addAttribute( "style:display-name", m_displayName );
00578 if ( m_paragLayout.counter ) {
00579 if ( m_bOutline )
00580 gs.addAttribute( "style:default-outline-level", (int)m_paragLayout.counter->depth() + 1 );
00581 else if ( m_paragLayout.counter->depth() )
00582
00583 gs.addAttribute( "style:default-level", (int)m_paragLayout.counter->depth() + 1 );
00584
00585 if ( m_paragLayout.counter->numbering() != KoParagCounter::NUM_NONE &&
00586 m_paragLayout.counter->style() != KoParagCounter::STYLE_NONE )
00587 {
00588 KoGenStyle listStyle( KoGenStyle::STYLE_LIST );
00589 m_paragLayout.counter->saveOasis( listStyle, true );
00590
00591
00592 listStyle.addAttribute( "style:display-name",
00593 i18n( "Numbering Style for %1" ).arg( m_displayName ) );
00594
00595 QString autoListStyleName = genStyles.lookup( listStyle, "L", true );
00596 gs.addAttribute( "style:list-style-name", autoListStyleName );
00597 }
00598 }
00599
00600 m_paragLayout.saveOasis( gs, context, true );
00601
00602 m_format.save( gs, context );
00603
00604
00605
00606 bool nameIsConform = !m_name.isEmpty() && m_name.find( ' ' ) == -1;
00607 if ( nameIsConform )
00608 return genStyles.lookup( gs, m_name, false );
00609 else
00610 return genStyles.lookup( gs, "U", true );
00611 }
00612
00613 const KoParagLayout & KoParagStyle::paragLayout() const
00614 {
00615 return m_paragLayout;
00616 }
00617
00618 KoParagLayout & KoParagStyle::paragLayout()
00619 {
00620 return m_paragLayout;
00621 }
00622
00623 void KoParagStyle::propagateChanges( int paragLayoutFlag, int )
00624 {
00625 if ( !m_parentStyle )
00626 return;
00627 if ( !(paragLayoutFlag & KoParagLayout::Alignment) )
00628 m_paragLayout.alignment = m_parentStyle->paragLayout().alignment;
00629 if ( !(paragLayoutFlag & KoParagLayout::Margins) )
00630 for ( int i = 0 ; i < 5 ; ++i )
00631 m_paragLayout.margins[i] = m_parentStyle->paragLayout().margins[i];
00632 if ( !(paragLayoutFlag & KoParagLayout::LineSpacing) )
00633 {
00634 m_paragLayout.setLineSpacingValue(m_parentStyle->paragLayout().lineSpacingValue());
00635 m_paragLayout.lineSpacingType = m_parentStyle->paragLayout().lineSpacingType;
00636 }
00637 if ( !(paragLayoutFlag & KoParagLayout::Borders) )
00638 {
00639 m_paragLayout.leftBorder = m_parentStyle->paragLayout().leftBorder;
00640 m_paragLayout.rightBorder = m_parentStyle->paragLayout().rightBorder;
00641 m_paragLayout.topBorder = m_parentStyle->paragLayout().topBorder;
00642 m_paragLayout.bottomBorder = m_parentStyle->paragLayout().bottomBorder;
00643 }
00644 if ( !(paragLayoutFlag & KoParagLayout::BulletNumber) )
00645 m_paragLayout.counter = m_parentStyle->paragLayout().counter;
00646 if ( !(paragLayoutFlag & KoParagLayout::Tabulator) )
00647 m_paragLayout.setTabList(m_parentStyle->paragLayout().tabList());
00648 #if 0
00649 if ( paragLayoutFlag == KoParagLayout::All )
00650 {
00651 setDirection( static_cast<QChar::Direction>(layout.direction) );
00652
00653 setStyle( layout.style );
00654 }
00655 #endif
00656
00657
00658 }
00659
00660 void KoParagStyle::setOutline( bool b )
00661 {
00662 m_bOutline = b;
00663 }