kword

KWFrame.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999, 2000 Reginald Stadlbauer <reggie@kde.org>
00003    Copyright (C) 2000-2006 David Faure <faure@kde.org>
00004    Copyright (C) 2005 Thomas Zander <zander@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "KWFrame.h"
00023 #include "KWFrameSet.h"
00024 #include "KWFrameList.h"
00025 #include "KWDocument.h"
00026 #include "KWPageManager.h"
00027 #include "KWTextFrameSet.h"
00028 #include "KWViewMode.h"
00029 #include "KWCanvas.h"
00030 
00031 #include <KoOasisContext.h>
00032 #include <KoXmlNS.h>
00033 #include <KoXmlWriter.h>
00034 #include <KoStyleStack.h>
00035 
00036 #include <kcommand.h>
00037 #include <kdebug.h>
00038 
00039 #include <float.h> // for DBL_DIG
00040 
00041 //#define DEBUG_DRAW
00042 
00043 /******************************************************************/
00044 /* Class: ZOrderedFrameList                                       */
00045 /******************************************************************/
00046 
00047 int ZOrderedFrameList::compareItems(QPtrCollection::Item a, QPtrCollection::Item b)
00048 {
00049     int za = ((KWFrame *)a)->zOrder();
00050     int zb = ((KWFrame *)b)->zOrder();
00051     if (za == zb) return 0;
00052     if (za < zb) return -1;
00053     return 1;
00054 }
00055 
00056 
00057 /******************************************************************/
00058 /* Class: KWFrame                                                 */
00059 /******************************************************************/
00060 
00061 KWFrame::KWFrame(KWFrame * frame)
00062 {
00063     m_runAround = RA_NO;
00064     //kdDebug(32001) << "KWFrame::KWFrame this=" << this << " frame=" << frame << endl;
00065     copySettings( frame );
00066     m_minFrameHeight=0;
00067     m_frameStack = 0; // lazy initialisation.
00068 }
00069 
00070 KWFrame::KWFrame(KWFrameSet *fs, double left, double top, double width, double height, RunAround ra )
00071     : KoRect( left, top, width, height ),
00072       // Initialize member vars here. This ensures they are all initialized, since it's
00073       // easier to compare this list with the member vars list (compiler ensures order).
00074       m_sheetSide( AnySide ),
00075       m_runAround( ra ),
00076       m_runAroundSide( RA_BIGGEST ),
00077       m_frameBehavior( AutoExtendFrame ),
00078       m_newFrameBehavior( ( fs && fs->type() == FT_TEXT ) ? Reconnect : NoFollowup ),
00079       m_bCopy( false ),
00080       m_drawFootNoteLine( false ),
00081       m_runAroundLeft( 1.0 ),
00082       m_runAroundRight( 1.0 ),
00083       m_runAroundTop( 1.0 ),
00084       m_runAroundBottom( 1.0 ),
00085       m_paddingLeft( 0 ),
00086       m_paddingRight( 0 ),
00087       m_paddingTop( 0 ),
00088       m_paddingBottom( 0 ),
00089       m_minFrameHeight( 0 ),
00090       m_internalY( 0 ),
00091       m_zOrder( 0 ),
00092       m_backgroundColor( (fs && (fs->type() == FT_PICTURE || fs->type() == FT_PART)) ? QBrush( QColor(), Qt::NoBrush) : QBrush( QColor() ) ), // valid brush with invalid color ( default )
00093       m_borderLeft( QColor(), KoBorder::SOLID, 0 ),
00094       m_borderRight( QColor(), KoBorder::SOLID, 0 ),
00095       m_borderTop( QColor(), KoBorder::SOLID, 0 ),
00096       m_borderBottom( QColor(), KoBorder::SOLID, 0 ),
00097       m_frameSet( fs )
00098 {
00099     //kdDebug(32001) << "KWFrame::KWFrame " << this << " left=" << left << " top=" << top << endl;
00100     m_frameStack = 0; // lazy initialisation.
00101 }
00102 
00103 KWFrame::~KWFrame()
00104 {
00105     //kdDebug(32001) << "KWFrame::~KWFrame " << this << endl;
00106     delete m_frameStack;
00107     m_frameStack = 0;
00108 }
00109 
00110 void KWFrame::setBackgroundColor( const QBrush &color )
00111 {
00112     m_backgroundColor = color;
00113 }
00114 
00115 
00116 int KWFrame::pageNumber() const
00117 {
00118     Q_ASSERT( m_frameSet );
00119     if( !m_frameSet ) {
00120         kdDebug() << k_funcinfo << this << " has no frameset!" << endl;
00121         return 0;
00122     }
00123     if( !m_frameSet->pageManager() ) {
00124         kdWarning() << k_funcinfo << this << " is not a frame that is in use; misses a pageManager!" << endl;
00125         return -1;
00126     }
00127     return frameSet()->pageManager()->pageNumber(this);
00128 }
00129 
00130 int KWFrame::pageNumber( KWDocument* doc ) const
00131 {
00132     return doc->pageManager()->pageNumber(this);
00133 }
00134 
00135 KWFrame *KWFrame::getCopy() {
00136     /* returns a deep copy of self */
00137     return new KWFrame(this);
00138 }
00139 
00140 void KWFrame::copySettings(KWFrame *frm)
00141 {
00142     setFrameSet( frm->frameSet() ); // do this first in case of debug output in the methods below
00143     setRect(frm->x(), frm->y(), frm->width(), frm->height());
00144     // Keep order identical as member var order (and init in ctor)
00145     setSheetSide(frm->sheetSide());
00146     setRunAround(frm->runAround());
00147     setRunAroundSide(frm->runAroundSide());
00148     setFrameBehavior(frm->frameBehavior());
00149     setNewFrameBehavior(frm->newFrameBehavior());
00150     setRunAroundGap(frm->runAroundLeft(), frm->runAroundRight(), frm->runAroundTop(), frm->runAroundBottom());
00151     setPaddingLeft(frm->paddingLeft());
00152     setPaddingRight(frm->paddingRight());
00153     setPaddingTop(frm->paddingTop());
00154     setPaddingBottom(frm->paddingBottom());
00155     setMinimumFrameHeight(frm->minimumFrameHeight());
00156     m_internalY = 0; // internal Y is recalculated
00157     setZOrder(frm->zOrder());
00158     setCopy(frm->isCopy());
00159     m_drawFootNoteLine = false; // recalculated
00160     setBackgroundColor( frm->backgroundColor() );
00161     setLeftBorder(frm->leftBorder());
00162     setRightBorder(frm->rightBorder());
00163     setTopBorder(frm->topBorder());
00164     setBottomBorder(frm->bottomBorder());
00165 }
00166 
00167 void KWFrame::frameBordersChanged() {
00168     if (frameSet()->isFloating())
00169         frameSet()->anchorFrameset()->invalidate();
00170 }
00171 
00172 
00173 void KWFrame::updateRulerHandles(){
00174 // TODO
00175 #if 0
00176     if(! isSelected())
00177     {
00178         KWDocument *doc = frameSet()->kWordDocument();
00179         if(doc)
00180             doc->updateRulerFrameStartEnd();
00181     }
00182 #endif
00183 }
00184 
00185 QRect KWFrame::outerRect( KWViewMode* viewMode ) const
00186 {
00187     KWDocument *doc = m_frameSet->kWordDocument();
00188     QRect outerRect( doc->zoomRect( *this ) );
00189     if ( viewMode && !m_frameSet->groupmanager() ) {
00190         int minBorder = viewMode->drawFrameBorders() ? 1 : 0;
00191         KWFrame* settingsFrame = m_frameSet->settingsFrame( this );
00192         outerRect.rLeft() -= KoBorder::zoomWidthX( settingsFrame->leftBorder().width(), doc, minBorder );
00193         outerRect.rTop() -= KoBorder::zoomWidthY( settingsFrame->topBorder().width(), doc, minBorder );
00194         outerRect.rRight() += KoBorder::zoomWidthX( settingsFrame->rightBorder().width(), doc, minBorder );
00195         outerRect.rBottom() += KoBorder::zoomWidthY( settingsFrame->bottomBorder().width(), doc, minBorder );
00196     }
00197     return outerRect;
00198 }
00199 
00200 KoRect KWFrame::outerKoRect() const
00201 {
00202     KoRect outerRect = *this;
00203     KWDocument *doc = m_frameSet->kWordDocument();
00204     KWFrame* settingsFrame = m_frameSet->settingsFrame( this );
00205     outerRect.rLeft() -= KoBorder::zoomWidthX( settingsFrame->leftBorder().width(), doc, 1 ) / doc->zoomedResolutionX();
00206     outerRect.rTop() -= KoBorder::zoomWidthY( settingsFrame->topBorder().width(), doc, 1 ) / doc->zoomedResolutionY();
00207     outerRect.rRight() += KoBorder::zoomWidthX( settingsFrame->rightBorder().width(), doc, 1 ) / doc->zoomedResolutionX();
00208     outerRect.rBottom() += KoBorder::zoomWidthY( settingsFrame->bottomBorder().width(), doc, 1 ) / doc->zoomedResolutionY();
00209     return outerRect;
00210 }
00211 
00212 KoRect KWFrame::runAroundRect() const
00213 {
00214     KoRect raRect = outerKoRect();
00215     raRect.rLeft() -= m_runAroundLeft;
00216     raRect.rRight() += m_runAroundRight;
00217     raRect.rTop() -= m_runAroundTop;
00218     raRect.rBottom() += m_runAroundBottom;
00219     return raRect;
00220 }
00221 
00222 void KWFrame::save( QDomElement &frameElem )
00223 {
00224     // setAttribute( double ) uses a default precision of 6, and this seems
00225     // to be 6 digits, even like '123.123' !
00226     frameElem.setAttribute( "left", QString::number( left(), 'g', DBL_DIG ) );
00227     frameElem.setAttribute( "top", QString::number( top(), 'g', DBL_DIG ) );
00228     frameElem.setAttribute( "right", QString::number( right(), 'g', DBL_DIG ) );
00229     frameElem.setAttribute( "bottom", QString::number( bottom(), 'g', DBL_DIG ) );
00230     if ( minimumFrameHeight() > 0 )
00231         frameElem.setAttribute( "min-height", QString::number( minimumFrameHeight(), 'g', DBL_DIG ) );
00232 
00233     if ( !m_frameSet->isHeaderOrFooter() && !m_frameSet->isMainFrameset() )
00234     {
00235         if(runAround()!=RA_NO)
00236         {
00237             frameElem.setAttribute( "runaround", static_cast<int>( runAround() ) );
00238             if (runAround() == RA_BOUNDINGRECT)
00239             {
00240                 if (runAroundSide()==RA_LEFT)
00241                     frameElem.setAttribute( "runaroundSide", "left" );
00242                 else if (runAroundSide()==RA_RIGHT)
00243                     frameElem.setAttribute( "runaroundSide", "right" );
00244                 else
00245                     frameElem.setAttribute( "runaroundSide", "biggest" );
00246             }
00247         }
00248         if(runAroundLeft()!=0 || runAroundRight()!=0 || runAroundTop()!=0 || runAroundBottom()!=0) {
00249             frameElem.setAttribute( "runaroundLeft", m_runAroundLeft );
00250             frameElem.setAttribute( "runaroundRight", m_runAroundRight );
00251             frameElem.setAttribute( "runaroundTop", m_runAroundTop );
00252             frameElem.setAttribute( "runaroundBottom", m_runAroundBottom );
00253             // The old file format had only one value, keep compat
00254             double runAroundGap = QMAX( QMAX( m_runAroundLeft, m_runAroundRight ), QMAX( m_runAroundTop, m_runAroundBottom ) );
00255             frameElem.setAttribute( "runaroundGap", runAroundGap );
00256         }
00257     }
00258 
00259     if(leftBorder().penWidth()!=0)
00260         frameElem.setAttribute( "lWidth", leftBorder().penWidth() );
00261 
00262     if(leftBorder().color.isValid())
00263     {
00264         frameElem.setAttribute( "lRed", leftBorder().color.red() );
00265         frameElem.setAttribute( "lGreen", leftBorder().color.green() );
00266         frameElem.setAttribute( "lBlue", leftBorder().color.blue() );
00267     }
00268     if(leftBorder().getStyle() != KoBorder::SOLID)
00269         frameElem.setAttribute( "lStyle", static_cast<int>( leftBorder().getStyle()) );
00270 
00271     if(rightBorder().penWidth()!=0)
00272         frameElem.setAttribute( "rWidth", rightBorder().penWidth() );
00273 
00274     if(rightBorder().color.isValid())
00275     {
00276         frameElem.setAttribute( "rRed", rightBorder().color.red() );
00277         frameElem.setAttribute( "rGreen", rightBorder().color.green() );
00278         frameElem.setAttribute( "rBlue", rightBorder().color.blue() );
00279     }
00280     if(rightBorder().getStyle() != KoBorder::SOLID)
00281         frameElem.setAttribute( "rStyle", static_cast<int>( rightBorder().getStyle() ) );
00282 
00283     if(topBorder().penWidth()!=0)
00284         frameElem.setAttribute( "tWidth", topBorder().penWidth() );
00285 
00286     if(topBorder().color.isValid())
00287     {
00288         frameElem.setAttribute( "tRed", topBorder().color.red() );
00289         frameElem.setAttribute( "tGreen", topBorder().color.green() );
00290         frameElem.setAttribute( "tBlue", topBorder().color.blue() );
00291     }
00292     if(topBorder().getStyle() != KoBorder::SOLID)
00293         frameElem.setAttribute( "tStyle", static_cast<int>( topBorder().getStyle() ) );
00294 
00295     if(bottomBorder().penWidth()!=0) {
00296         frameElem.setAttribute( "bWidth", bottomBorder().penWidth() );
00297     }
00298     if(bottomBorder().color.isValid()) {
00299         frameElem.setAttribute( "bRed", bottomBorder().color.red() );
00300         frameElem.setAttribute( "bGreen", bottomBorder().color.green() );
00301         frameElem.setAttribute( "bBlue", bottomBorder().color.blue() );
00302     }
00303     if(bottomBorder().getStyle() != KoBorder::SOLID)
00304         frameElem.setAttribute( "bStyle", static_cast<int>( bottomBorder().getStyle() ) );
00305 
00306     if(backgroundColor().color().isValid())
00307     {
00308         frameElem.setAttribute( "bkRed", backgroundColor().color().red() );
00309         frameElem.setAttribute( "bkGreen", backgroundColor().color().green() );
00310         frameElem.setAttribute( "bkBlue", backgroundColor().color().blue() );
00311         frameElem.setAttribute( "bkStyle", (int)backgroundColor().style ());
00312     }
00313     if(paddingLeft() != 0)
00314         frameElem.setAttribute( "bleftpt", paddingLeft() );
00315 
00316     if(paddingRight()!=0)
00317         frameElem.setAttribute( "brightpt", paddingRight() );
00318 
00319     if(paddingTop()!=0)
00320         frameElem.setAttribute( "btoppt", paddingTop() );
00321 
00322     if(paddingBottom()!=0)
00323         frameElem.setAttribute( "bbottompt", paddingBottom() );
00324 
00325     if(frameBehavior()!=AutoCreateNewFrame)
00326         frameElem.setAttribute( "autoCreateNewFrame", static_cast<int>( frameBehavior()) );
00327 
00328     //if(newFrameBehavior()!=Reconnect) // always save this one, since the default value depends on the type of frame, etc.
00329     frameElem.setAttribute( "newFrameBehavior", static_cast<int>( newFrameBehavior()) );
00330 
00331     //same reason
00332     frameElem.setAttribute( "copy", static_cast<int>( m_bCopy ) );
00333 
00334     if(sheetSide()!= AnySide)
00335         frameElem.setAttribute( "sheetSide", static_cast<int>( sheetSide()) );
00336 
00337     frameElem.setAttribute( "z-index", zOrder() );
00338 }
00339 
00340 void KWFrame::load( QDomElement &frameElem, KWFrameSet* frameSet, int syntaxVersion )
00341 {
00342     m_minFrameHeight = KWDocument::getAttribute( frameElem, "min-height", 0.0 );
00343     m_runAround = static_cast<RunAround>( KWDocument::getAttribute( frameElem, "runaround", RA_NO ) );
00344     QString str = frameElem.attribute( "runaroundSide" );
00345     if ( str == "left" )
00346         m_runAroundSide = RA_LEFT;
00347     else if ( str == "right" )
00348         m_runAroundSide = RA_RIGHT;
00349     else
00350         m_runAroundSide = RA_BIGGEST;
00351 
00352     double runAroundGap = ( frameElem.hasAttribute( "runaroundGap" ) )
00353                           ? frameElem.attribute( "runaroundGap" ).toDouble()
00354                           : frameElem.attribute( "runaGapPT" ).toDouble();
00355     setRunAroundGap( KWDocument::getAttribute( frameElem, "runaroundLeft", runAroundGap ),
00356                      KWDocument::getAttribute( frameElem, "runaroundRight", runAroundGap ),
00357                      KWDocument::getAttribute( frameElem, "runaroundTop", runAroundGap ),
00358                      KWDocument::getAttribute( frameElem, "runaroundBottom", runAroundGap ) );
00359 
00360     m_sheetSide = static_cast<SheetSide>( KWDocument::getAttribute( frameElem, "sheetSide", AnySide ) );
00361     m_frameBehavior = static_cast<FrameBehavior>( KWDocument::getAttribute( frameElem, "autoCreateNewFrame", AutoCreateNewFrame ) );
00362     // Old documents had no "NewFrameBehavior" for footers/headers -> default to Copy.
00363     NewFrameBehavior defaultValue = frameSet->isHeaderOrFooter() ? Copy : Reconnect;
00364     // for old document we used the British spelling (newFrameBehaviour), so this is for backwards compatibility.
00365     defaultValue = static_cast<NewFrameBehavior>( KWDocument::getAttribute( frameElem, "newFrameBehaviour", defaultValue ) );
00366     m_newFrameBehavior = static_cast<NewFrameBehavior>( KWDocument::getAttribute( frameElem, "newFrameBehavior", defaultValue ) );
00367     if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet
00368         m_newFrameBehavior = NoFollowup;
00369 
00370     KoBorder l, r, t, b;
00371     l.setPenWidth( KWDocument::getAttribute( frameElem, "lWidth", 0.0 ));
00372     r.setPenWidth(KWDocument::getAttribute( frameElem, "rWidth", 0.0 ));
00373     t.setPenWidth(KWDocument::getAttribute( frameElem, "tWidth", 0.0 ));
00374     b.setPenWidth(KWDocument::getAttribute( frameElem, "bWidth", 0.0 ));
00375     if ( frameElem.hasAttribute("lRed") )
00376         l.color.setRgb(
00377             KWDocument::getAttribute( frameElem, "lRed", 0 ),
00378             KWDocument::getAttribute( frameElem, "lGreen", 0 ),
00379             KWDocument::getAttribute( frameElem, "lBlue", 0 ) );
00380     if ( frameElem.hasAttribute("rRed") )
00381         r.color.setRgb(
00382             KWDocument::getAttribute( frameElem, "rRed", 0 ),
00383             KWDocument::getAttribute( frameElem, "rGreen", 0 ),
00384             KWDocument::getAttribute( frameElem, "rBlue", 0 ) );
00385     if ( frameElem.hasAttribute("tRed") )
00386         t.color.setRgb(
00387             KWDocument::getAttribute( frameElem, "tRed", 0 ),
00388             KWDocument::getAttribute( frameElem, "tGreen", 0 ),
00389             KWDocument::getAttribute( frameElem, "tBlue", 0 ) );
00390     if ( frameElem.hasAttribute("bRed") )
00391         b.color.setRgb(
00392             KWDocument::getAttribute( frameElem, "bRed", 0 ),
00393             KWDocument::getAttribute( frameElem, "bGreen", 0 ),
00394             KWDocument::getAttribute( frameElem, "bBlue", 0 ) );
00395     l.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "lStyle", KoBorder::SOLID ) ));
00396     r.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "rStyle", KoBorder::SOLID ) ));
00397     t.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "tStyle", KoBorder::SOLID ) ));
00398     b.setStyle( static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "bStyle", KoBorder::SOLID ) ));
00399     QColor c;
00400     if ( frameElem.hasAttribute("bkRed") )
00401         c.setRgb(
00402             KWDocument::getAttribute( frameElem, "bkRed", 0 ),
00403             KWDocument::getAttribute( frameElem, "bkGreen", 0 ),
00404             KWDocument::getAttribute( frameElem, "bkBlue", 0 ) );
00405 
00406     if ( syntaxVersion < 2 ) // Activate old "white border == no border" conversion
00407     {
00408         if(c==l.color && l.penWidth()==1 && l.getStyle()==0 )
00409             l.setPenWidth(0);
00410         if(c==r.color  && r.penWidth()==1 && r.getStyle()==0)
00411             r.setPenWidth(0);
00412         if(c==t.color && t.penWidth()==1 && t.getStyle()==0 )
00413             t.setPenWidth(0);
00414         if(c==b.color && b.penWidth()==1 && b.getStyle()==0 )
00415             b.setPenWidth(0);
00416     }
00417     m_borderLeft = l;
00418     m_borderRight = r;
00419     m_borderTop = t;
00420     m_borderBottom = b;
00421     m_backgroundColor = QBrush( c );
00422 
00423 
00424     if( frameElem.hasAttribute("bkStyle"))
00425         m_backgroundColor.setStyle (static_cast<Qt::BrushStyle>(KWDocument::getAttribute( frameElem, "bkStyle", Qt::SolidPattern )));
00426 
00427     m_paddingLeft = frameElem.attribute( "bleftpt" ).toDouble();
00428     m_paddingRight = frameElem.attribute( "brightpt" ).toDouble();
00429     m_paddingTop = frameElem.attribute( "btoppt" ).toDouble();
00430     m_paddingBottom = frameElem.attribute( "bbottompt" ).toDouble();
00431     m_bCopy = KWDocument::getAttribute( frameElem, "copy", frameSet->isHeaderOrFooter() /* default to true for h/f */ );
00432     m_zOrder = frameElem.attribute( "z-index" ).toInt();
00433 }
00434 
00435 // This is shared with table cells - so, no runaround and newframebehavior etc.
00436 // Only background, borders, padding.
00437 void KWFrame::loadBorderProperties( KoStyleStack& styleStack )
00438 {
00439     // padding. fo:padding for 4 values or padding-left/right/top/bottom
00440     m_paddingLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "left" ) );
00441     m_paddingRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "right" ) );
00442     m_paddingTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "top" ) );
00443     m_paddingBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "bottom" ) );
00444 
00445     // background color (3.11.25)
00446     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color" ) ) {
00447         QString color = styleStack.attributeNS( KoXmlNS::fo, "background-color" );
00448         if ( color == "transparent" )
00449             m_backgroundColor = QBrush( QColor(), Qt::NoBrush );
00450         else
00451         {
00452             m_backgroundColor = QBrush( QColor( color ) /*, brush style is a dead feature, ignored */ );
00453         }
00454     }
00455     // OOo compatibility: it uses background-transparency=100% instead of background-color="transparent"
00456     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-transparency" ) ) {
00457         QString transp = styleStack.attributeNS( KoXmlNS::fo, "background-transparency" );
00458         if ( transp == "100%" )
00459             m_backgroundColor.setStyle( Qt::NoBrush );
00460     }
00461 
00462     // borders (3.11.27)
00463     // can be none/hidden, solid and double. General form is the XSL/FO "width|style|color"
00464     {
00465         m_borderLeft.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "left") );
00466         m_borderRight.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "right") );
00467         m_borderTop.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "top") );
00468         m_borderBottom.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "bottom") );
00469     }
00470     // TODO more refined border spec for double borders (3.11.28)
00471 }
00472 
00473 void KWFrame::loadCommonOasisProperties( KoOasisContext& context, KWFrameSet* frameSet, const char* typeProperties )
00474 {
00475     KoStyleStack& styleStack = context.styleStack();
00476     styleStack.setTypeProperties( typeProperties );
00477 
00478     loadBorderProperties( styleStack );
00479 
00480 #if 0 // not allowed in the current OASIS spec
00481     // margins, i.e. runAroundGap. fo:margin for 4 values or padding-left/right/top/bottom
00482     m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "left" ) );
00483     m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "right" ) );
00484     m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "top" ) );
00485     m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "bottom" ) );
00486 #endif
00487     // margins, i.e. runAroundGap. fo:margin-left/right/top/bottom
00488     m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) );
00489     m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) );
00490     m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) );
00491     m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) );
00492 
00493     // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering
00494     // of existing documents, only editing (and only KWord has this kind of option until now).
00495     const QCString frameBehaviorOnNewPage = styleStack.attributeNS( KoXmlNS::koffice, "frame-behavior-on-new-page" ).latin1();
00496     if ( frameBehaviorOnNewPage == "followup" )
00497         m_newFrameBehavior = Reconnect;
00498     else if ( frameBehaviorOnNewPage == "copy" )
00499         m_newFrameBehavior = Copy;
00500     else if ( frameBehaviorOnNewPage == "none" )
00501         m_newFrameBehavior = NoFollowup;
00502     else { // Defaults for OASIS documents not created by KWord
00503         m_newFrameBehavior = frameSet->isHeaderOrFooter() ? Copy : NoFollowup;
00504         if ( !frameBehaviorOnNewPage.isEmpty() )
00505             kdWarning(32001) << "Unknown value for koffice:frame-behavior-on-new-page: " << frameBehaviorOnNewPage << endl;
00506     }
00507     // Footnotes and endnotes are handled in a special way.
00508     if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet
00509         m_newFrameBehavior = NoFollowup;
00510 
00511     KWFrame::RunAround runAround = KWFrame::RA_BOUNDINGRECT;
00512     KWFrame::RunAroundSide runAroundSide = KWFrame::RA_BIGGEST;
00513     const QCString oowrap = styleStack.attributeNS( KoXmlNS::style, "wrap" ).latin1();
00514     if ( oowrap == "none" )        // 'no wrap' means 'avoid horizontal space'
00515         runAround = KWFrame::RA_SKIP;
00516     else if ( oowrap == "left" )
00517         runAroundSide = KWFrame::RA_LEFT;
00518     else if ( oowrap == "right" )
00519         runAroundSide= KWFrame::RA_RIGHT;
00520     else if ( oowrap == "run-through" )
00521         runAround = KWFrame::RA_NO;
00522     //if ( oowrap == "biggest" ) // OASIS extension
00523     // ->( KWFrame::RA_BOUNDINGRECT, KWFrame::RA_BIGGEST ), already set above
00524     //if ( oowrap == "parallel" || oowrap == "dynamic" )
00525     // dynamic is called "optimal" in the OO GUI. It's different from biggest because it can lead to parallel.
00526     // Those are not supported in KWord, let's use biggest instead
00527     setRunAround( runAround );
00528     setRunAroundSide( runAroundSide );
00529 }
00530 
00531 void KWFrame::startOasisFrame( KoXmlWriter &writer, KoGenStyles& mainStyles, const QString& name, const QString& lastFrameName ) const
00532 {
00533     writer.startElement( "draw:frame" );
00534     writer.addAttribute( "draw:name", name );
00535     writer.addAttribute( "draw:style-name", saveOasisFrameStyle( mainStyles ) );
00536 
00537     if ( !frameSet()->isFloating() )
00538     { // non-inline frame, anchored to page
00539         const int pgNum = pageNumber();
00540         const double yInPage = top() - frameSet()->pageManager()->topOfPage(pgNum);
00541         writer.addAttributePt( "svg:x", left() );
00542         writer.addAttributePt( "svg:y", yInPage );
00543         writer.addAttribute( "text:anchor-type", "page" );
00544         writer.addAttribute( "text:anchor-page-number", pgNum );
00545         writer.addAttribute( "draw:z-index", zOrder() );
00546     }
00547     writer.addAttributePt( "svg:width", width() );
00548     writer.addAttributePt( "svg:height", height() );
00549     if ( isCopy() )
00550         writer.addAttribute( "draw:copy-of", lastFrameName );
00551 }
00552 
00553 // shared between startOasisFrame and table cells.
00554 // Only background, borders, padding.
00555 void KWFrame::saveBorderProperties( KoGenStyle& frameStyle ) const
00556 {
00557     // Background: color and transparency
00558     // OOo seems to use style:background-transparency="100%", but the schema allows background-color=transparent
00559     if ( m_backgroundColor.style() == Qt::NoBrush )
00560         frameStyle.addProperty( "fo:background-color", "transparent" );
00561     else if ( m_backgroundColor.color().isValid() )
00562         frameStyle.addProperty( "fo:background-color", m_backgroundColor.color().name() );
00563 
00564     // Borders
00565     if (  ( m_borderLeft == m_borderRight )
00566           && ( m_borderLeft == m_borderTop )
00567           && ( m_borderLeft == m_borderBottom ) )
00568     {
00569         frameStyle.addProperty( "fo:border", m_borderLeft.saveFoBorder() );
00570     }
00571     else
00572     {
00573         frameStyle.addProperty( "fo:border-left", m_borderLeft.saveFoBorder() );
00574         frameStyle.addProperty( "fo:border-right", m_borderRight.saveFoBorder() );
00575         frameStyle.addProperty( "fo:border-top", m_borderTop.saveFoBorder() );
00576         frameStyle.addProperty( "fo:border-bottom", m_borderBottom.saveFoBorder() );
00577     }
00578 
00579     if ( m_paddingLeft != 0 && ( ( m_paddingLeft == m_paddingRight )
00580                                  && ( m_paddingLeft == m_paddingTop )
00581                                  && ( m_paddingLeft == m_paddingBottom ) ) )
00582         frameStyle.addPropertyPt( "fo:padding", m_paddingLeft );
00583     else
00584     {
00585         if ( m_paddingLeft != 0 )
00586             frameStyle.addPropertyPt( "fo:padding-left", m_paddingLeft );
00587         if ( m_paddingRight != 0 )
00588             frameStyle.addPropertyPt( "fo:padding-right", m_paddingRight );
00589         if ( m_paddingTop != 0 )
00590             frameStyle.addPropertyPt( "fo:padding-top", m_paddingTop );
00591         if ( m_paddingBottom != 0 )
00592             frameStyle.addPropertyPt( "fo:padding-bottom", m_paddingBottom );
00593     }
00594 }
00595 
00596 void KWFrame::saveMarginAttributes( KoXmlWriter &writer ) const
00597 {
00598     if ( m_runAroundLeft != 0 )
00599         writer.addAttributePt( "fo:margin-left", m_runAroundLeft );
00600     if ( m_runAroundRight != 0 )
00601         writer.addAttributePt( "fo:margin-right", m_runAroundRight );
00602     if ( m_runAroundTop != 0 )
00603         writer.addAttributePt( "fo:margin-top", m_runAroundTop );
00604     if ( m_runAroundBottom != 0 )
00605         writer.addAttributePt( "fo:margin-bottom", m_runAroundBottom );
00606 }
00607 
00608 void KWFrame::saveMarginProperties( KoGenStyle& frameStyle ) const
00609 {
00610 #if 0 // not allowed in the current OASIS spec
00611     if ( m_runAroundLeft != 0 && ( ( m_runAroundLeft == m_runAroundRight )
00612                                  && ( m_runAroundLeft == m_runAroundTop )
00613                                  && ( m_runAroundLeft == m_runAroundBottom ) ) )
00614         frameStyle.addPropertyPt( "fo:margin", m_runAroundLeft );
00615     else
00616     {
00617 #endif
00618         if ( m_runAroundLeft != 0 )
00619             frameStyle.addPropertyPt( "fo:margin-left", m_runAroundLeft );
00620         if ( m_runAroundRight != 0 )
00621             frameStyle.addPropertyPt( "fo:margin-right", m_runAroundRight );
00622         if ( m_runAroundTop != 0 )
00623             frameStyle.addPropertyPt( "fo:margin-top", m_runAroundTop );
00624         if ( m_runAroundBottom != 0 )
00625             frameStyle.addPropertyPt( "fo:margin-bottom", m_runAroundBottom );
00626 #if 0 // not allowed in the current OASIS spec
00627     }
00628 #endif
00629 }
00630 
00631 QString KWFrame::saveOasisFrameStyle( KoGenStyles& mainStyles ) const
00632 {
00633     KoGenStyle frameStyle( KWDocument::STYLE_FRAME_AUTO, "graphic" );
00634     QString protect;
00635     if ( frameSet()->protectContent() )
00636         protect = "content";
00637     if ( frameSet()->isProtectSize() ) // ## should be moved for frame
00638     {
00639         if ( !protect.isEmpty() )
00640             protect+=" ";
00641         protect+="size";
00642     }
00643     if ( !protect.isEmpty() )
00644         frameStyle.addProperty( "style:protect", protect );
00645 
00646     if ( !frameSet()->isFloating() )
00647     { // non-inline frame, anchored to page
00648         frameStyle.addProperty( "style:horizontal-rel", "page" );
00649         frameStyle.addProperty( "style:vertical-rel", "page" );
00650         frameStyle.addProperty( "style:horizontal-pos", "from-left" );
00651         frameStyle.addProperty( "style:vertical-pos", "from-top" );
00652     }
00653 
00654     saveBorderProperties( frameStyle );
00655     saveMarginProperties( frameStyle );
00656 
00657     if ( runAround() == KWFrame::RA_SKIP )
00658         frameStyle.addProperty( "style:wrap", "none" );
00659     else if ( runAround() == KWFrame::RA_NO )
00660         frameStyle.addProperty( "style:wrap", "run-through" );
00661     else // RA_BOUNDINGRECT
00662     {
00663         if ( runAroundSide() ==  KWFrame::RA_LEFT )
00664             frameStyle.addProperty( "style:wrap", "left" );
00665         else if ( runAroundSide() == KWFrame::RA_RIGHT )
00666             frameStyle.addProperty( "style:wrap", "right" );
00667         else if ( runAroundSide() == KWFrame::RA_BIGGEST )
00668             frameStyle.addProperty( "style:wrap", "biggest" );
00669     }
00670 
00671     // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering
00672     // of existing documents, only editing (and only KWord has this kind of option until now).
00673     NewFrameBehavior defaultNfb = frameSet()->isHeaderOrFooter() ? Copy : NoFollowup;
00674     if ( m_newFrameBehavior != defaultNfb ) {
00675         const char* value = "none";
00676         if ( m_newFrameBehavior == Reconnect )
00677             value = "followup";
00678         else if ( m_newFrameBehavior == Copy )
00679             value = "copy";
00680         else if ( m_newFrameBehavior == NoFollowup )
00681             value = "none";
00682         frameStyle.addProperty( "koffice:frame-behavior-on-new-page", value );
00683     }
00684 
00685     // The loading code for this one is in kwtextframeset, maybe this should be moved there too
00686     const char* frameBehav = 0;
00687     if ( m_frameBehavior == KWFrame::Ignore )
00688         frameBehav = "clip";
00689     else if ( m_frameBehavior == KWFrame::AutoCreateNewFrame )
00690         frameBehav = "auto-create-new-frame";
00691     // the third case, AutoExtendFrame is handled by min-height
00692     if ( frameBehav )
00693         frameStyle.addProperty( "style:overflow-behavior", frameBehav );
00694 
00695     return mainStyles.lookup( frameStyle, "fr" );
00696 }
00697 
00698 bool KWFrame::frameAtPos( const QPoint& point, bool borderOfFrameOnly) const {
00699     // Forwarded to KWFrameSet to make it virtual
00700     return frameSet()->isFrameAtPos( this, point, borderOfFrameOnly );
00701 }
00702 
00703 KoRect KWFrame::innerRect() const
00704 {
00705     KoRect inner( this->normalize());
00706     inner.moveBy( paddingLeft(), paddingTop() );
00707     inner.setWidth( innerWidth() );
00708     inner.setHeight( innerHeight() );
00709     return inner;
00710 }
00711 
00712 double KWFrame::innerWidth() const
00713 {
00714     return KMAX( 0.0, width() - m_paddingLeft - m_paddingRight );
00715 }
00716 
00717 double KWFrame::innerHeight() const
00718 {
00719     return KMAX( 0.0, height() - m_paddingTop - m_paddingBottom );
00720 }
00721 
00722 void KWFrame::setFramePadding( double left, double top, double right, double bottom)
00723 {
00724     m_paddingLeft = left;
00725     m_paddingTop = top;
00726     m_paddingRight = right;
00727     m_paddingBottom = bottom;
00728 }
00729 
00730 bool KWFrame::compareFrameZOrder(KWFrame *f1, KWFrame *f2)
00731 {
00732     return f1->zOrder() < f2->zOrder();
00733 }
KDE Home | KDE Accessibility Home | Description of Access Keys