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