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 case 7:
00382 case 6:
00383 case 5:
00384 distanceX = shadowDistance;
00385 }
00386 switch ( shadowDirection )
00387 {
00388 case 7:
00389 case 8:
00390 case 1:
00391 distanceY = - shadowDistance;
00392 case 3:
00393 case 4:
00394 case 5:
00395 distanceY = shadowDistance;
00396 }
00397 if ( !shadowCssCompat )
00398 shadowCssCompat = new QString;
00399 *shadowCssCompat = KoTextFormat::shadowAsCss( distanceX, distanceY, shadowColor );
00400 kdDebug(32500) << "setting shadow compat to " << ( *shadowCssCompat ) << endl;
00401 }
00402 else
00403 {
00404 delete shadowCssCompat;
00405 shadowCssCompat = 0L;
00406 }
00407 }
00408
00409
00410 Qt::AlignmentFlags KoParagLayout::loadOasisAlignment( const QCString& str )
00411 {
00412 return
00413 str == "left" ? Qt::AlignLeft :
00414 str == "right" ? Qt::AlignRight :
00415 str == "start" ? Qt::AlignLeft :
00416 str == "end" ? Qt::AlignRight :
00417 str == "center" ? Qt::AlignHCenter :
00418 str == "justify" ? Qt::AlignJustify :
00419 str == "start" ? Qt::AlignAuto
00420 : Qt::AlignAuto;
00421 }
00422
00423
00424 QCString KoParagLayout::saveOasisAlignment( Qt::AlignmentFlags alignment )
00425 {
00426 return alignment == Qt::AlignLeft ? "left" :
00427 alignment == Qt::AlignRight ? "right" :
00428 alignment == Qt::AlignHCenter ? "center" :
00429 alignment == Qt::AlignJustify ? "justify" :
00430 "start";
00431 }
00432
00433 void KoParagLayout::loadOasisParagLayout( KoParagLayout& layout, KoOasisContext& context )
00434 {
00435 context.styleStack().setTypeProperties( "paragraph" );
00436
00437
00438
00439
00440 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "text-align" ) ) {
00441 QCString align = context.styleStack().attributeNS( KoXmlNS::fo, "text-align" ).latin1();
00442 layout.alignment = loadOasisAlignment( align );
00443 }
00444
00445 if ( context.styleStack().hasAttributeNS( KoXmlNS::style, "writing-mode" ) ) {
00446
00447 QString writingMode = context.styleStack().attributeNS( KoXmlNS::style, "writing-mode" );
00448 layout.direction = ( writingMode=="rl-tb" || writingMode=="rl" ) ? QChar::DirR : QChar::DirL;
00449 }
00450
00451
00452 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "margin-left" ) ||
00453 context.styleStack().hasAttributeNS( KoXmlNS::fo, "margin-right" ) ) {
00454 layout.margins[QStyleSheetItem::MarginLeft] = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-left" ) );
00455 layout.margins[QStyleSheetItem::MarginRight] = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-right" ) );
00456
00457 double first = 0;
00458 if ( context.styleStack().attributeNS( KoXmlNS::style, "auto-text-indent") == "true" )
00459
00460
00461
00462 first = 10;
00463 else if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "text-indent") )
00464 first = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "text-indent") );
00465
00466 layout.margins[QStyleSheetItem::MarginFirstLine] = first;
00467 }
00468
00469
00470 if( context.styleStack().hasAttributeNS( KoXmlNS::fo, "margin-top") ||
00471 context.styleStack().hasAttributeNS( KoXmlNS::fo, "margin-bottom")) {
00472 layout.margins[QStyleSheetItem::MarginTop] = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-top" ) );
00473 layout.margins[QStyleSheetItem::MarginBottom] = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-bottom" ) );
00474 }
00475
00476
00477 if( context.styleStack().hasAttributeNS( KoXmlNS::fo, "line-height") ) {
00478
00479 QString value = context.styleStack().attributeNS( KoXmlNS::fo, "line-height" );
00480 if ( value != "normal" ) {
00481 if ( value == "100%" )
00482 layout.lineSpacingType = KoParagLayout::LS_SINGLE;
00483 else if( value=="150%")
00484 layout.lineSpacingType = KoParagLayout::LS_ONEANDHALF;
00485 else if( value=="200%")
00486 layout.lineSpacingType = KoParagLayout::LS_DOUBLE;
00487 else if ( value.find('%') > -1 )
00488 {
00489 value = value.remove( '%' );
00490 double percent = value.toDouble();
00491 layout.lineSpacingType = KoParagLayout::LS_MULTIPLE;
00492 layout.lineSpacing = percent / 100.0;
00493 kdDebug(33001) << "line-height =" << percent << ", " << layout.lineSpacing << ", " << percent/100 << endl;
00494 }
00495 else
00496 {
00497 layout.lineSpacingType = KoParagLayout::LS_FIXED;
00498 layout.lineSpacing = KoUnit::parseValue( value );
00499 }
00500 }
00501 }
00502
00503 else if ( context.styleStack().hasAttributeNS( KoXmlNS::style, "line-height-at-least") )
00504 {
00505 QString value = context.styleStack().attributeNS( KoXmlNS::style, "line-height-at-least" );
00506
00507
00508
00509
00510
00511 layout.lineSpacingType = KoParagLayout::LS_AT_LEAST;
00512 layout.lineSpacing = KoUnit::parseValue( value );
00513 }
00514
00515 else if ( context.styleStack().hasAttributeNS( KoXmlNS::style, "line-spacing") )
00516 {
00517 double value = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::style, "line-spacing" ) );
00518 if ( value != 0.0 )
00519 {
00520 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
00521 layout.lineSpacing = value;
00522 }
00523 }
00524
00525
00526 KoTabulatorList tabList;
00527 if ( context.styleStack().hasChildNodeNS( KoXmlNS::style, "tab-stops" ) ) {
00528 QDomElement tabStops = context.styleStack().childNodeNS( KoXmlNS::style, "tab-stops" );
00529
00530 QDomElement tabStop;
00531 forEachElement( tabStop, tabStops )
00532 {
00533 Q_ASSERT( tabStop.localName() == "tab-stop" );
00534 const QString type = tabStop.attributeNS( KoXmlNS::style, "type", QString::null );
00535
00536 KoTabulator tab;
00537 tab.ptPos = KoUnit::parseValue( tabStop.attributeNS( KoXmlNS::style, "position", QString::null ) );
00538
00539 tab.ptPos += layout.margins[QStyleSheetItem::MarginLeft];
00540 if ( type == "center" )
00541 tab.type = T_CENTER;
00542 else if ( type == "right" )
00543 tab.type = T_RIGHT;
00544 else if ( type == "char" ) {
00545 QString delimiterChar = tabStop.attributeNS( KoXmlNS::style, "char", QString::null );
00546 if ( !delimiterChar.isEmpty() )
00547 tab.alignChar = delimiterChar[0];
00548 tab.type = T_DEC_PNT;
00549 }
00550 else
00551 tab.type = T_LEFT;
00552
00553 tab.ptWidth = KoUnit::parseValue( tabStop.attributeNS( KoXmlNS::style, "leader-width", QString::null ), 0.5 );
00554
00555 tab.filling = TF_BLANK;
00556 if ( tabStop.attributeNS( KoXmlNS::style, "leader-type", QString::null ) == "single" )
00557 {
00558 QString leaderStyle = tabStop.attributeNS( KoXmlNS::style, "leader-style", QString::null );
00559 if ( leaderStyle == "solid" )
00560 tab.filling = TF_LINE;
00561 else if ( leaderStyle == "dotted" )
00562 tab.filling = TF_DOTS;
00563 else if ( leaderStyle == "dash" )
00564 tab.filling = TF_DASH;
00565 else if ( leaderStyle == "dot-dash" )
00566 tab.filling = TF_DASH_DOT;
00567 else if ( leaderStyle == "dot-dot-dash" )
00568 tab.filling = TF_DASH_DOT_DOT;
00569 }
00570 else
00571 {
00572
00573 QString leaderChar = tabStop.attributeNS( KoXmlNS::style, "leader-text", QString::null );
00574 if ( !leaderChar.isEmpty() )
00575 {
00576 QChar ch = leaderChar[0];
00577 switch (ch.latin1()) {
00578 case '.':
00579 tab.filling = TF_DOTS; break;
00580 case '-':
00581 case '_':
00582 tab.filling = TF_LINE; break;
00583 default:
00584
00585 break;
00586 }
00587 }
00588 }
00589 tabList.append( tab );
00590 }
00591 }
00592 qHeapSort( tabList );
00593 layout.setTabList( tabList );
00594
00595 layout.joinBorder = !( context.styleStack().attributeNS( KoXmlNS::style, "join-border") == "false" );
00596
00597
00598 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "border","left") )
00599 layout.leftBorder.loadFoBorder( context.styleStack().attributeNS( KoXmlNS::fo, "border","left") );
00600 else
00601 layout.leftBorder.setPenWidth(0);
00602 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "border","right") )
00603 layout.rightBorder.loadFoBorder( context.styleStack().attributeNS( KoXmlNS::fo, "border","right") );
00604 else
00605 layout.rightBorder.setPenWidth(0);
00606 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "border","top") )
00607 layout.topBorder.loadFoBorder( context.styleStack().attributeNS( KoXmlNS::fo, "border","top") );
00608 else
00609 layout.topBorder.setPenWidth(0);
00610 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "border","bottom") )
00611 layout.bottomBorder.loadFoBorder( context.styleStack().attributeNS( KoXmlNS::fo, "border","bottom") );
00612 else
00613 layout.bottomBorder.setPenWidth(0);
00614
00615
00616
00617 int pageBreaking = 0;
00618 if( context.styleStack().hasAttributeNS( KoXmlNS::fo, "break-before") ||
00619 context.styleStack().hasAttributeNS( KoXmlNS::fo, "break-after") ||
00620 context.styleStack().hasAttributeNS( KoXmlNS::fo, "keep-together") ||
00621 context.styleStack().hasAttributeNS( KoXmlNS::style, "keep-with-next") ||
00622 context.styleStack().hasAttributeNS( KoXmlNS::fo, "keep-with-next") )
00623 {
00624 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "break-before") ) {
00625
00626 if ( context.styleStack().attributeNS( KoXmlNS::fo, "break-before" ) != "auto" )
00627 pageBreaking |= KoParagLayout::HardFrameBreakBefore;
00628 }
00629 else if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "break-after") ) {
00630
00631 if ( context.styleStack().attributeNS( KoXmlNS::fo, "break-after" ) != "auto" )
00632 pageBreaking |= KoParagLayout::HardFrameBreakAfter;
00633 }
00634
00635 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "keep-together" ) ) {
00636 if ( context.styleStack().attributeNS( KoXmlNS::fo, "keep-together" ) != "auto" )
00637 pageBreaking |= KoParagLayout::KeepLinesTogether;
00638 }
00639 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "keep-with-next" ) ) {
00640
00641 QString val = context.styleStack().attributeNS( KoXmlNS::fo, "keep-with-next" );
00642 if ( val == "true" || val == "always" )
00643 pageBreaking |= KoParagLayout::KeepWithNext;
00644 }
00645 }
00646 layout.pageBreaking = pageBreaking;
00647
00648
00649
00650 if ( context.styleStack().hasAttributeNS( KoXmlNS::fo, "background-color" ) ) {
00651 QString bgColor = context.styleStack().attributeNS( KoXmlNS::fo, "background-color");
00652 if (bgColor != "transparent")
00653 layout.backgroundColor.setNamedColor( bgColor );
00654 }
00655 }
00656
00657 void KoParagLayout::saveParagLayout( QDomElement & parentElem, int alignment ) const
00658 {
00659 const KoParagLayout& layout = *this;
00660 QDomDocument doc = parentElem.ownerDocument();
00661 QDomElement element = doc.createElement( "NAME" );
00662 parentElem.appendChild( element );
00663 if ( layout.style )
00664 element.setAttribute( "value", layout.style->displayName() );
00665
00666
00667
00668 element = doc.createElement( "FLOW" );
00669 parentElem.appendChild( element );
00670
00671 element.setAttribute( "align", alignment==Qt::AlignRight ? "right" :
00672 alignment==Qt::AlignHCenter ? "center" :
00673 alignment==Qt::AlignJustify ? "justify" :
00674 alignment==Qt::AlignAuto ? "auto" : "left" );
00675
00676 if ( static_cast<QChar::Direction>(layout.direction) == QChar::DirR )
00677 element.setAttribute( "dir", "R" );
00678 else
00679 if ( static_cast<QChar::Direction>(layout.direction) == QChar::DirL )
00680 element.setAttribute( "dir", "L" );
00681
00682 if ( layout.margins[QStyleSheetItem::MarginFirstLine] != 0 ||
00683 layout.margins[QStyleSheetItem::MarginLeft] != 0 ||
00684 layout.margins[QStyleSheetItem::MarginRight] != 0 )
00685 {
00686 element = doc.createElement( "INDENTS" );
00687 parentElem.appendChild( element );
00688 if ( layout.margins[QStyleSheetItem::MarginFirstLine] != 0 )
00689 element.setAttribute( "first", layout.margins[QStyleSheetItem::MarginFirstLine] );
00690 if ( layout.margins[QStyleSheetItem::MarginLeft] != 0 )
00691 element.setAttribute( "left", layout.margins[QStyleSheetItem::MarginLeft] );
00692 if ( layout.margins[QStyleSheetItem::MarginRight] != 0 )
00693 element.setAttribute( "right", layout.margins[QStyleSheetItem::MarginRight] );
00694 }
00695
00696 if ( layout.margins[QStyleSheetItem::MarginTop] != 0 ||
00697 layout.margins[QStyleSheetItem::MarginBottom] != 0 )
00698 {
00699 element = doc.createElement( "OFFSETS" );
00700 parentElem.appendChild( element );
00701 if ( layout.margins[QStyleSheetItem::MarginTop] != 0 )
00702 element.setAttribute( "before", layout.margins[QStyleSheetItem::MarginTop] );
00703 if ( layout.margins[QStyleSheetItem::MarginBottom] != 0 )
00704 element.setAttribute( "after", layout.margins[QStyleSheetItem::MarginBottom] );
00705 }
00706 if ( layout.lineSpacingType != LS_SINGLE )
00707 {
00708 element = doc.createElement( "LINESPACING" );
00709 parentElem.appendChild( element );
00710 if ( layout.lineSpacingType == KoParagLayout::LS_ONEANDHALF ) {
00711 element.setAttribute( "type", "oneandhalf" );
00712 element.setAttribute( "value", "oneandhalf" );
00713 }
00714 else if ( layout.lineSpacingType == KoParagLayout::LS_DOUBLE ) {
00715 element.setAttribute( "type", "double" );
00716 element.setAttribute( "value", "double" );
00717 }
00718 else if ( layout.lineSpacingType == KoParagLayout::LS_CUSTOM )
00719 {
00720 element.setAttribute( "type", "custom" );
00721 element.setAttribute( "spacingvalue", layout.lineSpacing);
00722 element.setAttribute( "value", layout.lineSpacing );
00723 }
00724 else if ( layout.lineSpacingType == KoParagLayout::LS_AT_LEAST )
00725 {
00726 element.setAttribute( "type", "atleast" );
00727 element.setAttribute( "spacingvalue", layout.lineSpacing);
00728 }
00729 else if ( layout.lineSpacingType == KoParagLayout::LS_MULTIPLE )
00730 {
00731 element.setAttribute( "type", "multiple" );
00732 element.setAttribute( "spacingvalue", layout.lineSpacing);
00733 }
00734 else if ( layout.lineSpacingType == KoParagLayout::LS_FIXED )
00735 {
00736 element.setAttribute( "type", "fixed" );
00737 element.setAttribute( "spacingvalue", layout.lineSpacing);
00738 }
00739 else
00740 kdDebug()<<" error in lineSpacing Type\n";
00741 }
00742
00743 if ( layout.pageBreaking != 0 )
00744 {
00745 element = doc.createElement( "PAGEBREAKING" );
00746 parentElem.appendChild( element );
00747 if ( layout.pageBreaking & KoParagLayout::KeepLinesTogether )
00748 element.setAttribute( "linesTogether", "true" );
00749 if ( layout.pageBreaking & KoParagLayout::HardFrameBreakBefore )
00750 element.setAttribute( "hardFrameBreak", "true" );
00751 if ( layout.pageBreaking & KoParagLayout::HardFrameBreakAfter )
00752 element.setAttribute( "hardFrameBreakAfter", "true" );
00753 }
00754
00755 if ( layout.leftBorder.penWidth() > 0 )
00756 {
00757 element = doc.createElement( "LEFTBORDER" );
00758 parentElem.appendChild( element );
00759 layout.leftBorder.save( element );
00760 }
00761 if ( layout.rightBorder.penWidth() > 0 )
00762 {
00763 element = doc.createElement( "RIGHTBORDER" );
00764 parentElem.appendChild( element );
00765 layout.rightBorder.save( element );
00766 }
00767 if ( layout.topBorder.penWidth() > 0 )
00768 {
00769 element = doc.createElement( "TOPBORDER" );
00770 parentElem.appendChild( element );
00771 layout.topBorder.save( element );
00772 }
00773 if ( layout.bottomBorder.penWidth() > 0 )
00774 {
00775 element = doc.createElement( "BOTTOMBORDER" );
00776 parentElem.appendChild( element );
00777 layout.bottomBorder.save( element );
00778 }
00779 if ( layout.counter && layout.counter->numbering() != KoParagCounter::NUM_NONE )
00780 {
00781 element = doc.createElement( "COUNTER" );
00782 parentElem.appendChild( element );
00783 if ( layout.counter )
00784 layout.counter->save( element );
00785 }
00786
00787 KoTabulatorList tabList = layout.tabList();
00788 KoTabulatorList::ConstIterator it = tabList.begin();
00789 for ( ; it != tabList.end() ; it++ )
00790 {
00791 element = doc.createElement( "TABULATOR" );
00792 parentElem.appendChild( element );
00793 element.setAttribute( "type", (*it).type );
00794 element.setAttribute( "ptpos", (*it).ptPos );
00795 element.setAttribute( "filling", (*it).filling );
00796 if ( (*it).filling != TF_BLANK )
00797 element.setAttribute( "width", QString::number( (*it).ptWidth, 'g', DBL_DIG ) );
00798 if ( (*it).type == T_DEC_PNT && !(*it).alignChar.isNull() )
00799 element.setAttribute( "alignchar", QString((*it).alignChar) );
00800 }
00801 }
00802
00803 void KoParagLayout::saveOasis( KoGenStyle& gs, KoSavingContext& context, bool savingStyle ) const
00804 {
00805 gs.addProperty( "fo:text-align", saveOasisAlignment( (Qt::AlignmentFlags)alignment ).data() );
00806
00807
00808 if ( !savingStyle || (QChar::Direction) direction != QChar::DirON )
00809 gs.addProperty( "style:writing-mode", (QChar::Direction)direction == QChar::DirR ? "rl-tb" : "lr-tb" );
00810 gs.addPropertyPt( "fo:margin-left", margins[QStyleSheetItem::MarginLeft] );
00811 gs.addPropertyPt( "fo:margin-right", margins[QStyleSheetItem::MarginRight] );
00812 gs.addPropertyPt( "fo:text-indent", margins[QStyleSheetItem::MarginFirstLine] );
00813 gs.addPropertyPt( "fo:margin-top", margins[QStyleSheetItem::MarginTop] );
00814 gs.addPropertyPt( "fo:margin-bottom", margins[QStyleSheetItem::MarginBottom] );
00815
00816 switch ( lineSpacingType ) {
00817 case KoParagLayout::LS_SINGLE:
00818 gs.addProperty( "fo:line-height", "100%" );
00819 break;
00820 case KoParagLayout::LS_ONEANDHALF:
00821 gs.addProperty( "fo:line-height", "150%" );
00822 break;
00823 case KoParagLayout::LS_DOUBLE:
00824 gs.addProperty( "fo:line-height", "200%" );
00825 break;
00826 case KoParagLayout::LS_MULTIPLE:
00827 gs.addProperty( "fo:line-height", QString::number( lineSpacing * 100.0 ) + '%' );
00828 break;
00829 case KoParagLayout::LS_FIXED:
00830 gs.addPropertyPt( "fo:line-height", lineSpacing );
00831 break;
00832 case KoParagLayout::LS_CUSTOM:
00833 gs.addPropertyPt( "style:line-spacing", lineSpacing );
00834 break;
00835 case KoParagLayout::LS_AT_LEAST:
00836 gs.addPropertyPt( "style:line-height-at-least", lineSpacing );
00837 break;
00838 }
00839
00840 QBuffer buffer;
00841 buffer.open( IO_WriteOnly );
00842 KoXmlWriter tabsWriter( &buffer, 4 );
00843 tabsWriter.startElement( "style:tab-stops" );
00844 KoTabulatorList::ConstIterator it = m_tabList.begin();
00845 for ( ; it != m_tabList.end() ; it++ )
00846 {
00847 tabsWriter.startElement( "style:tab-stop" );
00848
00849 double pos = (*it).ptPos - margins[QStyleSheetItem::MarginLeft];
00850 tabsWriter.addAttributePt( "style:position", pos );
00851
00852 switch ( (*it).type ) {
00853 case T_LEFT:
00854 tabsWriter.addAttribute( "style:type", "left" );
00855 break;
00856 case T_CENTER:
00857 tabsWriter.addAttribute( "style:type", "center" );
00858 break;
00859 case T_RIGHT:
00860 tabsWriter.addAttribute( "style:type", "right" );
00861 break;
00862 case T_DEC_PNT:
00863 tabsWriter.addAttribute( "style:type", "char" );
00864 if ( !(*it).alignChar.isNull() )
00865 tabsWriter.addAttribute( "style:char", QString( (*it).alignChar ) );
00866 break;
00867 case T_INVALID:
00868 break;
00869 }
00870 switch( (*it).filling ) {
00871 case TF_BLANK:
00872 tabsWriter.addAttribute( "style:leader-type", "none" );
00873 break;
00874 case TF_LINE:
00875 tabsWriter.addAttribute( "style:leader-type", "single" );
00876 tabsWriter.addAttribute( "style:leader-style", "solid" );
00877
00878 tabsWriter.addAttribute( "style:leader-text", "_" );
00879 break;
00880 case TF_DOTS:
00881 tabsWriter.addAttribute( "style:leader-type", "single" );
00882 tabsWriter.addAttribute( "style:leader-style", "dotted" );
00883
00884 tabsWriter.addAttribute( "style:leader-text", "." );
00885 break;
00886 case TF_DASH:
00887 tabsWriter.addAttribute( "style:leader-type", "single" );
00888 tabsWriter.addAttribute( "style:leader-style", "dash" );
00889
00890 tabsWriter.addAttribute( "style:leader-text", "_" );
00891 break;
00892 case TF_DASH_DOT:
00893 tabsWriter.addAttribute( "style:leader-type", "single" );
00894 tabsWriter.addAttribute( "style:leader-style", "dot-dash" );
00895
00896 tabsWriter.addAttribute( "style:leader-text", "." );
00897 break;
00898 case TF_DASH_DOT_DOT:
00899 tabsWriter.addAttribute( "style:leader-type", "single" );
00900 tabsWriter.addAttribute( "style:leader-style", "dot-dot-dash" );
00901
00902 tabsWriter.addAttribute( "style:leader-text", "." );
00903 break;
00904 }
00905 if ( (*it).filling != TF_BLANK )
00906 tabsWriter.addAttributePt( "style:leader-width", (*it).ptWidth );
00907
00908 tabsWriter.endElement();
00909 }
00910 tabsWriter.endElement();
00911 buffer.close();
00912 QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
00913 gs.addChildElement( "style:tab-stops", elementContents );
00914
00915 if ( !joinBorder )
00916 gs.addProperty( "style:join-border", "false" );
00917 bool fourBordersEqual = leftBorder.penWidth() > 0 &&
00918 leftBorder == rightBorder && rightBorder == topBorder && topBorder == bottomBorder;
00919 if ( fourBordersEqual ) {
00920 gs.addProperty( "fo:border", leftBorder.saveFoBorder() );
00921 } else {
00922 if ( leftBorder.penWidth() > 0 )
00923 gs.addProperty( "fo:border-left", leftBorder.saveFoBorder() );
00924 if ( rightBorder.penWidth() > 0 )
00925 gs.addProperty( "fo:border-right", rightBorder.saveFoBorder() );
00926 if ( topBorder.penWidth() > 0 )
00927 gs.addProperty( "fo:border-top", topBorder.saveFoBorder() );
00928 if ( bottomBorder.penWidth() > 0 )
00929 gs.addProperty( "fo:border-bottom", bottomBorder.saveFoBorder() );
00930 }
00931
00932 if ( pageBreaking & KoParagLayout::HardFrameBreakBefore )
00933 gs.addProperty( "fo:break-before", context.hasColumns() ? "column" : "page" );
00934 else if ( pageBreaking & KoParagLayout::HardFrameBreakAfter )
00935 gs.addProperty( "fo:break-after", context.hasColumns() ? "column" : "page" );
00936 if ( pageBreaking & KoParagLayout::KeepLinesTogether )
00937 gs.addProperty( "fo:keep-together", "always" );
00938 if ( pageBreaking & KoParagLayout::KeepWithNext )
00939 gs.addProperty( "fo:keep-with-next", "always" );
00940
00941 gs.addProperty( "fo:background-color",
00942 backgroundColor.isValid() ?
00943 backgroundColor.name() : "transparent");
00944 }