00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "KoParagLayout.h"
00021 #include "KoRichText.h"
00022 #include "KoParagCounter.h"
00023 #include "KoStyleCollection.h"
00024 #include "KoOasisContext.h"
00025 #include <KoXmlWriter.h>
00026 #include <KoXmlNS.h>
00027 #include <KoDom.h>
00028 #include <KoGenStyles.h>
00029
00030 #include <kglobal.h>
00031 #include <klocale.h>
00032 #include <kdebug.h>
00033 #include <qdom.h>
00034 #include <qbuffer.h>
00035 #include <qcolor.h>
00036
00037 #include <float.h>
00038
00039 QString* KoParagLayout::shadowCssCompat = 0L;
00040
00041
00042 KoParagLayout::KoParagLayout()
00043 {
00044 initialise();
00045 }
00046
00047 void KoParagLayout::operator=( const KoParagLayout &layout )
00048 {
00049 alignment = layout.alignment;
00050 for ( int i = 0 ; i < 5 ; ++i )
00051 margins[i] = layout.margins[i];
00052 pageBreaking = layout.pageBreaking;
00053 leftBorder = layout.leftBorder;
00054 rightBorder = layout.rightBorder;
00055 topBorder = layout.topBorder;
00056 bottomBorder = layout.bottomBorder;
00057 joinBorder = layout.joinBorder;
00058 backgroundColor = layout.backgroundColor;
00059 if ( layout.counter )
00060 counter = new KoParagCounter( *layout.counter );
00061 else
00062 counter = 0L;
00063 lineSpacing = layout.lineSpacing;
00064 lineSpacingType = layout.lineSpacingType;
00065 style = layout.style;
00066 direction = layout.direction;
00067 setTabList( layout.tabList() );
00068 }
00069
00070 int KoParagLayout::compare( const KoParagLayout & layout ) const
00071 {
00072 int flags = 0;
00073 if ( alignment != layout.alignment )
00074 flags |= Alignment;
00075 for ( int i = 0 ; i < 5 ; ++i )
00076 if ( margins[i] != layout.margins[i] )
00077 {
00078 flags |= Margins;
00079 break;
00080 }
00081 if ( pageBreaking != layout.pageBreaking )
00082 flags |= PageBreaking;
00083 if ( leftBorder != layout.leftBorder
00084 || rightBorder != layout.rightBorder
00085 || topBorder != layout.topBorder
00086 || bottomBorder != layout.bottomBorder
00087 || joinBorder != layout.joinBorder )
00088 flags |= Borders;
00089
00090 if ( layout.counter )
00091 {
00092 if ( counter )
00093 {
00094 if ( ! ( *layout.counter == *counter ) )
00095 flags |= BulletNumber;
00096 } else
00097 if ( layout.counter->numbering() != KoParagCounter::NUM_NONE )
00098 flags |= BulletNumber;
00099 }
00100 else
00101 if ( counter && counter->numbering() != KoParagCounter::NUM_NONE )
00102 flags |= BulletNumber;
00103
00104 if ( lineSpacing != layout.lineSpacing
00105 || lineSpacingType != layout.lineSpacingType )
00106 flags |= LineSpacing;
00107
00108
00109 if ( m_tabList != layout.m_tabList )
00110 flags |= Tabulator;
00111
00112 if ( backgroundColor != layout.backgroundColor)
00113 flags |= BackgroundColor;
00114
00115
00116
00117 return flags;
00118 }
00119
00120 void KoParagLayout::initialise()
00121 {
00122 alignment = Qt::AlignAuto;
00123 for ( int i = 0 ; i < 5 ; ++i )
00124 margins[i] = 0;
00125 lineSpacingType = LS_SINGLE;
00126 lineSpacing = 0;
00127 counter = 0L;
00128 leftBorder.setPenWidth( 0);
00129 rightBorder.setPenWidth( 0);
00130 topBorder.setPenWidth( 0);
00131 bottomBorder.setPenWidth( 0);
00132 joinBorder = true;
00133 pageBreaking = 0;
00134 style = 0L;
00135 direction = QChar::DirON;
00136 m_tabList.clear();
00137 }
00138
00139 KoParagLayout::~KoParagLayout()
00140 {
00141 delete counter;
00142 }
00143
00144 void KoParagLayout::loadParagLayout( KoParagLayout& layout, const QDomElement& parentElem, int docVersion )
00145 {
00146
00147
00148
00149
00150
00151
00152
00153
00154 KoTabulatorList tabList;
00155 QDomElement element = parentElem.firstChild().toElement();
00156 for ( ; !element.isNull() ; element = element.nextSibling().toElement() )
00157 {
00158 if ( element.tagName() == "TABULATOR" )
00159 {
00160 KoTabulator tab;
00161 tab.type = static_cast<KoTabulators>( getAttribute( element, "type", T_LEFT ) );
00162 tab.ptPos = getAttribute( element, "ptpos", 0.0 );
00163 tab.filling = static_cast<KoTabulatorFilling>( getAttribute( element, "filling", TF_BLANK ) );
00164 tab.ptWidth = getAttribute( element, "width", 0.5 );
00165 QString alignCharStr = element.attribute("alignchar");
00166 if ( alignCharStr.isEmpty() )
00167 tab.alignChar = KGlobal::locale()->decimalSymbol()[0];
00168 else
00169 tab.alignChar = alignCharStr[0];
00170 tabList.append( tab );
00171 }
00172 }
00173 qHeapSort( tabList );
00174 layout.setTabList( tabList );
00175 layout.alignment = Qt::AlignAuto;
00176 element = parentElem.namedItem( "FLOW" ).toElement();
00177 if ( !element.isNull() )
00178 {
00179 QString flow = element.attribute( "align" );
00180 if ( !flow.isEmpty() )
00181 {
00182 layout.alignment = flow=="right" ? Qt::AlignRight :
00183 flow=="center" ? Qt::AlignHCenter :
00184 flow=="justify" ? Qt::AlignJustify :
00185 flow=="left" ? Qt::AlignLeft : Qt::AlignAuto;
00186
00187 QString dir = element.attribute( "dir" );
00188 if ( !dir.isEmpty() ) {
00189 if ( dir == "L" )
00190 layout.direction = QChar::DirL;
00191 else if ( dir == "R" )
00192 layout.direction = QChar::DirR;
00193 else
00194 kdWarning() << "Unexpected value for paragraph direction: " << dir << endl;
00195 }
00196 } else {
00197 flow = element.attribute( "value" );
00198 static const int flow2align[] = { Qt::AlignAuto, Qt::AlignRight, Qt::AlignHCenter, Qt::AlignJustify };
00199 if ( !flow.isEmpty() && flow.toInt() < 4 )
00200 layout.alignment = flow2align[flow.toInt()];
00201 }
00202 }
00203
00204 if ( docVersion < 2 )
00205 {
00206 element = parentElem.namedItem( "OHEAD" ).toElement();
00207 if ( !element.isNull() )
00208 layout.margins[QStyleSheetItem::MarginTop] = getAttribute( element, "pt", 0.0 );
00209
00210 element = parentElem.namedItem( "OFOOT" ).toElement();
00211 if ( !element.isNull() )
00212 layout.margins[QStyleSheetItem::MarginBottom] = getAttribute( element, "pt", 0.0 );
00213
00214 element = parentElem.namedItem( "IFIRST" ).toElement();
00215 if ( !element.isNull() )
00216 layout.margins[QStyleSheetItem::MarginFirstLine] = getAttribute( element, "pt", 0.0 );
00217
00218 element = parentElem.namedItem( "ILEFT" ).toElement();
00219 if ( !element.isNull() )
00220 layout.margins[QStyleSheetItem::MarginLeft] = getAttribute( element, "pt", 0.0 );
00221 }
00222
00223
00224 element = parentElem.namedItem( "INDENTS" ).toElement();
00225 if ( !element.isNull() )
00226 {
00227 layout.margins[QStyleSheetItem::MarginFirstLine] = getAttribute( element, "first", 0.0 );
00228 layout.margins[QStyleSheetItem::MarginLeft] = getAttribute( element, "left", 0.0 );
00229 layout.margins[QStyleSheetItem::MarginRight] = getAttribute( element, "right", 0.0 );
00230 }
00231 element = parentElem.namedItem( "OFFSETS" ).toElement();
00232 if ( !element.isNull() )
00233 {
00234 layout.margins[QStyleSheetItem::MarginTop] = getAttribute( element, "before", 0.0 );
00235 layout.margins[QStyleSheetItem::MarginBottom] = getAttribute( element, "after", 0.0 );
00236 }
00237
00238 if ( docVersion < 2 )
00239 {
00240 element = parentElem.namedItem( "LINESPACE" ).toElement();
00241 if ( !element.isNull() )
00242 {
00243 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
00244 layout.lineSpacing = getAttribute( element, "pt", 0.0 );
00245 }
00246 }
00247
00248 element = parentElem.namedItem( "LINESPACING" ).toElement();
00249 if ( !element.isNull() )
00250 {
00251
00252 if ( element.hasAttribute( "value" ))
00253 {
00254 QString value = element.attribute( "value" );
00255 if ( value == "oneandhalf" )
00256 {
00257 layout.lineSpacingType = KoParagLayout::LS_ONEANDHALF;
00258 layout.lineSpacing = 0;
00259 }
00260 else if ( value == "double" )
00261 {
00262 layout.lineSpacingType = KoParagLayout::LS_DOUBLE;
00263 layout.lineSpacing = 0;
00264 }
00265 else
00266 {
00267 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
00268 layout.lineSpacing = value.toDouble();
00269 }
00270 }
00271 else
00272 {
00273 QString type = element.attribute( "type" );
00274 if ( type == "oneandhalf" )
00275 {
00276 layout.lineSpacingType = KoParagLayout::LS_ONEANDHALF;
00277 layout.lineSpacing = 0;
00278 }
00279 else if ( type == "double" )
00280 {
00281 layout.lineSpacingType = KoParagLayout::LS_DOUBLE;
00282 layout.lineSpacing = 0;
00283 }
00284 else if ( type == "custom" )
00285 {
00286 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
00287 layout.lineSpacing = element.attribute( "spacingvalue" ).toDouble();
00288 }
00289 else if ( type == "atleast" )
00290 {
00291 layout.lineSpacingType = KoParagLayout::LS_AT_LEAST;
00292 layout.lineSpacing = element.attribute( "spacingvalue" ).toDouble();
00293 }
00294 else if ( type == "multiple" )
00295 {
00296 layout.lineSpacingType = KoParagLayout::LS_MULTIPLE;
00297 layout.lineSpacing = element.attribute( "spacingvalue" ).toDouble();
00298 }
00299 else if ( type == "fixed" )
00300 {
00301 layout.lineSpacingType = KoParagLayout::LS_FIXED;
00302 layout.lineSpacing = element.attribute( "spacingvalue" ).toDouble();
00303 }
00304 else if ( type == "single" )
00305 layout.lineSpacingType = KoParagLayout::LS_SINGLE;
00306 }
00307 }
00308
00309 int pageBreaking = 0;
00310 element = parentElem.namedItem( "PAGEBREAKING" ).toElement();
00311 if ( !element.isNull() )
00312 {
00313 if ( element.attribute( "linesTogether" ) == "true" )
00314 pageBreaking |= KoParagLayout::KeepLinesTogether;
00315 if ( element.attribute( "hardFrameBreak" ) == "true" )
00316 pageBreaking |= KoParagLayout::HardFrameBreakBefore;
00317 if ( element.attribute( "hardFrameBreakAfter" ) == "true" )
00318 pageBreaking |= KoParagLayout::HardFrameBreakAfter;
00319 }
00320 if ( docVersion < 2 )
00321 {
00322 element = parentElem.namedItem( "HARDBRK" ).toElement();
00323 if ( !element.isNull() )
00324 pageBreaking |= KoParagLayout::HardFrameBreakBefore;
00325 }
00326 layout.pageBreaking = pageBreaking;
00327
00328 element = parentElem.namedItem( "LEFTBORDER" ).toElement();
00329 if ( !element.isNull() )
00330 layout.leftBorder = KoBorder::loadBorder( element );
00331 else
00332 layout.leftBorder.setPenWidth(0);
00333
00334 element = parentElem.namedItem( "RIGHTBORDER" ).toElement();
00335 if ( !element.isNull() )
00336 layout.rightBorder = KoBorder::loadBorder( element );
00337 else
00338 layout.rightBorder.setPenWidth(0);
00339
00340 element = parentElem.namedItem( "TOPBORDER" ).toElement();
00341 if ( !element.isNull() )
00342 layout.topBorder = KoBorder::loadBorder( element );
00343 else
00344 layout.topBorder.setPenWidth(0);
00345
00346 element = parentElem.namedItem( "BOTTOMBORDER" ).toElement();
00347 if ( !element.isNull() )
00348 layout.bottomBorder = KoBorder::loadBorder( element );
00349 else
00350 layout.bottomBorder.setPenWidth(0);
00351
00352 element = parentElem.namedItem( "COUNTER" ).toElement();
00353 if ( !element.isNull() )
00354 {
00355 layout.counter = new KoParagCounter;
00356 layout.counter->load( element );
00357 }
00358
00359
00360 element = parentElem.namedItem( "SHADOW" ).toElement();
00361 if ( !element.isNull() && element.hasAttribute("direction") )
00362 {
00363 int shadowDistance = element.attribute("distance").toInt();
00364 int shadowDirection = element.attribute("direction").toInt();
00365 QColor shadowColor;
00366 if ( element.hasAttribute("red") )
00367 {
00368 int r = element.attribute("red").toInt();
00369 int g = element.attribute("green").toInt();
00370 int b = element.attribute("blue").toInt();
00371 shadowColor.setRgb( r, g, b );
00372 }
00373 int distanceX = 0;
00374 int distanceY = 0;
00375 switch ( shadowDirection )
00376 {
00377 case 1:
00378 case 2:
00379 case 3:
00380 distanceX = - shadowDistance;
00381 break;
00382 case 7:
00383 case 6:
00384 case 5:
00385 distanceX = shadowDistance;
00386 break;
00387 }
00388 switch ( shadowDirection )
00389 {
00390 case 7:
00391 case 8:
00392 case 1:
00393 distanceY = - shadowDistance;
00394 break;
00395 case 3:
00396 case 4:
00397 case 5:
00398 distanceY = shadowDistance;
00399 break;
00400 }
00401 if ( !shadowCssCompat )
00402 shadowCssCompat = new QString;
00403 *shadowCssCompat = KoTextFormat::shadowAsCss( distanceX, distanceY, shadowColor );
00404 kdDebug(32500) << "setting shadow compat to " << ( *shadowCssCompat ) << endl;
00405 }
00406 else
00407 {
00408 delete shadowCssCompat;
00409 shadowCssCompat = 0L;
00410 }
00411 }
00412
00413
00414 Qt::AlignmentFlags KoParagLayout::loadOasisAlignment( const QCString& str )
00415 {
00416 return
00417 str == "left" ? Qt::AlignLeft :
00418 str == "right" ? Qt::AlignRight :
00419 str == "start" ? Qt::AlignLeft :
00420 str == "end" ? Qt::AlignRight :
00421 str == "center" ? Qt::AlignHCenter :
00422 str == "justify" ? Qt::AlignJustify :
00423 str == "start" ? Qt::AlignAuto
00424 : Qt::AlignAuto;
00425 }
00426
00427
00428 QCString KoParagLayout::saveOasisAlignment( Qt::AlignmentFlags alignment )
00429 {
00430 return alignment == Qt::AlignLeft ? "left" :
00431 alignment == Qt::AlignRight ? "right" :
00432 alignment == Qt::AlignHCenter ? "center" :
00433 alignment == Qt::AlignJustify ? "justify" :
00434 "start";
00435 }
00436
00437 void KoParagLayout::loadOasisParagLayout( KoParagLayout& layout, KoOasisContext& context )
00438 {
00439 context.styleStack().setTypeProperties( "paragraph" );
00440
00441
00442
00443
00444 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "text-align" ) ) {
00445 QCString align = context.styleStack().attributeNS( KoXmlNS::fo, "text-align" ).latin1();
00446 layout.alignment = loadOasisAlignment( align );
00447 }
00448
00449 if ( context.styleStack().hasAttributeNS( KoXmlNS::style, "writing-mode" ) ) {
00450
00451 QString writingMode = context.styleStack().attributeNS( KoXmlNS::style, "writing-mode" );
00452 layout.direction = ( writingMode=="rl-tb" || writingMode=="rl" ) ? QChar::DirR : QChar::DirL;
00453 }
00454
00455
00456 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "margin-left" ) ||
00457 context.styleStack().hasAttributeNS( KoXmlNS::fo, "margin-right" ) ) {
00458 layout.margins[QStyleSheetItem::MarginLeft] = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-left" ) );
00459 layout.margins[QStyleSheetItem::MarginRight] = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-right" ) );
00460
00461 double first = 0;
00462 if ( context.styleStack().attributeNS( KoXmlNS::style, "auto-text-indent") == "true" )
00463
00464
00465
00466 first = 10;
00467 else if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "text-indent") )
00468 first = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "text-indent") );
00469
00470 layout.margins[QStyleSheetItem::MarginFirstLine] = first;
00471 }
00472
00473
00474 if( context.styleStack().hasAttributeNS( KoXmlNS::fo, "margin-top") ||
00475 context.styleStack().hasAttributeNS( KoXmlNS::fo, "margin-bottom")) {
00476 layout.margins[QStyleSheetItem::MarginTop] = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-top" ) );
00477 layout.margins[QStyleSheetItem::MarginBottom] = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-bottom" ) );
00478 }
00479
00480
00481 if( context.styleStack().hasAttributeNS( KoXmlNS::fo, "line-height") ) {
00482
00483 QString value = context.styleStack().attributeNS( KoXmlNS::fo, "line-height" );
00484 if ( value != "normal" ) {
00485 if ( value == "100%" )
00486 layout.lineSpacingType = KoParagLayout::LS_SINGLE;
00487 else if( value=="150%")
00488 layout.lineSpacingType = KoParagLayout::LS_ONEANDHALF;
00489 else if( value=="200%")
00490 layout.lineSpacingType = KoParagLayout::LS_DOUBLE;
00491 else if ( value.find('%') > -1 )
00492 {
00493 value = value.remove( '%' );
00494 double percent = value.toDouble();
00495 layout.lineSpacingType = KoParagLayout::LS_MULTIPLE;
00496 layout.lineSpacing = percent / 100.0;
00497 kdDebug(33001) << "line-height =" << percent << ", " << layout.lineSpacing << ", " << percent/100 << endl;
00498 }
00499 else
00500 {
00501 layout.lineSpacingType = KoParagLayout::LS_FIXED;
00502 layout.lineSpacing = KoUnit::parseValue( value );
00503 }
00504 }
00505 }
00506
00507 else if ( context.styleStack().hasAttributeNS( KoXmlNS::style, "line-height-at-least") )
00508 {
00509 QString value = context.styleStack().attributeNS( KoXmlNS::style, "line-height-at-least" );
00510
00511
00512
00513
00514
00515 layout.lineSpacingType = KoParagLayout::LS_AT_LEAST;
00516 layout.lineSpacing = KoUnit::parseValue( value );
00517 }
00518
00519 else if ( context.styleStack().hasAttributeNS( KoXmlNS::style, "line-spacing") )
00520 {
00521 double value = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::style, "line-spacing" ) );
00522 if ( value != 0.0 )
00523 {
00524 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
00525 layout.lineSpacing = value;
00526 }
00527 }
00528
00529
00530 KoTabulatorList tabList;
00531 if ( context.styleStack().hasChildNodeNS( KoXmlNS::style, "tab-stops" ) ) {
00532 QDomElement tabStops = context.styleStack().childNodeNS( KoXmlNS::style, "tab-stops" );
00533
00534 QDomElement tabStop;
00535 forEachElement( tabStop, tabStops )
00536 {
00537 Q_ASSERT( tabStop.localName() == "tab-stop" );
00538 const QString type = tabStop.attributeNS( KoXmlNS::style, "type", QString::null );
00539
00540 KoTabulator tab;
00541 tab.ptPos = KoUnit::parseValue( tabStop.attributeNS( KoXmlNS::style, "position", QString::null ) );
00542
00543 tab.ptPos += layout.margins[QStyleSheetItem::MarginLeft];
00544 if ( type == "center" )
00545 tab.type = T_CENTER;
00546 else if ( type == "right" )
00547 tab.type = T_RIGHT;
00548 else if ( type == "char" ) {
00549 QString delimiterChar = tabStop.attributeNS( KoXmlNS::style, "char", QString::null );
00550 if ( !delimiterChar.isEmpty() )
00551 tab.alignChar = delimiterChar[0];
00552 tab.type = T_DEC_PNT;
00553 }
00554 else
00555 tab.type = T_LEFT;
00556
00557 tab.ptWidth = KoUnit::parseValue( tabStop.attributeNS( KoXmlNS::style, "leader-width", QString::null ), 0.5 );
00558
00559 tab.filling = TF_BLANK;
00560 if ( tabStop.attributeNS( KoXmlNS::style, "leader-type", QString::null ) == "single" )
00561 {
00562 QString leaderStyle = tabStop.attributeNS( KoXmlNS::style, "leader-style", QString::null );
00563 if ( leaderStyle == "solid" )
00564 tab.filling = TF_LINE;
00565 else if ( leaderStyle == "dotted" )
00566 tab.filling = TF_DOTS;
00567 else if ( leaderStyle == "dash" )
00568 tab.filling = TF_DASH;
00569 else if ( leaderStyle == "dot-dash" )
00570 tab.filling = TF_DASH_DOT;
00571 else if ( leaderStyle == "dot-dot-dash" )
00572 tab.filling = TF_DASH_DOT_DOT;
00573 }
00574 else
00575 {
00576
00577 QString leaderChar = tabStop.attributeNS( KoXmlNS::style, "leader-text", QString::null );
00578 if ( !leaderChar.isEmpty() )
00579 {
00580 QChar ch = leaderChar[0];
00581 switch (ch.latin1()) {
00582 case '.':
00583 tab.filling = TF_DOTS; break;
00584 case '-':
00585 case '_':
00586 tab.filling = TF_LINE; break;
00587 default:
00588
00589 break;
00590 }
00591 }
00592 }
00593 tabList.append( tab );
00594 }
00595 }
00596 qHeapSort( tabList );
00597 layout.setTabList( tabList );
00598
00599 layout.joinBorder = !( context.styleStack().attributeNS( KoXmlNS::style, "join-border") == "false" );
00600
00601
00602 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "border","left") )
00603 layout.leftBorder.loadFoBorder( context.styleStack().attributeNS( KoXmlNS::fo, "border","left") );
00604 else
00605 layout.leftBorder.setPenWidth(0);
00606 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "border","right") )
00607 layout.rightBorder.loadFoBorder( context.styleStack().attributeNS( KoXmlNS::fo, "border","right") );
00608 else
00609 layout.rightBorder.setPenWidth(0);
00610 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "border","top") )
00611 layout.topBorder.loadFoBorder( context.styleStack().attributeNS( KoXmlNS::fo, "border","top") );
00612 else
00613 layout.topBorder.setPenWidth(0);
00614 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "border","bottom") )
00615 layout.bottomBorder.loadFoBorder( context.styleStack().attributeNS( KoXmlNS::fo, "border","bottom") );
00616 else
00617 layout.bottomBorder.setPenWidth(0);
00618
00619
00620
00621 int pageBreaking = 0;
00622 if( context.styleStack().hasAttributeNS( KoXmlNS::fo, "break-before") ||
00623 context.styleStack().hasAttributeNS( KoXmlNS::fo, "break-after") ||
00624 context.styleStack().hasAttributeNS( KoXmlNS::fo, "keep-together") ||
00625 context.styleStack().hasAttributeNS( KoXmlNS::style, "keep-with-next") ||
00626 context.styleStack().hasAttributeNS( KoXmlNS::fo, "keep-with-next") )
00627 {
00628 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "break-before") ) {
00629
00630 if ( context.styleStack().attributeNS( KoXmlNS::fo, "break-before" ) != "auto" )
00631 pageBreaking |= KoParagLayout::HardFrameBreakBefore;
00632 }
00633 else if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "break-after") ) {
00634
00635 if ( context.styleStack().attributeNS( KoXmlNS::fo, "break-after" ) != "auto" )
00636 pageBreaking |= KoParagLayout::HardFrameBreakAfter;
00637 }
00638
00639 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "keep-together" ) ) {
00640 if ( context.styleStack().attributeNS( KoXmlNS::fo, "keep-together" ) != "auto" )
00641 pageBreaking |= KoParagLayout::KeepLinesTogether;
00642 }
00643 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "keep-with-next" ) ) {
00644
00645 QString val = context.styleStack().attributeNS( KoXmlNS::fo, "keep-with-next" );
00646 if ( val == "true" || val == "always" )
00647 pageBreaking |= KoParagLayout::KeepWithNext;
00648 }
00649 }
00650 layout.pageBreaking = pageBreaking;
00651
00652
00653
00654 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "background-color" ) ) {
00655 QString bgColor = context.styleStack().attributeNS( KoXmlNS::fo, "background-color");
00656 if (bgColor != "transparent")
00657 layout.backgroundColor.setNamedColor( bgColor );
00658 }
00659 }
00660
00661 void KoParagLayout::saveParagLayout( QDomElement & parentElem, int alignment ) const
00662 {
00663 const KoParagLayout& layout = *this;
00664 QDomDocument doc = parentElem.ownerDocument();
00665 QDomElement element = doc.createElement( "NAME" );
00666 parentElem.appendChild( element );
00667 if ( layout.style )
00668 element.setAttribute( "value", layout.style->displayName() );
00669
00670
00671
00672 element = doc.createElement( "FLOW" );
00673 parentElem.appendChild( element );
00674
00675 element.setAttribute( "align", alignment==Qt::AlignRight ? "right" :
00676 alignment==Qt::AlignHCenter ? "center" :
00677 alignment==Qt::AlignJustify ? "justify" :
00678 alignment==Qt::AlignAuto ? "auto" : "left" );
00679
00680 if ( static_cast<QChar::Direction>(layout.direction) == QChar::DirR )
00681 element.setAttribute( "dir", "R" );
00682 else
00683 if ( static_cast<QChar::Direction>(layout.direction) == QChar::DirL )
00684 element.setAttribute( "dir", "L" );
00685
00686 if ( layout.margins[QStyleSheetItem::MarginFirstLine] != 0 ||
00687 layout.margins[QStyleSheetItem::MarginLeft] != 0 ||
00688 layout.margins[QStyleSheetItem::MarginRight] != 0 )
00689 {
00690 element = doc.createElement( "INDENTS" );
00691 parentElem.appendChild( element );
00692 if ( layout.margins[QStyleSheetItem::MarginFirstLine] != 0 )
00693 element.setAttribute( "first", layout.margins[QStyleSheetItem::MarginFirstLine] );
00694 if ( layout.margins[QStyleSheetItem::MarginLeft] != 0 )
00695 element.setAttribute( "left", layout.margins[QStyleSheetItem::MarginLeft] );
00696 if ( layout.margins[QStyleSheetItem::MarginRight] != 0 )
00697 element.setAttribute( "right", layout.margins[QStyleSheetItem::MarginRight] );
00698 }
00699
00700 if ( layout.margins[QStyleSheetItem::MarginTop] != 0 ||
00701 layout.margins[QStyleSheetItem::MarginBottom] != 0 )
00702 {
00703 element = doc.createElement( "OFFSETS" );
00704 parentElem.appendChild( element );
00705 if ( layout.margins[QStyleSheetItem::MarginTop] != 0 )
00706 element.setAttribute( "before", layout.margins[QStyleSheetItem::MarginTop] );
00707 if ( layout.margins[QStyleSheetItem::MarginBottom] != 0 )
00708 element.setAttribute( "after", layout.margins[QStyleSheetItem::MarginBottom] );
00709 }
00710 if ( layout.lineSpacingType != LS_SINGLE )
00711 {
00712 element = doc.createElement( "LINESPACING" );
00713 parentElem.appendChild( element );
00714 if ( layout.lineSpacingType == KoParagLayout::LS_ONEANDHALF ) {
00715 element.setAttribute( "type", "oneandhalf" );
00716 element.setAttribute( "value", "oneandhalf" );
00717 }
00718 else if ( layout.lineSpacingType == KoParagLayout::LS_DOUBLE ) {
00719 element.setAttribute( "type", "double" );
00720 element.setAttribute( "value", "double" );
00721 }
00722 else if ( layout.lineSpacingType == KoParagLayout::LS_CUSTOM )
00723 {
00724 element.setAttribute( "type", "custom" );
00725 element.setAttribute( "spacingvalue", layout.lineSpacing);
00726 element.setAttribute( "value", layout.lineSpacing );
00727 }
00728 else if ( layout.lineSpacingType == KoParagLayout::LS_AT_LEAST )
00729 {
00730 element.setAttribute( "type", "atleast" );
00731 element.setAttribute( "spacingvalue", layout.lineSpacing);
00732 }
00733 else if ( layout.lineSpacingType == KoParagLayout::LS_MULTIPLE )
00734 {
00735 element.setAttribute( "type", "multiple" );
00736 element.setAttribute( "spacingvalue", layout.lineSpacing);
00737 }
00738 else if ( layout.lineSpacingType == KoParagLayout::LS_FIXED )
00739 {
00740 element.setAttribute( "type", "fixed" );
00741 element.setAttribute( "spacingvalue", layout.lineSpacing);
00742 }
00743 else
00744 kdDebug()<<" error in lineSpacing Type\n";
00745 }
00746
00747 if ( layout.pageBreaking != 0 )
00748 {
00749 element = doc.createElement( "PAGEBREAKING" );
00750 parentElem.appendChild( element );
00751 if ( layout.pageBreaking & KoParagLayout::KeepLinesTogether )
00752 element.setAttribute( "linesTogether", "true" );
00753 if ( layout.pageBreaking & KoParagLayout::HardFrameBreakBefore )
00754 element.setAttribute( "hardFrameBreak", "true" );
00755 if ( layout.pageBreaking & KoParagLayout::HardFrameBreakAfter )
00756 element.setAttribute( "hardFrameBreakAfter", "true" );
00757 }
00758
00759 if ( layout.leftBorder.penWidth() > 0 )
00760 {
00761 element = doc.createElement( "LEFTBORDER" );
00762 parentElem.appendChild( element );
00763 layout.leftBorder.save( element );
00764 }
00765 if ( layout.rightBorder.penWidth() > 0 )
00766 {
00767 element = doc.createElement( "RIGHTBORDER" );
00768 parentElem.appendChild( element );
00769 layout.rightBorder.save( element );
00770 }
00771 if ( layout.topBorder.penWidth() > 0 )
00772 {
00773 element = doc.createElement( "TOPBORDER" );
00774 parentElem.appendChild( element );
00775 layout.topBorder.save( element );
00776 }
00777 if ( layout.bottomBorder.penWidth() > 0 )
00778 {
00779 element = doc.createElement( "BOTTOMBORDER" );
00780 parentElem.appendChild( element );
00781 layout.bottomBorder.save( element );
00782 }
00783 if ( layout.counter && layout.counter->numbering() != KoParagCounter::NUM_NONE )
00784 {
00785 element = doc.createElement( "COUNTER" );
00786 parentElem.appendChild( element );
00787 if ( layout.counter )
00788 layout.counter->save( element );
00789 }
00790
00791 KoTabulatorList tabList = layout.tabList();
00792 KoTabulatorList::ConstIterator it = tabList.begin();
00793 for ( ; it != tabList.end() ; it++ )
00794 {
00795 element = doc.createElement( "TABULATOR" );
00796 parentElem.appendChild( element );
00797 element.setAttribute( "type", (*it).type );
00798 element.setAttribute( "ptpos", (*it).ptPos );
00799 element.setAttribute( "filling", (*it).filling );
00800 if ( (*it).filling != TF_BLANK )
00801 element.setAttribute( "width", QString::number( (*it).ptWidth, 'g', DBL_DIG ) );
00802 if ( (*it).type == T_DEC_PNT && !(*it).alignChar.isNull() )
00803 element.setAttribute( "alignchar", QString((*it).alignChar) );
00804 }
00805 }
00806
00807 void KoParagLayout::saveOasis( KoGenStyle& gs, KoSavingContext& context, bool savingStyle ) const
00808 {
00809 gs.addProperty( "fo:text-align", saveOasisAlignment( (Qt::AlignmentFlags)alignment ).data() );
00810
00811
00812 if ( !savingStyle || (QChar::Direction) direction != QChar::DirON )
00813 gs.addProperty( "style:writing-mode", (QChar::Direction)direction == QChar::DirR ? "rl-tb" : "lr-tb" );
00814 gs.addPropertyPt( "fo:margin-left", margins[QStyleSheetItem::MarginLeft] );
00815 gs.addPropertyPt( "fo:margin-right", margins[QStyleSheetItem::MarginRight] );
00816 gs.addPropertyPt( "fo:text-indent", margins[QStyleSheetItem::MarginFirstLine] );
00817 gs.addPropertyPt( "fo:margin-top", margins[QStyleSheetItem::MarginTop] );
00818 gs.addPropertyPt( "fo:margin-bottom", margins[QStyleSheetItem::MarginBottom] );
00819
00820 switch ( lineSpacingType ) {
00821 case KoParagLayout::LS_SINGLE:
00822 gs.addProperty( "fo:line-height", "100%" );
00823 break;
00824 case KoParagLayout::LS_ONEANDHALF:
00825 gs.addProperty( "fo:line-height", "150%" );
00826 break;
00827 case KoParagLayout::LS_DOUBLE:
00828 gs.addProperty( "fo:line-height", "200%" );
00829 break;
00830 case KoParagLayout::LS_MULTIPLE:
00831 gs.addProperty( "fo:line-height", QString::number( lineSpacing * 100.0 ) + '%' );
00832 break;
00833 case KoParagLayout::LS_FIXED:
00834 gs.addPropertyPt( "fo:line-height", lineSpacing );
00835 break;
00836 case KoParagLayout::LS_CUSTOM:
00837 gs.addPropertyPt( "style:line-spacing", lineSpacing );
00838 break;
00839 case KoParagLayout::LS_AT_LEAST:
00840 gs.addPropertyPt( "style:line-height-at-least", lineSpacing );
00841 break;
00842 }
00843
00844 QBuffer buffer;
00845 buffer.open( IO_WriteOnly );
00846 KoXmlWriter tabsWriter( &buffer, 4 );
00847 tabsWriter.startElement( "style:tab-stops" );
00848 KoTabulatorList::ConstIterator it = m_tabList.begin();
00849 for ( ; it != m_tabList.end() ; it++ )
00850 {
00851 tabsWriter.startElement( "style:tab-stop" );
00852
00853 double pos = (*it).ptPos - margins[QStyleSheetItem::MarginLeft];
00854 tabsWriter.addAttributePt( "style:position", pos );
00855
00856 switch ( (*it).type ) {
00857 case T_LEFT:
00858 tabsWriter.addAttribute( "style:type", "left" );
00859 break;
00860 case T_CENTER:
00861 tabsWriter.addAttribute( "style:type", "center" );
00862 break;
00863 case T_RIGHT:
00864 tabsWriter.addAttribute( "style:type", "right" );
00865 break;
00866 case T_DEC_PNT:
00867 tabsWriter.addAttribute( "style:type", "char" );
00868 if ( !(*it).alignChar.isNull() )
00869 tabsWriter.addAttribute( "style:char", QString( (*it).alignChar ) );
00870 break;
00871 case T_INVALID:
00872 break;
00873 }
00874 switch( (*it).filling ) {
00875 case TF_BLANK:
00876 tabsWriter.addAttribute( "style:leader-type", "none" );
00877 break;
00878 case TF_LINE:
00879 tabsWriter.addAttribute( "style:leader-type", "single" );
00880 tabsWriter.addAttribute( "style:leader-style", "solid" );
00881
00882 tabsWriter.addAttribute( "style:leader-text", "_" );
00883 break;
00884 case TF_DOTS:
00885 tabsWriter.addAttribute( "style:leader-type", "single" );
00886 tabsWriter.addAttribute( "style:leader-style", "dotted" );
00887
00888 tabsWriter.addAttribute( "style:leader-text", "." );
00889 break;
00890 case TF_DASH:
00891 tabsWriter.addAttribute( "style:leader-type", "single" );
00892 tabsWriter.addAttribute( "style:leader-style", "dash" );
00893
00894 tabsWriter.addAttribute( "style:leader-text", "_" );
00895 break;
00896 case TF_DASH_DOT:
00897 tabsWriter.addAttribute( "style:leader-type", "single" );
00898 tabsWriter.addAttribute( "style:leader-style", "dot-dash" );
00899
00900 tabsWriter.addAttribute( "style:leader-text", "." );
00901 break;
00902 case TF_DASH_DOT_DOT:
00903 tabsWriter.addAttribute( "style:leader-type", "single" );
00904 tabsWriter.addAttribute( "style:leader-style", "dot-dot-dash" );
00905
00906 tabsWriter.addAttribute( "style:leader-text", "." );
00907 break;
00908 }
00909 if ( (*it).filling != TF_BLANK )
00910 tabsWriter.addAttributePt( "style:leader-width", (*it).ptWidth );
00911
00912 tabsWriter.endElement();
00913 }
00914 tabsWriter.endElement();
00915 buffer.close();
00916 QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
00917 gs.addChildElement( "style:tab-stops", elementContents );
00918
00919 if ( !joinBorder )
00920 gs.addProperty( "style:join-border", "false" );
00921 bool fourBordersEqual = leftBorder.penWidth() > 0 &&
00922 leftBorder == rightBorder && rightBorder == topBorder && topBorder == bottomBorder;
00923 if ( fourBordersEqual ) {
00924 gs.addProperty( "fo:border", leftBorder.saveFoBorder() );
00925 } else {
00926 if ( leftBorder.penWidth() > 0 )
00927 gs.addProperty( "fo:border-left", leftBorder.saveFoBorder() );
00928 if ( rightBorder.penWidth() > 0 )
00929 gs.addProperty( "fo:border-right", rightBorder.saveFoBorder() );
00930 if ( topBorder.penWidth() > 0 )
00931 gs.addProperty( "fo:border-top", topBorder.saveFoBorder() );
00932 if ( bottomBorder.penWidth() > 0 )
00933 gs.addProperty( "fo:border-bottom", bottomBorder.saveFoBorder() );
00934 }
00935
00936 if ( pageBreaking & KoParagLayout::HardFrameBreakBefore )
00937 gs.addProperty( "fo:break-before", context.hasColumns() ? "column" : "page" );
00938 else if ( pageBreaking & KoParagLayout::HardFrameBreakAfter )
00939 gs.addProperty( "fo:break-after", context.hasColumns() ? "column" : "page" );
00940 if ( pageBreaking & KoParagLayout::KeepLinesTogether )
00941 gs.addProperty( "fo:keep-together", "always" );
00942 if ( pageBreaking & KoParagLayout::KeepWithNext )
00943 gs.addProperty( "fo:keep-with-next", "always" );
00944
00945 gs.addProperty( "fo:background-color",
00946 backgroundColor.isValid() ?
00947 backgroundColor.name() : "transparent");
00948 }