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.01 ), // not 0, since AutoExtendFrame means min-height in odt
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
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     // Background color is now done with fill-color.
00481     // loadBorderProperties loads fo:background-color for compatibility (and for table cells),
00482     // but the correct way for text boxes is draw:fill-color
00483     if ( styleStack.hasAttributeNS( KoXmlNS::draw, "fill-color" ) ) {
00484         QString color = styleStack.attributeNS( KoXmlNS::draw, "fill-color" );
00485         if ( color == "transparent" )
00486             m_backgroundColor = QBrush( QColor(), Qt::NoBrush );
00487         else
00488         {
00489             m_backgroundColor = QBrush( QColor( color ) /*, brush style is a dead feature, ignored */ );
00490         }
00491     }
00492 
00493 #if 0 // not allowed in the current OASIS spec
00494     // margins, i.e. runAroundGap. fo:margin for 4 values or padding-left/right/top/bottom
00495     m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "left" ) );
00496     m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "right" ) );
00497     m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "top" ) );
00498     m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "bottom" ) );
00499 #endif
00500     // margins, i.e. runAroundGap. fo:margin-left/right/top/bottom
00501     m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) );
00502     m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) );
00503     m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) );
00504     m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) );
00505 
00506     // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering
00507     // of existing documents, only editing (and only KWord has this kind of option until now).
00508     const QCString frameBehaviorOnNewPage = styleStack.attributeNS( KoXmlNS::koffice, "frame-behavior-on-new-page" ).latin1();
00509     if ( frameBehaviorOnNewPage == "followup" )
00510         m_newFrameBehavior = Reconnect;
00511     else if ( frameBehaviorOnNewPage == "copy" )
00512         m_newFrameBehavior = Copy;
00513     else if ( frameBehaviorOnNewPage == "none" )
00514         m_newFrameBehavior = NoFollowup;
00515     else { // Defaults for OASIS documents not created by KWord
00516         m_newFrameBehavior = frameSet->isHeaderOrFooter() ? Copy : NoFollowup;
00517         if ( !frameBehaviorOnNewPage.isEmpty() )
00518             kdWarning(32001) << "Unknown value for koffice:frame-behavior-on-new-page: " << frameBehaviorOnNewPage << endl;
00519     }
00520     // Footnotes and endnotes are handled in a special way.
00521     if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet
00522         m_newFrameBehavior = NoFollowup;
00523 
00524     KWFrame::RunAround runAround = KWFrame::RA_BOUNDINGRECT;
00525     KWFrame::RunAroundSide runAroundSide = KWFrame::RA_BIGGEST;
00526     const QCString oowrap = styleStack.attributeNS( KoXmlNS::style, "wrap" ).latin1();
00527     if ( oowrap == "none" )        // 'no wrap' means 'avoid horizontal space'
00528         runAround = KWFrame::RA_SKIP;
00529     else if ( oowrap == "left" )
00530         runAroundSide = KWFrame::RA_LEFT;
00531     else if ( oowrap == "right" )
00532         runAroundSide= KWFrame::RA_RIGHT;
00533     else if ( oowrap == "run-through" )
00534         runAround = KWFrame::RA_NO;
00535     //if ( oowrap == "biggest" ) // OASIS extension
00536     // ->( KWFrame::RA_BOUNDINGRECT, KWFrame::RA_BIGGEST ), already set above
00537     //if ( oowrap == "parallel" || oowrap == "dynamic" )
00538     // dynamic is called "optimal" in the OO GUI. It's different from biggest because it can lead to parallel.
00539     // Those are not supported in KWord, let's use biggest instead
00540     setRunAround( runAround );
00541     setRunAroundSide( runAroundSide );
00542 }
00543 
00544 void KWFrame::startOasisFrame( KoXmlWriter &writer, KoGenStyles& mainStyles, const QString& name, const QString& lastFrameName ) const
00545 {
00546     writer.startElement( "draw:frame" );
00547     writer.addAttribute( "draw:name", name );
00548     writer.addAttribute( "draw:style-name", saveOasisFrameStyle( mainStyles ) );
00549 
00550     if ( !frameSet()->isFloating() )
00551     { // non-inline frame, anchored to page
00552         const int pgNum = pageNumber();
00553         const double yInPage = top() - frameSet()->pageManager()->topOfPage(pgNum);
00554         writer.addAttributePt( "svg:x", left() );
00555         writer.addAttributePt( "svg:y", yInPage );
00556         writer.addAttribute( "text:anchor-type", "page" );
00557         writer.addAttribute( "text:anchor-page-number", pgNum );
00558         writer.addAttribute( "draw:z-index", zOrder() );
00559     }
00560     writer.addAttributePt( "svg:width", width() );
00561     writer.addAttributePt( "svg:height", height() );
00562     if ( isCopy() )
00563         writer.addAttribute( "draw:copy-of", lastFrameName );
00564 }
00565 
00566 // shared between startOasisFrame and table cells.
00567 // Only background, borders, padding.
00568 void KWFrame::saveBorderProperties( KoGenStyle& frameStyle ) const
00569 {
00570     // Background: color and transparency
00571     // OOo seems to use style:background-transparency="100%", but the schema allows background-color=transparent
00572     if ( m_backgroundColor.style() == Qt::NoBrush )
00573         frameStyle.addProperty( "fo:background-color", "transparent" );
00574     else if ( m_backgroundColor.color().isValid() )
00575         frameStyle.addProperty( "fo:background-color", m_backgroundColor.color().name() );
00576 
00577     // Borders
00578     if (  ( m_borderLeft == m_borderRight )
00579           && ( m_borderLeft == m_borderTop )
00580           && ( m_borderLeft == m_borderBottom ) )
00581     {
00582         frameStyle.addProperty( "fo:border", m_borderLeft.saveFoBorder() );
00583     }
00584     else
00585     {
00586         frameStyle.addProperty( "fo:border-left", m_borderLeft.saveFoBorder() );
00587         frameStyle.addProperty( "fo:border-right", m_borderRight.saveFoBorder() );
00588         frameStyle.addProperty( "fo:border-top", m_borderTop.saveFoBorder() );
00589         frameStyle.addProperty( "fo:border-bottom", m_borderBottom.saveFoBorder() );
00590     }
00591 
00592     if ( m_paddingLeft != 0 && ( ( m_paddingLeft == m_paddingRight )
00593                                  && ( m_paddingLeft == m_paddingTop )
00594                                  && ( m_paddingLeft == m_paddingBottom ) ) )
00595         frameStyle.addPropertyPt( "fo:padding", m_paddingLeft );
00596     else
00597     {
00598         if ( m_paddingLeft != 0 )
00599             frameStyle.addPropertyPt( "fo:padding-left", m_paddingLeft );
00600         if ( m_paddingRight != 0 )
00601             frameStyle.addPropertyPt( "fo:padding-right", m_paddingRight );
00602         if ( m_paddingTop != 0 )
00603             frameStyle.addPropertyPt( "fo:padding-top", m_paddingTop );
00604         if ( m_paddingBottom != 0 )
00605             frameStyle.addPropertyPt( "fo:padding-bottom", m_paddingBottom );
00606     }
00607 }
00608 
00609 void KWFrame::saveMarginAttributes( KoXmlWriter &writer ) const
00610 {
00611     if ( m_runAroundLeft != 0 )
00612         writer.addAttributePt( "fo:margin-left", m_runAroundLeft );
00613     if ( m_runAroundRight != 0 )
00614         writer.addAttributePt( "fo:margin-right", m_runAroundRight );
00615     if ( m_runAroundTop != 0 )
00616         writer.addAttributePt( "fo:margin-top", m_runAroundTop );
00617     if ( m_runAroundBottom != 0 )
00618         writer.addAttributePt( "fo:margin-bottom", m_runAroundBottom );
00619 }
00620 
00621 void KWFrame::saveMarginProperties( KoGenStyle& frameStyle ) const
00622 {
00623 #if 0 // not allowed in the current OASIS spec
00624     if ( m_runAroundLeft != 0 && ( ( m_runAroundLeft == m_runAroundRight )
00625                                  && ( m_runAroundLeft == m_runAroundTop )
00626                                  && ( m_runAroundLeft == m_runAroundBottom ) ) )
00627         frameStyle.addPropertyPt( "fo:margin", m_runAroundLeft );
00628     else
00629     {
00630 #endif
00631         if ( m_runAroundLeft != 0 )
00632             frameStyle.addPropertyPt( "fo:margin-left", m_runAroundLeft );
00633         if ( m_runAroundRight != 0 )
00634             frameStyle.addPropertyPt( "fo:margin-right", m_runAroundRight );
00635         if ( m_runAroundTop != 0 )
00636             frameStyle.addPropertyPt( "fo:margin-top", m_runAroundTop );
00637         if ( m_runAroundBottom != 0 )
00638             frameStyle.addPropertyPt( "fo:margin-bottom", m_runAroundBottom );
00639 #if 0 // not allowed in the current OASIS spec
00640     }
00641 #endif
00642 }
00643 
00644 QString KWFrame::saveOasisFrameStyle( KoGenStyles& mainStyles ) const
00645 {
00646     KoGenStyle frameStyle( KWDocument::STYLE_FRAME_AUTO, "graphic" );
00647     QString protect;
00648     if ( frameSet()->protectContent() )
00649         protect = "content";
00650     if ( frameSet()->isProtectSize() ) // ## should be moved for frame
00651     {
00652         if ( !protect.isEmpty() )
00653             protect+=" ";
00654         protect+="size";
00655     }
00656     if ( !protect.isEmpty() )
00657         frameStyle.addProperty( "style:protect", protect );
00658 
00659     if ( !frameSet()->isFloating() )
00660     { // non-inline frame, anchored to page
00661         frameStyle.addProperty( "style:horizontal-rel", "page" );
00662         frameStyle.addProperty( "style:vertical-rel", "page" );
00663         frameStyle.addProperty( "style:horizontal-pos", "from-left" );
00664         frameStyle.addProperty( "style:vertical-pos", "from-top" );
00665     }
00666 
00667     // Background (KWFrame::saveBorderProperties saves as fo:background-color, but OOo-2.0.x uses draw:fill-color)
00668     // So now we use draw:fill-color too, the text background color is in fact a paragraph feature.
00669     if ( m_backgroundColor.style() == Qt::NoBrush )
00670         frameStyle.addProperty( "draw:fill-color", "transparent" );
00671     else if ( m_backgroundColor.color().isValid() )
00672         frameStyle.addProperty( "draw:fill-color", m_backgroundColor.color().name() );
00673 
00674     saveBorderProperties( frameStyle );
00675     saveMarginProperties( frameStyle );
00676 
00677     if ( runAround() == KWFrame::RA_SKIP )
00678         frameStyle.addProperty( "style:wrap", "none" );
00679     else if ( runAround() == KWFrame::RA_NO )
00680         frameStyle.addProperty( "style:wrap", "run-through" );
00681     else // RA_BOUNDINGRECT
00682     {
00683         if ( runAroundSide() ==  KWFrame::RA_LEFT )
00684             frameStyle.addProperty( "style:wrap", "left" );
00685         else if ( runAroundSide() == KWFrame::RA_RIGHT )
00686             frameStyle.addProperty( "style:wrap", "right" );
00687         else if ( runAroundSide() == KWFrame::RA_BIGGEST )
00688             frameStyle.addProperty( "style:wrap", "biggest" );
00689     }
00690 
00691     // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering
00692     // of existing documents, only editing (and only KWord has this kind of option until now).
00693     NewFrameBehavior defaultNfb = frameSet()->isHeaderOrFooter() ? Copy : NoFollowup;
00694     if ( m_newFrameBehavior != defaultNfb ) {
00695         const char* value = "none";
00696         if ( m_newFrameBehavior == Reconnect )
00697             value = "followup";
00698         else if ( m_newFrameBehavior == Copy )
00699             value = "copy";
00700         else if ( m_newFrameBehavior == NoFollowup )
00701             value = "none";
00702         frameStyle.addProperty( "koffice:frame-behavior-on-new-page", value );
00703     }
00704 
00705     // The loading code for this one is in kwtextframeset, maybe this should be moved there too
00706     const char* frameBehav = 0;
00707     if ( m_frameBehavior == KWFrame::Ignore )
00708         frameBehav = "clip";
00709     else if ( m_frameBehavior == KWFrame::AutoCreateNewFrame )
00710         frameBehav = "auto-create-new-frame";
00711     // the third case, AutoExtendFrame is handled by min-height
00712     if ( frameBehav )
00713         frameStyle.addProperty( "style:overflow-behavior", frameBehav );
00714 
00715     return mainStyles.lookup( frameStyle, "fr" );
00716 }
00717 
00718 bool KWFrame::frameAtPos( const QPoint& point, bool borderOfFrameOnly) const {
00719     // Forwarded to KWFrameSet to make it virtual
00720     return frameSet()->isFrameAtPos( this, point, borderOfFrameOnly );
00721 }
00722 
00723 KoRect KWFrame::innerRect() const
00724 {
00725     KoRect inner( this->normalize());
00726     inner.moveBy( paddingLeft(), paddingTop() );
00727     inner.setWidth( innerWidth() );
00728     inner.setHeight( innerHeight() );
00729     return inner;
00730 }
00731 
00732 double KWFrame::innerWidth() const
00733 {
00734     return KMAX( 0.0, width() - m_paddingLeft - m_paddingRight );
00735 }
00736 
00737 double KWFrame::innerHeight() const
00738 {
00739     return KMAX( 0.0, height() - m_paddingTop - m_paddingBottom );
00740 }
00741 
00742 void KWFrame::setFramePadding( double left, double top, double right, double bottom)
00743 {
00744     m_paddingLeft = left;
00745     m_paddingTop = top;
00746     m_paddingRight = right;
00747     m_paddingBottom = bottom;
00748 }
00749 
00750 bool KWFrame::compareFrameZOrder(KWFrame *f1, KWFrame *f2)
00751 {
00752     return f1->zOrder() < f2->zOrder();
00753 }
KDE Home | KDE Accessibility Home | Description of Access Keys