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