lib Library API Documentation

koparaglayout.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #include "koparaglayout.h"
00021 #include "korichtext.h"
00022 #include "koparagcounter.h"
00023 #include "kostyle.h"
00024 #include <qdom.h>
00025 #include <kglobal.h>
00026 #include <klocale.h>
00027 #include <kdebug.h>
00028 
00029 QString* KoParagLayout::shadowCssCompat = 0L;
00030 
00031 // Create a default KoParagLayout.
00032 KoParagLayout::KoParagLayout()
00033 {
00034     initialise();
00035 }
00036 
00037 void KoParagLayout::operator=( const KoParagLayout &layout )
00038 {
00039     alignment = layout.alignment;
00040     for ( int i = 0 ; i < 5 ; ++i )
00041         margins[i] = layout.margins[i];
00042     pageBreaking = layout.pageBreaking;
00043     leftBorder = layout.leftBorder;
00044     rightBorder = layout.rightBorder;
00045     topBorder = layout.topBorder;
00046     bottomBorder = layout.bottomBorder;
00047     if ( layout.counter )
00048         counter = new KoParagCounter( *layout.counter );
00049     else
00050         counter = 0L;
00051     lineSpacing = layout.lineSpacing;
00052     lineSpacingType = layout.lineSpacingType;
00053     style = layout.style;
00054     direction = layout.direction;
00055     setTabList( layout.tabList() );
00056 }
00057 
00058 int KoParagLayout::compare( const KoParagLayout & layout ) const
00059 {
00060     int flags = 0;
00061     if ( alignment != layout.alignment )
00062         flags |= Alignment;
00063     for ( int i = 0 ; i < 5 ; ++i )
00064         if ( margins[i] != layout.margins[i] )
00065         {
00066             flags |= Margins;
00067             break;
00068         }
00069     if ( pageBreaking != layout.pageBreaking )
00070         flags |= PageBreaking;
00071     if ( leftBorder != layout.leftBorder
00072          || rightBorder != layout.rightBorder
00073          || topBorder != layout.topBorder
00074          || bottomBorder != layout.bottomBorder )
00075         flags |= Borders;
00076 
00077     if ( layout.counter )
00078     {
00079         if ( counter )
00080         {
00081             if ( ! ( *layout.counter == *counter ) )
00082                 flags |= BulletNumber;
00083         } else
00084             if ( layout.counter->numbering() != KoParagCounter::NUM_NONE )
00085                 flags |= BulletNumber;
00086     }
00087     else
00088         if ( counter && counter->numbering() != KoParagCounter::NUM_NONE )
00089             flags |= BulletNumber;
00090 
00091     if ( lineSpacing != layout.lineSpacing
00092         || lineSpacingType != layout.lineSpacingType )
00093         flags |= LineSpacing;
00094     //if ( style != layout.style )
00095     //    flags |= Style;
00096     if ( m_tabList != layout.m_tabList )
00097         flags |= Tabulator;
00098 
00099     // This method is used for the GUI stuff only, so we don't have a flag
00100     // for the Direction value.
00101     return flags;
00102 }
00103 
00104 void KoParagLayout::initialise()
00105 {
00106     alignment = Qt::AlignAuto;
00107     for ( int i = 0 ; i < 5 ; ++i ) // use memset ?
00108         margins[i] = 0;
00109     lineSpacingType = LS_SINGLE;
00110     lineSpacing = 0;
00111     counter = 0L;
00112     leftBorder.setPenWidth( 0);
00113     rightBorder.setPenWidth( 0);
00114     topBorder.setPenWidth( 0);
00115     bottomBorder.setPenWidth( 0);
00116     pageBreaking = 0;
00117     style = 0L;
00118     direction = QChar::DirON;
00119     m_tabList.clear();
00120 }
00121 
00122 KoParagLayout::~KoParagLayout()
00123 {
00124     delete counter;
00125 }
00126 
00127 void KoParagLayout::loadParagLayout( KoParagLayout& layout, const QDomElement& parentElem, int docVersion )
00128 {
00129     // layout is an input and output parameter
00130     // It can have been initialized already, e.g. by copying from a style
00131     // (we don't do that anymore though).
00132 
00133     // Load the paragraph tabs - we load into a clean list, not mixing with those already in "layout"
00134     // We can't apply the 'default comes from the style' in this case, because
00135     // there is no way to differentiate between "I want no tabs in the parag"
00136     // and "use default from style".
00137     KoTabulatorList tabList;
00138     QDomElement element = parentElem.firstChild().toElement();
00139     for ( ; !element.isNull() ; element = element.nextSibling().toElement() )
00140     {
00141         if ( element.tagName() == "TABULATOR" )
00142         {
00143             KoTabulator tab;
00144             tab.type = static_cast<KoTabulators>( KoStyle::getAttribute( element, "type", T_LEFT ) );
00145             tab.ptPos = KoStyle::getAttribute( element, "ptpos", 0.0 );
00146             tab.filling = static_cast<KoTabulatorFilling>( KoStyle::getAttribute( element, "filling", TF_BLANK ) );
00147             tab.ptWidth = KoStyle::getAttribute( element, "width", 0.5 );
00148             QString alignCharStr = element.attribute("alignchar");
00149             if ( alignCharStr.isEmpty() )
00150                 tab.alignChar = KGlobal::locale()->decimalSymbol()[0];
00151             else
00152                 tab.alignChar = alignCharStr[0];
00153             tabList.append( tab );
00154         }
00155     }
00156     qHeapSort( tabList );
00157     layout.setTabList( tabList );
00158     layout.alignment = Qt::AlignAuto;
00159     element = parentElem.namedItem( "FLOW" ).toElement(); // Flow is what is now called alignment internally
00160     if ( !element.isNull() )
00161     {
00162         QString flow = element.attribute( "align" ); // KWord-1.0 DTD
00163         if ( !flow.isEmpty() )
00164         {
00165             layout.alignment = flow=="right" ? Qt::AlignRight :
00166                          flow=="center" ? Qt::AlignHCenter :
00167                          flow=="justify" ? Qt::AlignJustify :
00168                          flow=="left" ? Qt::AlignLeft : Qt::AlignAuto;
00169 
00170             QString dir = element.attribute( "dir" ); // KWord-1.2
00171             if ( !dir.isEmpty() ) {
00172                 if ( dir == "L" )
00173                     layout.direction = QChar::DirL;
00174                 else if ( dir == "R" )
00175                     layout.direction = QChar::DirR;
00176                 else
00177                     kdWarning() << "Unexpected value for paragraph direction: " << dir << endl;
00178             }
00179         } else {
00180             flow = element.attribute( "value" ); // KWord-0.8
00181             static const int flow2align[] = { Qt::AlignAuto, Qt::AlignRight, Qt::AlignHCenter, Qt::AlignJustify };
00182             if ( !flow.isEmpty() && flow.toInt() < 4 )
00183                 layout.alignment = flow2align[flow.toInt()];
00184         }
00185     }
00186 
00187     if ( docVersion < 2 )
00188     {
00189         element = parentElem.namedItem( "OHEAD" ).toElement(); // used by KWord-0.8
00190         if ( !element.isNull() )
00191             layout.margins[QStyleSheetItem::MarginTop] = KoStyle::getAttribute( element, "pt", 0.0 );
00192 
00193         element = parentElem.namedItem( "OFOOT" ).toElement(); // used by KWord-0.8
00194         if ( !element.isNull() )
00195             layout.margins[QStyleSheetItem::MarginBottom] = KoStyle::getAttribute( element, "pt", 0.0 );
00196 
00197         element = parentElem.namedItem( "IFIRST" ).toElement(); // used by KWord-0.8
00198         if ( !element.isNull() )
00199             layout.margins[QStyleSheetItem::MarginFirstLine] = KoStyle::getAttribute( element, "pt", 0.0 );
00200 
00201         element = parentElem.namedItem( "ILEFT" ).toElement(); // used by KWord-0.8
00202         if ( !element.isNull() )
00203             layout.margins[QStyleSheetItem::MarginLeft] = KoStyle::getAttribute( element, "pt", 0.0 );
00204     }
00205 
00206     // KWord-1.0 DTD
00207     element = parentElem.namedItem( "INDENTS" ).toElement();
00208     if ( !element.isNull() )
00209     {
00210         layout.margins[QStyleSheetItem::MarginFirstLine] = KoStyle::getAttribute( element, "first", 0.0 );
00211         layout.margins[QStyleSheetItem::MarginLeft] = KoStyle::getAttribute( element, "left", 0.0 );
00212         layout.margins[QStyleSheetItem::MarginRight] = KoStyle::getAttribute( element, "right", 0.0 );
00213     }
00214     element = parentElem.namedItem( "OFFSETS" ).toElement();
00215     if ( !element.isNull() )
00216     {
00217         layout.margins[QStyleSheetItem::MarginTop] = KoStyle::getAttribute( element, "before", 0.0 );
00218         layout.margins[QStyleSheetItem::MarginBottom] = KoStyle::getAttribute( element, "after", 0.0 );
00219     }
00220 
00221     if ( docVersion < 2 )
00222     {
00223         element = parentElem.namedItem( "LINESPACE" ).toElement(); // used by KWord-0.8
00224         if ( !element.isNull() )
00225         {
00226             layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
00227             layout.lineSpacing = KoStyle::getAttribute( element, "pt", 0.0 );
00228         }
00229     }
00230 
00231     element = parentElem.namedItem( "LINESPACING" ).toElement(); // KWord-1.0 DTD
00232     if ( !element.isNull() )
00233     {
00234         //compatibility with koffice 1.1
00235         if ( element.hasAttribute( "value" ))
00236         {
00237             QString value = element.attribute( "value" );
00238             if ( value == "oneandhalf" )
00239             {
00240                 layout.lineSpacingType = KoParagLayout::LS_ONEANDHALF;
00241                 layout.lineSpacing = 0;
00242             }
00243             else if ( value == "double" )
00244             {
00245                 layout.lineSpacingType = KoParagLayout::LS_DOUBLE;
00246                 layout.lineSpacing = 0;
00247             }
00248             else
00249             {
00250                 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
00251                 layout.lineSpacing = value.toDouble();
00252             }
00253         }
00254         else
00255         {
00256             QString type = element.attribute( "type" );
00257             if ( type == "oneandhalf" )
00258             {
00259                 layout.lineSpacingType = KoParagLayout::LS_ONEANDHALF;
00260                 layout.lineSpacing = 0;
00261             }
00262             else if ( type == "double" )
00263             {
00264                 layout.lineSpacingType = KoParagLayout::LS_DOUBLE;
00265                 layout.lineSpacing = 0;
00266             }
00267             else if ( type == "custom" )
00268             {
00269                 layout.lineSpacingType = KoParagLayout::LS_CUSTOM;
00270                 layout.lineSpacing = element.attribute( "spacingvalue" ).toDouble();
00271             }
00272             else if ( type == "atleast" )
00273             {
00274                 layout.lineSpacingType = KoParagLayout::LS_AT_LEAST;
00275                 layout.lineSpacing = element.attribute( "spacingvalue" ).toDouble();
00276             }
00277             else if ( type == "multiple" )
00278             {
00279                 layout.lineSpacingType = KoParagLayout::LS_MULTIPLE;
00280                 layout.lineSpacing = element.attribute( "spacingvalue" ).toDouble();
00281             }
00282             else if ( type == "fixed" )
00283             {
00284                 layout.lineSpacingType = KoParagLayout::LS_FIXED;
00285                 layout.lineSpacing = element.attribute( "spacingvalue" ).toDouble();
00286             }
00287             else if ( type == "single" ) // not used; just in case future versions use it.
00288                 layout.lineSpacingType = KoParagLayout::LS_SINGLE;
00289         }
00290     }
00291 
00292     int pageBreaking = 0;
00293     element = parentElem.namedItem( "PAGEBREAKING" ).toElement();
00294     if ( !element.isNull() )
00295     {
00296         if ( element.attribute( "linesTogether" ) == "true" )
00297             pageBreaking |= KoParagLayout::KeepLinesTogether;
00298         if ( element.attribute( "hardFrameBreak" ) == "true" )
00299             pageBreaking |= KoParagLayout::HardFrameBreakBefore;
00300         if ( element.attribute( "hardFrameBreakAfter" ) == "true" )
00301             pageBreaking |= KoParagLayout::HardFrameBreakAfter;
00302     }
00303     if ( docVersion < 2 )
00304     {
00305         element = parentElem.namedItem( "HARDBRK" ).toElement(); // KWord-0.8
00306         if ( !element.isNull() )
00307             pageBreaking |= KoParagLayout::HardFrameBreakBefore;
00308     }
00309     layout.pageBreaking = pageBreaking;
00310 
00311     element = parentElem.namedItem( "LEFTBORDER" ).toElement();
00312     if ( !element.isNull() )
00313         layout.leftBorder = KoBorder::loadBorder( element );
00314     else
00315         layout.leftBorder.setPenWidth(0);
00316 
00317     element = parentElem.namedItem( "RIGHTBORDER" ).toElement();
00318     if ( !element.isNull() )
00319         layout.rightBorder = KoBorder::loadBorder( element );
00320     else
00321         layout.rightBorder.setPenWidth(0);
00322 
00323     element = parentElem.namedItem( "TOPBORDER" ).toElement();
00324     if ( !element.isNull() )
00325         layout.topBorder = KoBorder::loadBorder( element );
00326     else
00327         layout.topBorder.setPenWidth(0);
00328 
00329     element = parentElem.namedItem( "BOTTOMBORDER" ).toElement();
00330     if ( !element.isNull() )
00331         layout.bottomBorder = KoBorder::loadBorder( element );
00332     else
00333         layout.bottomBorder.setPenWidth(0);
00334 
00335     element = parentElem.namedItem( "COUNTER" ).toElement();
00336     if ( !element.isNull() )
00337     {
00338         layout.counter = new KoParagCounter;
00339         layout.counter->load( element );
00340     }
00341 
00342     // Compatibility with KOffice-1.2
00343     element = parentElem.namedItem( "SHADOW" ).toElement();
00344     if ( !element.isNull() && element.hasAttribute("direction") )
00345     {
00346         int shadowDistance = element.attribute("distance").toInt();
00347         int shadowDirection = element.attribute("direction").toInt();
00348         QColor shadowColor;
00349         if ( element.hasAttribute("red") )
00350         {
00351             int r = element.attribute("red").toInt();
00352             int g = element.attribute("green").toInt();
00353             int b = element.attribute("blue").toInt();
00354             shadowColor.setRgb( r, g, b );
00355         }
00356         int distanceX = 0;
00357         int distanceY = 0;
00358         switch ( shadowDirection )
00359         {
00360         case 1: // KoParagLayout::SD_LEFT_UP:
00361         case 2: // KoParagLayout::SD_UP:
00362         case 3: // KoParagLayout::SD_RIGHT_UP:
00363             distanceX = - shadowDistance;
00364         case 7: // KoParagLayout::SD_LEFT_BOTTOM:
00365         case 6: // KoParagLayout::SD_BOTTOM:
00366         case 5: // KoParagLayout::SD_RIGHT_BOTTOM:
00367             distanceX = shadowDistance;
00368         }
00369         switch ( shadowDirection )
00370         {
00371         case 7: // KoParagLayout::SD_LEFT_BOTTOM:
00372         case 8: // KoParagLayout::SD_LEFT:
00373         case 1: //KoParagLayout::SD_LEFT_UP:
00374             distanceY = - shadowDistance;
00375         case 3: // KoParagLayout::SD_RIGHT_UP:
00376         case 4: // KoParagLayout::SD_RIGHT:
00377         case 5: // KoParagLayout::SD_RIGHT_BOTTOM:
00378             distanceY = shadowDistance;
00379         }
00380         if ( !shadowCssCompat )
00381             shadowCssCompat = new QString;
00382         *shadowCssCompat = KoTextFormat::shadowAsCss( distanceX, distanceY, shadowColor );
00383         kdDebug(32500) << "setting shadow compat to " << ( *shadowCssCompat ) << endl;
00384     }
00385     else
00386     {
00387         delete shadowCssCompat;
00388         shadowCssCompat = 0L;
00389     }
00390 }
00391 
00392 void KoParagLayout::saveParagLayout( QDomElement & parentElem, int alignment ) const
00393 {
00394     const KoParagLayout& layout = *this; // code moved from somewhere else;)
00395     QDomDocument doc = parentElem.ownerDocument();
00396     QDomElement element = doc.createElement( "NAME" );
00397     parentElem.appendChild( element );
00398     if ( layout.style )
00399         element.setAttribute( "value", layout.style->name() );
00400     //else
00401     //    kdWarning() << "KoParagLayout::saveParagLayout: style==0L!" << endl;
00402 
00403     element = doc.createElement( "FLOW" );
00404     parentElem.appendChild( element );
00405 
00406     element.setAttribute( "align", alignment==Qt::AlignRight ? "right" :
00407                           alignment==Qt::AlignHCenter ? "center" :
00408                           alignment==Qt::AlignJustify ? "justify" :
00409                           alignment==Qt::AlignAuto ? "auto" : "left" ); // Note: styles can have AlignAuto. Not paragraphs.
00410 
00411     if ( static_cast<QChar::Direction>(layout.direction) == QChar::DirR )
00412         element.setAttribute( "dir", "R" );
00413     else
00414     if ( static_cast<QChar::Direction>(layout.direction) == QChar::DirL )
00415             element.setAttribute( "dir", "L" );
00416 
00417     if ( layout.margins[QStyleSheetItem::MarginFirstLine] != 0 ||
00418          layout.margins[QStyleSheetItem::MarginLeft] != 0 ||
00419          layout.margins[QStyleSheetItem::MarginRight] != 0 )
00420     {
00421         element = doc.createElement( "INDENTS" );
00422         parentElem.appendChild( element );
00423         if ( layout.margins[QStyleSheetItem::MarginFirstLine] != 0 )
00424             element.setAttribute( "first", layout.margins[QStyleSheetItem::MarginFirstLine] );
00425         if ( layout.margins[QStyleSheetItem::MarginLeft] != 0 )
00426             element.setAttribute( "left", layout.margins[QStyleSheetItem::MarginLeft] );
00427         if ( layout.margins[QStyleSheetItem::MarginRight] != 0 )
00428             element.setAttribute( "right", layout.margins[QStyleSheetItem::MarginRight] );
00429     }
00430 
00431     if ( layout.margins[QStyleSheetItem::MarginTop] != 0 ||
00432          layout.margins[QStyleSheetItem::MarginBottom] != 0 )
00433     {
00434         element = doc.createElement( "OFFSETS" );
00435         parentElem.appendChild( element );
00436         if ( layout.margins[QStyleSheetItem::MarginTop] != 0 )
00437             element.setAttribute( "before", layout.margins[QStyleSheetItem::MarginTop] );
00438         if ( layout.margins[QStyleSheetItem::MarginBottom] != 0 )
00439             element.setAttribute( "after", layout.margins[QStyleSheetItem::MarginBottom] );
00440     }
00441     if ( layout.lineSpacingType != LS_SINGLE )
00442     {
00443         element = doc.createElement( "LINESPACING" );
00444         parentElem.appendChild( element );
00445         if ( layout.lineSpacingType == KoParagLayout::LS_ONEANDHALF )  {
00446             element.setAttribute( "type", "oneandhalf" );
00447             element.setAttribute( "value", "oneandhalf" ); //compatibility with koffice 1.2
00448         }
00449         else if ( layout.lineSpacingType == KoParagLayout::LS_DOUBLE ) {
00450             element.setAttribute( "type", "double" );
00451             element.setAttribute( "value", "double" ); //compatibility with koffice 1.2
00452         }
00453         else if ( layout.lineSpacingType == KoParagLayout::LS_CUSTOM )
00454         {
00455             element.setAttribute( "type", "custom" );
00456             element.setAttribute( "spacingvalue", layout.lineSpacing);
00457             element.setAttribute( "value", layout.lineSpacing ); //compatibility with koffice 1.2
00458         }
00459         else if ( layout.lineSpacingType == KoParagLayout::LS_AT_LEAST )
00460         {
00461             element.setAttribute( "type", "atleast" );
00462             element.setAttribute( "spacingvalue", layout.lineSpacing);
00463         }
00464         else if ( layout.lineSpacingType == KoParagLayout::LS_MULTIPLE )
00465         {
00466             element.setAttribute( "type", "multiple" );
00467             element.setAttribute( "spacingvalue", layout.lineSpacing);
00468         }
00469         else if ( layout.lineSpacingType == KoParagLayout::LS_FIXED )
00470         {
00471             element.setAttribute( "type", "fixed" );
00472             element.setAttribute( "spacingvalue", layout.lineSpacing);
00473         }
00474         else
00475             kdDebug()<<" error in lineSpacing Type\n";
00476     }
00477 
00478     if ( layout.pageBreaking != 0 )
00479     {
00480         element = doc.createElement( "PAGEBREAKING" );
00481         parentElem.appendChild( element );
00482         if ( layout.pageBreaking & KoParagLayout::KeepLinesTogether )
00483             element.setAttribute( "linesTogether",  "true" );
00484         if ( layout.pageBreaking & KoParagLayout::HardFrameBreakBefore )
00485             element.setAttribute( "hardFrameBreak", "true" );
00486         if ( layout.pageBreaking & KoParagLayout::HardFrameBreakAfter )
00487             element.setAttribute( "hardFrameBreakAfter", "true" );
00488     }
00489 
00490     if ( layout.leftBorder.penWidth() > 0 )
00491     {
00492         element = doc.createElement( "LEFTBORDER" );
00493         parentElem.appendChild( element );
00494         layout.leftBorder.save( element );
00495     }
00496     if ( layout.rightBorder.penWidth() > 0 )
00497     {
00498         element = doc.createElement( "RIGHTBORDER" );
00499         parentElem.appendChild( element );
00500         layout.rightBorder.save( element );
00501     }
00502     if ( layout.topBorder.penWidth() > 0 )
00503     {
00504         element = doc.createElement( "TOPBORDER" );
00505         parentElem.appendChild( element );
00506         layout.topBorder.save( element );
00507     }
00508     if ( layout.bottomBorder.penWidth() > 0 )
00509     {
00510         element = doc.createElement( "BOTTOMBORDER" );
00511         parentElem.appendChild( element );
00512         layout.bottomBorder.save( element );
00513     }
00514     if ( layout.counter && layout.counter->numbering() != KoParagCounter::NUM_NONE )
00515     {
00516         element = doc.createElement( "COUNTER" );
00517         parentElem.appendChild( element );
00518         if ( layout.counter )
00519             layout.counter->save( element );
00520     }
00521 
00522     KoTabulatorList tabList = layout.tabList();
00523     KoTabulatorList::ConstIterator it = tabList.begin();
00524     for ( ; it != tabList.end() ; it++ )
00525     {
00526         element = doc.createElement( "TABULATOR" );
00527         parentElem.appendChild( element );
00528         element.setAttribute( "type", (*it).type );
00529         element.setAttribute( "ptpos", (*it).ptPos );
00530         element.setAttribute( "filling", (*it).filling );
00531         element.setAttribute( "width", (*it).ptWidth );
00532         if ( !(*it).alignChar.isNull() )
00533           element.setAttribute( "alignchar", QString((*it).alignChar) );
00534     }
00535 }
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Mar 20 14:25:26 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003