summaryrefslogtreecommitdiffstats
path: root/kword/KWFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kword/KWFrame.cpp')
-rw-r--r--kword/KWFrame.cpp753
1 files changed, 753 insertions, 0 deletions
diff --git a/kword/KWFrame.cpp b/kword/KWFrame.cpp
new file mode 100644
index 00000000..cc31aa97
--- /dev/null
+++ b/kword/KWFrame.cpp
@@ -0,0 +1,753 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999, 2000 Reginald Stadlbauer <reggie@kde.org>
+ Copyright (C) 2000-2006 David Faure <faure@kde.org>
+ Copyright (C) 2005 Thomas Zander <zander@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "KWFrame.h"
+#include "KWFrameSet.h"
+#include "KWFrameList.h"
+#include "KWDocument.h"
+#include "KWPageManager.h"
+#include "KWTextFrameSet.h"
+#include "KWViewMode.h"
+#include "KWCanvas.h"
+
+#include <KoOasisContext.h>
+#include <KoXmlNS.h>
+#include <KoXmlWriter.h>
+#include <KoStyleStack.h>
+
+#include <kcommand.h>
+#include <kdebug.h>
+
+#include <float.h> // for DBL_DIG
+
+//#define DEBUG_DRAW
+
+/******************************************************************/
+/* Class: ZOrderedFrameList */
+/******************************************************************/
+
+int ZOrderedFrameList::compareItems(QPtrCollection::Item a, QPtrCollection::Item b)
+{
+ int za = ((KWFrame *)a)->zOrder();
+ int zb = ((KWFrame *)b)->zOrder();
+ if (za == zb) return 0;
+ if (za < zb) return -1;
+ return 1;
+}
+
+
+/******************************************************************/
+/* Class: KWFrame */
+/******************************************************************/
+
+KWFrame::KWFrame(KWFrame * frame)
+{
+ m_runAround = RA_NO;
+ //kdDebug(32001) << "KWFrame::KWFrame this=" << this << " frame=" << frame << endl;
+ copySettings( frame );
+ m_minFrameHeight=0;
+ m_frameStack = 0; // lazy initialisation.
+}
+
+KWFrame::KWFrame(KWFrameSet *fs, double left, double top, double width, double height, RunAround ra )
+ : KoRect( left, top, width, height ),
+ // Initialize member vars here. This ensures they are all initialized, since it's
+ // easier to compare this list with the member vars list (compiler ensures order).
+ m_sheetSide( AnySide ),
+ m_runAround( ra ),
+ m_runAroundSide( RA_BIGGEST ),
+ m_frameBehavior( AutoExtendFrame ),
+ m_newFrameBehavior( ( fs && fs->type() == FT_TEXT ) ? Reconnect : NoFollowup ),
+ m_bCopy( false ),
+ m_drawFootNoteLine( false ),
+ m_runAroundLeft( 1.0 ),
+ m_runAroundRight( 1.0 ),
+ m_runAroundTop( 1.0 ),
+ m_runAroundBottom( 1.0 ),
+ m_paddingLeft( 0 ),
+ m_paddingRight( 0 ),
+ m_paddingTop( 0 ),
+ m_paddingBottom( 0 ),
+ m_minFrameHeight( 0.01 ), // not 0, since AutoExtendFrame means min-height in odt
+ m_internalY( 0 ),
+ m_zOrder( 0 ),
+ m_backgroundColor( (fs && (fs->type() == FT_PICTURE || fs->type() == FT_PART)) ? QBrush( QColor(), Qt::NoBrush) : QBrush( QColor() ) ), // valid brush with invalid color ( default )
+ m_borderLeft( QColor(), KoBorder::SOLID, 0 ),
+ m_borderRight( QColor(), KoBorder::SOLID, 0 ),
+ m_borderTop( QColor(), KoBorder::SOLID, 0 ),
+ m_borderBottom( QColor(), KoBorder::SOLID, 0 ),
+ m_frameSet( fs )
+{
+ //kdDebug(32001) << "KWFrame::KWFrame " << this << " left=" << left << " top=" << top << endl;
+ m_frameStack = 0; // lazy initialisation.
+}
+
+KWFrame::~KWFrame()
+{
+ //kdDebug(32001) << "KWFrame::~KWFrame " << this << endl;
+ delete m_frameStack;
+ m_frameStack = 0;
+}
+
+void KWFrame::setBackgroundColor( const QBrush &color )
+{
+ m_backgroundColor = color;
+}
+
+
+int KWFrame::pageNumber() const
+{
+ Q_ASSERT( m_frameSet );
+ if( !m_frameSet ) {
+ kdDebug() << k_funcinfo << this << " has no frameset!" << endl;
+ return 0;
+ }
+ if( !m_frameSet->pageManager() ) {
+ kdWarning() << k_funcinfo << this << " is not a frame that is in use; misses a pageManager!" << endl;
+ return -1;
+ }
+ return frameSet()->pageManager()->pageNumber(this);
+}
+
+int KWFrame::pageNumber( KWDocument* doc ) const
+{
+ return doc->pageManager()->pageNumber(this);
+}
+
+KWFrame *KWFrame::getCopy() {
+ /* returns a deep copy of self */
+ return new KWFrame(this);
+}
+
+void KWFrame::copySettings(KWFrame *frm)
+{
+ setFrameSet( frm->frameSet() ); // do this first in case of debug output in the methods below
+ setRect(frm->x(), frm->y(), frm->width(), frm->height());
+ // Keep order identical as member var order (and init in ctor)
+ setSheetSide(frm->sheetSide());
+ setRunAround(frm->runAround());
+ setRunAroundSide(frm->runAroundSide());
+ setFrameBehavior(frm->frameBehavior());
+ setNewFrameBehavior(frm->newFrameBehavior());
+ setRunAroundGap(frm->runAroundLeft(), frm->runAroundRight(), frm->runAroundTop(), frm->runAroundBottom());
+ setPaddingLeft(frm->paddingLeft());
+ setPaddingRight(frm->paddingRight());
+ setPaddingTop(frm->paddingTop());
+ setPaddingBottom(frm->paddingBottom());
+ setMinimumFrameHeight(frm->minimumFrameHeight());
+ m_internalY = 0; // internal Y is recalculated
+ setZOrder(frm->zOrder());
+ setCopy(frm->isCopy());
+ m_drawFootNoteLine = false; // recalculated
+ setBackgroundColor( frm->backgroundColor() );
+ setLeftBorder(frm->leftBorder());
+ setRightBorder(frm->rightBorder());
+ setTopBorder(frm->topBorder());
+ setBottomBorder(frm->bottomBorder());
+}
+
+void KWFrame::frameBordersChanged() {
+ if (frameSet()->isFloating())
+ frameSet()->anchorFrameset()->invalidate();
+}
+
+
+void KWFrame::updateRulerHandles(){
+// TODO
+#if 0
+ if(! isSelected())
+ {
+ KWDocument *doc = frameSet()->kWordDocument();
+ if(doc)
+ doc->updateRulerFrameStartEnd();
+ }
+#endif
+}
+
+QRect KWFrame::outerRect( KWViewMode* viewMode ) const
+{
+ KWDocument *doc = m_frameSet->kWordDocument();
+ QRect outerRect( doc->zoomRect( *this ) );
+ if ( viewMode && !m_frameSet->groupmanager() ) {
+ int minBorder = viewMode->drawFrameBorders() ? 1 : 0;
+ KWFrame* settingsFrame = m_frameSet->settingsFrame( this );
+ outerRect.rLeft() -= KoBorder::zoomWidthX( settingsFrame->leftBorder().width(), doc, minBorder );
+ outerRect.rTop() -= KoBorder::zoomWidthY( settingsFrame->topBorder().width(), doc, minBorder );
+ outerRect.rRight() += KoBorder::zoomWidthX( settingsFrame->rightBorder().width(), doc, minBorder );
+ outerRect.rBottom() += KoBorder::zoomWidthY( settingsFrame->bottomBorder().width(), doc, minBorder );
+ }
+ return outerRect;
+}
+
+KoRect KWFrame::outerKoRect() const
+{
+ KoRect outerRect = *this;
+ KWDocument *doc = m_frameSet->kWordDocument();
+ KWFrame* settingsFrame = m_frameSet->settingsFrame( this );
+ outerRect.rLeft() -= KoBorder::zoomWidthX( settingsFrame->leftBorder().width(), doc, 1 ) / doc->zoomedResolutionX();
+ outerRect.rTop() -= KoBorder::zoomWidthY( settingsFrame->topBorder().width(), doc, 1 ) / doc->zoomedResolutionY();
+ outerRect.rRight() += KoBorder::zoomWidthX( settingsFrame->rightBorder().width(), doc, 1 ) / doc->zoomedResolutionX();
+ outerRect.rBottom() += KoBorder::zoomWidthY( settingsFrame->bottomBorder().width(), doc, 1 ) / doc->zoomedResolutionY();
+ return outerRect;
+}
+
+KoRect KWFrame::runAroundRect() const
+{
+ KoRect raRect = outerKoRect();
+ raRect.rLeft() -= m_runAroundLeft;
+ raRect.rRight() += m_runAroundRight;
+ raRect.rTop() -= m_runAroundTop;
+ raRect.rBottom() += m_runAroundBottom;
+ return raRect;
+}
+
+void KWFrame::save( QDomElement &frameElem )
+{
+ // setAttribute( double ) uses a default precision of 6, and this seems
+ // to be 6 digits, even like '123.123' !
+ frameElem.setAttribute( "left", QString::number( left(), 'g', DBL_DIG ) );
+ frameElem.setAttribute( "top", QString::number( top(), 'g', DBL_DIG ) );
+ frameElem.setAttribute( "right", QString::number( right(), 'g', DBL_DIG ) );
+ frameElem.setAttribute( "bottom", QString::number( bottom(), 'g', DBL_DIG ) );
+ if ( minimumFrameHeight() > 0 )
+ frameElem.setAttribute( "min-height", QString::number( minimumFrameHeight(), 'g', DBL_DIG ) );
+
+ if ( !m_frameSet->isHeaderOrFooter() && !m_frameSet->isMainFrameset() )
+ {
+ if(runAround()!=RA_NO)
+ {
+ frameElem.setAttribute( "runaround", static_cast<int>( runAround() ) );
+ if (runAround() == RA_BOUNDINGRECT)
+ {
+ if (runAroundSide()==RA_LEFT)
+ frameElem.setAttribute( "runaroundSide", "left" );
+ else if (runAroundSide()==RA_RIGHT)
+ frameElem.setAttribute( "runaroundSide", "right" );
+ else
+ frameElem.setAttribute( "runaroundSide", "biggest" );
+ }
+ }
+ if(runAroundLeft()!=0 || runAroundRight()!=0 || runAroundTop()!=0 || runAroundBottom()!=0) {
+ frameElem.setAttribute( "runaroundLeft", m_runAroundLeft );
+ frameElem.setAttribute( "runaroundRight", m_runAroundRight );
+ frameElem.setAttribute( "runaroundTop", m_runAroundTop );
+ frameElem.setAttribute( "runaroundBottom", m_runAroundBottom );
+ // The old file format had only one value, keep compat
+ double runAroundGap = QMAX( QMAX( m_runAroundLeft, m_runAroundRight ), QMAX( m_runAroundTop, m_runAroundBottom ) );
+ frameElem.setAttribute( "runaroundGap", runAroundGap );
+ }
+ }
+
+ if(leftBorder().penWidth()!=0)
+ frameElem.setAttribute( "lWidth", leftBorder().penWidth() );
+
+ if(leftBorder().color.isValid())
+ {
+ frameElem.setAttribute( "lRed", leftBorder().color.red() );
+ frameElem.setAttribute( "lGreen", leftBorder().color.green() );
+ frameElem.setAttribute( "lBlue", leftBorder().color.blue() );
+ }
+ if(leftBorder().getStyle() != KoBorder::SOLID)
+ frameElem.setAttribute( "lStyle", static_cast<int>( leftBorder().getStyle()) );
+
+ if(rightBorder().penWidth()!=0)
+ frameElem.setAttribute( "rWidth", rightBorder().penWidth() );
+
+ if(rightBorder().color.isValid())
+ {
+ frameElem.setAttribute( "rRed", rightBorder().color.red() );
+ frameElem.setAttribute( "rGreen", rightBorder().color.green() );
+ frameElem.setAttribute( "rBlue", rightBorder().color.blue() );
+ }
+ if(rightBorder().getStyle() != KoBorder::SOLID)
+ frameElem.setAttribute( "rStyle", static_cast<int>( rightBorder().getStyle() ) );
+
+ if(topBorder().penWidth()!=0)
+ frameElem.setAttribute( "tWidth", topBorder().penWidth() );
+
+ if(topBorder().color.isValid())
+ {
+ frameElem.setAttribute( "tRed", topBorder().color.red() );
+ frameElem.setAttribute( "tGreen", topBorder().color.green() );
+ frameElem.setAttribute( "tBlue", topBorder().color.blue() );
+ }
+ if(topBorder().getStyle() != KoBorder::SOLID)
+ frameElem.setAttribute( "tStyle", static_cast<int>( topBorder().getStyle() ) );
+
+ if(bottomBorder().penWidth()!=0) {
+ frameElem.setAttribute( "bWidth", bottomBorder().penWidth() );
+ }
+ if(bottomBorder().color.isValid()) {
+ frameElem.setAttribute( "bRed", bottomBorder().color.red() );
+ frameElem.setAttribute( "bGreen", bottomBorder().color.green() );
+ frameElem.setAttribute( "bBlue", bottomBorder().color.blue() );
+ }
+ if(bottomBorder().getStyle() != KoBorder::SOLID)
+ frameElem.setAttribute( "bStyle", static_cast<int>( bottomBorder().getStyle() ) );
+
+ if(backgroundColor().color().isValid())
+ {
+ frameElem.setAttribute( "bkRed", backgroundColor().color().red() );
+ frameElem.setAttribute( "bkGreen", backgroundColor().color().green() );
+ frameElem.setAttribute( "bkBlue", backgroundColor().color().blue() );
+ frameElem.setAttribute( "bkStyle", (int)backgroundColor().style ());
+ }
+ if(paddingLeft() != 0)
+ frameElem.setAttribute( "bleftpt", paddingLeft() );
+
+ if(paddingRight()!=0)
+ frameElem.setAttribute( "brightpt", paddingRight() );
+
+ if(paddingTop()!=0)
+ frameElem.setAttribute( "btoppt", paddingTop() );
+
+ if(paddingBottom()!=0)
+ frameElem.setAttribute( "bbottompt", paddingBottom() );
+
+ if(frameBehavior()!=AutoCreateNewFrame)
+ frameElem.setAttribute( "autoCreateNewFrame", static_cast<int>( frameBehavior()) );
+
+ //if(newFrameBehavior()!=Reconnect) // always save this one, since the default value depends on the type of frame, etc.
+ frameElem.setAttribute( "newFrameBehavior", static_cast<int>( newFrameBehavior()) );
+
+ //same reason
+ frameElem.setAttribute( "copy", static_cast<int>( m_bCopy ) );
+
+ if(sheetSide()!= AnySide)
+ frameElem.setAttribute( "sheetSide", static_cast<int>( sheetSide()) );
+
+ frameElem.setAttribute( "z-index", zOrder() );
+}
+
+void KWFrame::load( QDomElement &frameElem, KWFrameSet* frameSet, int syntaxVersion )
+{
+ m_minFrameHeight = KWDocument::getAttribute( frameElem, "min-height", 0.0 );
+ m_runAround = static_cast<RunAround>( KWDocument::getAttribute( frameElem, "runaround", RA_NO ) );
+ QString str = frameElem.attribute( "runaroundSide" );
+ if ( str == "left" )
+ m_runAroundSide = RA_LEFT;
+ else if ( str == "right" )
+ m_runAroundSide = RA_RIGHT;
+ else
+ m_runAroundSide = RA_BIGGEST;
+
+ double runAroundGap = ( frameElem.hasAttribute( "runaroundGap" ) )
+ ? frameElem.attribute( "runaroundGap" ).toDouble()
+ : frameElem.attribute( "runaGapPT" ).toDouble();
+ setRunAroundGap( KWDocument::getAttribute( frameElem, "runaroundLeft", runAroundGap ),
+ KWDocument::getAttribute( frameElem, "runaroundRight", runAroundGap ),
+ KWDocument::getAttribute( frameElem, "runaroundTop", runAroundGap ),
+ KWDocument::getAttribute( frameElem, "runaroundBottom", runAroundGap ) );
+
+ m_sheetSide = static_cast<SheetSide>( KWDocument::getAttribute( frameElem, "sheetSide", AnySide ) );
+ m_frameBehavior = static_cast<FrameBehavior>( KWDocument::getAttribute( frameElem, "autoCreateNewFrame", AutoCreateNewFrame ) );
+ // Old documents had no "NewFrameBehavior" for footers/headers -> default to Copy.
+ NewFrameBehavior defaultValue = frameSet->isHeaderOrFooter() ? Copy : Reconnect;
+ // for old document we used the British spelling (newFrameBehaviour), so this is for backwards compatibility.
+ defaultValue = static_cast<NewFrameBehavior>( KWDocument::getAttribute( frameElem, "newFrameBehaviour", defaultValue ) );
+ m_newFrameBehavior = static_cast<NewFrameBehavior>( KWDocument::getAttribute( frameElem, "newFrameBehavior", defaultValue ) );
+ if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet
+ m_newFrameBehavior = NoFollowup;
+
+ KoBorder l, r, t, b;
+ l.setPenWidth( KWDocument::getAttribute( frameElem, "lWidth", 0.0 ));
+ r.setPenWidth(KWDocument::getAttribute( frameElem, "rWidth", 0.0 ));
+ t.setPenWidth(KWDocument::getAttribute( frameElem, "tWidth", 0.0 ));
+ b.setPenWidth(KWDocument::getAttribute( frameElem, "bWidth", 0.0 ));
+ if ( frameElem.hasAttribute("lRed") )
+ l.color.setRgb(
+ KWDocument::getAttribute( frameElem, "lRed", 0 ),
+ KWDocument::getAttribute( frameElem, "lGreen", 0 ),
+ KWDocument::getAttribute( frameElem, "lBlue", 0 ) );
+ if ( frameElem.hasAttribute("rRed") )
+ r.color.setRgb(
+ KWDocument::getAttribute( frameElem, "rRed", 0 ),
+ KWDocument::getAttribute( frameElem, "rGreen", 0 ),
+ KWDocument::getAttribute( frameElem, "rBlue", 0 ) );
+ if ( frameElem.hasAttribute("tRed") )
+ t.color.setRgb(
+ KWDocument::getAttribute( frameElem, "tRed", 0 ),
+ KWDocument::getAttribute( frameElem, "tGreen", 0 ),
+ KWDocument::getAttribute( frameElem, "tBlue", 0 ) );
+ if ( frameElem.hasAttribute("bRed") )
+ b.color.setRgb(
+ KWDocument::getAttribute( frameElem, "bRed", 0 ),
+ KWDocument::getAttribute( frameElem, "bGreen", 0 ),
+ KWDocument::getAttribute( frameElem, "bBlue", 0 ) );
+ l.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "lStyle", KoBorder::SOLID ) ));
+ r.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "rStyle", KoBorder::SOLID ) ));
+ t.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "tStyle", KoBorder::SOLID ) ));
+ b.setStyle( static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "bStyle", KoBorder::SOLID ) ));
+ QColor c;
+ if ( frameElem.hasAttribute("bkRed") )
+ c.setRgb(
+ KWDocument::getAttribute( frameElem, "bkRed", 0 ),
+ KWDocument::getAttribute( frameElem, "bkGreen", 0 ),
+ KWDocument::getAttribute( frameElem, "bkBlue", 0 ) );
+
+ if ( syntaxVersion < 2 ) // Activate old "white border == no border" conversion
+ {
+ if(c==l.color && l.penWidth()==1 && l.getStyle()==0 )
+ l.setPenWidth(0);
+ if(c==r.color && r.penWidth()==1 && r.getStyle()==0)
+ r.setPenWidth(0);
+ if(c==t.color && t.penWidth()==1 && t.getStyle()==0 )
+ t.setPenWidth(0);
+ if(c==b.color && b.penWidth()==1 && b.getStyle()==0 )
+ b.setPenWidth(0);
+ }
+ m_borderLeft = l;
+ m_borderRight = r;
+ m_borderTop = t;
+ m_borderBottom = b;
+ m_backgroundColor = QBrush( c );
+
+
+ if( frameElem.hasAttribute("bkStyle"))
+ m_backgroundColor.setStyle (static_cast<Qt::BrushStyle>(KWDocument::getAttribute( frameElem, "bkStyle", Qt::SolidPattern )));
+
+ m_paddingLeft = frameElem.attribute( "bleftpt" ).toDouble();
+ m_paddingRight = frameElem.attribute( "brightpt" ).toDouble();
+ m_paddingTop = frameElem.attribute( "btoppt" ).toDouble();
+ m_paddingBottom = frameElem.attribute( "bbottompt" ).toDouble();
+ m_bCopy = KWDocument::getAttribute( frameElem, "copy", frameSet->isHeaderOrFooter() /* default to true for h/f */ );
+ m_zOrder = frameElem.attribute( "z-index" ).toInt();
+}
+
+// This is shared with table cells - so, no runaround and newframebehavior etc.
+// Only background, borders, padding.
+void KWFrame::loadBorderProperties( KoStyleStack& styleStack )
+{
+ // padding. fo:padding for 4 values or padding-left/right/top/bottom
+ m_paddingLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "left" ) );
+ m_paddingRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "right" ) );
+ m_paddingTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "top" ) );
+ m_paddingBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "bottom" ) );
+
+ // background color
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color" ) ) {
+ QString color = styleStack.attributeNS( KoXmlNS::fo, "background-color" );
+ if ( color == "transparent" )
+ m_backgroundColor = QBrush( QColor(), Qt::NoBrush );
+ else
+ {
+ m_backgroundColor = QBrush( QColor( color ) /*, brush style is a dead feature, ignored */ );
+ }
+ }
+ // OOo compatibility: it uses background-transparency=100% instead of background-color="transparent"
+ if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-transparency" ) ) {
+ QString transp = styleStack.attributeNS( KoXmlNS::fo, "background-transparency" );
+ if ( transp == "100%" )
+ m_backgroundColor.setStyle( Qt::NoBrush );
+ }
+
+ // borders (3.11.27)
+ // can be none/hidden, solid and double. General form is the XSL/FO "width|style|color"
+ {
+ m_borderLeft.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "left") );
+ m_borderRight.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "right") );
+ m_borderTop.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "top") );
+ m_borderBottom.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "bottom") );
+ }
+ // TODO more refined border spec for double borders (3.11.28)
+}
+
+void KWFrame::loadCommonOasisProperties( KoOasisContext& context, KWFrameSet* frameSet, const char* typeProperties )
+{
+ KoStyleStack& styleStack = context.styleStack();
+ styleStack.setTypeProperties( typeProperties );
+
+ loadBorderProperties( styleStack );
+
+ // Background color is now done with fill-color.
+ // loadBorderProperties loads fo:background-color for compatibility (and for table cells),
+ // but the correct way for text boxes is draw:fill-color
+ if ( styleStack.hasAttributeNS( KoXmlNS::draw, "fill-color" ) ) {
+ QString color = styleStack.attributeNS( KoXmlNS::draw, "fill-color" );
+ if ( color == "transparent" )
+ m_backgroundColor = QBrush( QColor(), Qt::NoBrush );
+ else
+ {
+ m_backgroundColor = QBrush( QColor( color ) /*, brush style is a dead feature, ignored */ );
+ }
+ }
+
+#if 0 // not allowed in the current OASIS spec
+ // margins, i.e. runAroundGap. fo:margin for 4 values or padding-left/right/top/bottom
+ m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "left" ) );
+ m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "right" ) );
+ m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "top" ) );
+ m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "bottom" ) );
+#endif
+ // margins, i.e. runAroundGap. fo:margin-left/right/top/bottom
+ m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) );
+ m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) );
+ m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) );
+ m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) );
+
+ // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering
+ // of existing documents, only editing (and only KWord has this kind of option until now).
+ const QCString frameBehaviorOnNewPage = styleStack.attributeNS( KoXmlNS::koffice, "frame-behavior-on-new-page" ).latin1();
+ if ( frameBehaviorOnNewPage == "followup" )
+ m_newFrameBehavior = Reconnect;
+ else if ( frameBehaviorOnNewPage == "copy" )
+ m_newFrameBehavior = Copy;
+ else if ( frameBehaviorOnNewPage == "none" )
+ m_newFrameBehavior = NoFollowup;
+ else { // Defaults for OASIS documents not created by KWord
+ m_newFrameBehavior = frameSet->isHeaderOrFooter() ? Copy : NoFollowup;
+ if ( !frameBehaviorOnNewPage.isEmpty() )
+ kdWarning(32001) << "Unknown value for koffice:frame-behavior-on-new-page: " << frameBehaviorOnNewPage << endl;
+ }
+ // Footnotes and endnotes are handled in a special way.
+ if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet
+ m_newFrameBehavior = NoFollowup;
+
+ KWFrame::RunAround runAround = KWFrame::RA_BOUNDINGRECT;
+ KWFrame::RunAroundSide runAroundSide = KWFrame::RA_BIGGEST;
+ const QCString oowrap = styleStack.attributeNS( KoXmlNS::style, "wrap" ).latin1();
+ if ( oowrap == "none" ) // 'no wrap' means 'avoid horizontal space'
+ runAround = KWFrame::RA_SKIP;
+ else if ( oowrap == "left" )
+ runAroundSide = KWFrame::RA_LEFT;
+ else if ( oowrap == "right" )
+ runAroundSide= KWFrame::RA_RIGHT;
+ else if ( oowrap == "run-through" )
+ runAround = KWFrame::RA_NO;
+ //if ( oowrap == "biggest" ) // OASIS extension
+ // ->( KWFrame::RA_BOUNDINGRECT, KWFrame::RA_BIGGEST ), already set above
+ //if ( oowrap == "parallel" || oowrap == "dynamic" )
+ // dynamic is called "optimal" in the OO GUI. It's different from biggest because it can lead to parallel.
+ // Those are not supported in KWord, let's use biggest instead
+ setRunAround( runAround );
+ setRunAroundSide( runAroundSide );
+}
+
+void KWFrame::startOasisFrame( KoXmlWriter &writer, KoGenStyles& mainStyles, const QString& name, const QString& lastFrameName ) const
+{
+ writer.startElement( "draw:frame" );
+ writer.addAttribute( "draw:name", name );
+ writer.addAttribute( "draw:style-name", saveOasisFrameStyle( mainStyles ) );
+
+ if ( !frameSet()->isFloating() )
+ { // non-inline frame, anchored to page
+ const int pgNum = pageNumber();
+ const double yInPage = top() - frameSet()->pageManager()->topOfPage(pgNum);
+ writer.addAttributePt( "svg:x", left() );
+ writer.addAttributePt( "svg:y", yInPage );
+ writer.addAttribute( "text:anchor-type", "page" );
+ writer.addAttribute( "text:anchor-page-number", pgNum );
+ writer.addAttribute( "draw:z-index", zOrder() );
+ }
+ writer.addAttributePt( "svg:width", width() );
+ writer.addAttributePt( "svg:height", height() );
+ if ( isCopy() )
+ writer.addAttribute( "draw:copy-of", lastFrameName );
+}
+
+// shared between startOasisFrame and table cells.
+// Only background, borders, padding.
+void KWFrame::saveBorderProperties( KoGenStyle& frameStyle ) const
+{
+ // Background: color and transparency
+ // OOo seems to use style:background-transparency="100%", but the schema allows background-color=transparent
+ if ( m_backgroundColor.style() == Qt::NoBrush )
+ frameStyle.addProperty( "fo:background-color", "transparent" );
+ else if ( m_backgroundColor.color().isValid() )
+ frameStyle.addProperty( "fo:background-color", m_backgroundColor.color().name() );
+
+ // Borders
+ if ( ( m_borderLeft == m_borderRight )
+ && ( m_borderLeft == m_borderTop )
+ && ( m_borderLeft == m_borderBottom ) )
+ {
+ frameStyle.addProperty( "fo:border", m_borderLeft.saveFoBorder() );
+ }
+ else
+ {
+ frameStyle.addProperty( "fo:border-left", m_borderLeft.saveFoBorder() );
+ frameStyle.addProperty( "fo:border-right", m_borderRight.saveFoBorder() );
+ frameStyle.addProperty( "fo:border-top", m_borderTop.saveFoBorder() );
+ frameStyle.addProperty( "fo:border-bottom", m_borderBottom.saveFoBorder() );
+ }
+
+ if ( m_paddingLeft != 0 && ( ( m_paddingLeft == m_paddingRight )
+ && ( m_paddingLeft == m_paddingTop )
+ && ( m_paddingLeft == m_paddingBottom ) ) )
+ frameStyle.addPropertyPt( "fo:padding", m_paddingLeft );
+ else
+ {
+ if ( m_paddingLeft != 0 )
+ frameStyle.addPropertyPt( "fo:padding-left", m_paddingLeft );
+ if ( m_paddingRight != 0 )
+ frameStyle.addPropertyPt( "fo:padding-right", m_paddingRight );
+ if ( m_paddingTop != 0 )
+ frameStyle.addPropertyPt( "fo:padding-top", m_paddingTop );
+ if ( m_paddingBottom != 0 )
+ frameStyle.addPropertyPt( "fo:padding-bottom", m_paddingBottom );
+ }
+}
+
+void KWFrame::saveMarginAttributes( KoXmlWriter &writer ) const
+{
+ if ( m_runAroundLeft != 0 )
+ writer.addAttributePt( "fo:margin-left", m_runAroundLeft );
+ if ( m_runAroundRight != 0 )
+ writer.addAttributePt( "fo:margin-right", m_runAroundRight );
+ if ( m_runAroundTop != 0 )
+ writer.addAttributePt( "fo:margin-top", m_runAroundTop );
+ if ( m_runAroundBottom != 0 )
+ writer.addAttributePt( "fo:margin-bottom", m_runAroundBottom );
+}
+
+void KWFrame::saveMarginProperties( KoGenStyle& frameStyle ) const
+{
+#if 0 // not allowed in the current OASIS spec
+ if ( m_runAroundLeft != 0 && ( ( m_runAroundLeft == m_runAroundRight )
+ && ( m_runAroundLeft == m_runAroundTop )
+ && ( m_runAroundLeft == m_runAroundBottom ) ) )
+ frameStyle.addPropertyPt( "fo:margin", m_runAroundLeft );
+ else
+ {
+#endif
+ if ( m_runAroundLeft != 0 )
+ frameStyle.addPropertyPt( "fo:margin-left", m_runAroundLeft );
+ if ( m_runAroundRight != 0 )
+ frameStyle.addPropertyPt( "fo:margin-right", m_runAroundRight );
+ if ( m_runAroundTop != 0 )
+ frameStyle.addPropertyPt( "fo:margin-top", m_runAroundTop );
+ if ( m_runAroundBottom != 0 )
+ frameStyle.addPropertyPt( "fo:margin-bottom", m_runAroundBottom );
+#if 0 // not allowed in the current OASIS spec
+ }
+#endif
+}
+
+QString KWFrame::saveOasisFrameStyle( KoGenStyles& mainStyles ) const
+{
+ KoGenStyle frameStyle( KWDocument::STYLE_FRAME_AUTO, "graphic" );
+ QString protect;
+ if ( frameSet()->protectContent() )
+ protect = "content";
+ if ( frameSet()->isProtectSize() ) // ## should be moved for frame
+ {
+ if ( !protect.isEmpty() )
+ protect+=" ";
+ protect+="size";
+ }
+ if ( !protect.isEmpty() )
+ frameStyle.addProperty( "style:protect", protect );
+
+ if ( !frameSet()->isFloating() )
+ { // non-inline frame, anchored to page
+ frameStyle.addProperty( "style:horizontal-rel", "page" );
+ frameStyle.addProperty( "style:vertical-rel", "page" );
+ frameStyle.addProperty( "style:horizontal-pos", "from-left" );
+ frameStyle.addProperty( "style:vertical-pos", "from-top" );
+ }
+
+ // Background (KWFrame::saveBorderProperties saves as fo:background-color, but OOo-2.0.x uses draw:fill-color)
+ // So now we use draw:fill-color too, the text background color is in fact a paragraph feature.
+ if ( m_backgroundColor.style() == Qt::NoBrush )
+ frameStyle.addProperty( "draw:fill-color", "transparent" );
+ else if ( m_backgroundColor.color().isValid() )
+ frameStyle.addProperty( "draw:fill-color", m_backgroundColor.color().name() );
+
+ saveBorderProperties( frameStyle );
+ saveMarginProperties( frameStyle );
+
+ if ( runAround() == KWFrame::RA_SKIP )
+ frameStyle.addProperty( "style:wrap", "none" );
+ else if ( runAround() == KWFrame::RA_NO )
+ frameStyle.addProperty( "style:wrap", "run-through" );
+ else // RA_BOUNDINGRECT
+ {
+ if ( runAroundSide() == KWFrame::RA_LEFT )
+ frameStyle.addProperty( "style:wrap", "left" );
+ else if ( runAroundSide() == KWFrame::RA_RIGHT )
+ frameStyle.addProperty( "style:wrap", "right" );
+ else if ( runAroundSide() == KWFrame::RA_BIGGEST )
+ frameStyle.addProperty( "style:wrap", "biggest" );
+ }
+
+ // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering
+ // of existing documents, only editing (and only KWord has this kind of option until now).
+ NewFrameBehavior defaultNfb = frameSet()->isHeaderOrFooter() ? Copy : NoFollowup;
+ if ( m_newFrameBehavior != defaultNfb ) {
+ const char* value = "none";
+ if ( m_newFrameBehavior == Reconnect )
+ value = "followup";
+ else if ( m_newFrameBehavior == Copy )
+ value = "copy";
+ else if ( m_newFrameBehavior == NoFollowup )
+ value = "none";
+ frameStyle.addProperty( "koffice:frame-behavior-on-new-page", value );
+ }
+
+ // The loading code for this one is in kwtextframeset, maybe this should be moved there too
+ const char* frameBehav = 0;
+ if ( m_frameBehavior == KWFrame::Ignore )
+ frameBehav = "clip";
+ else if ( m_frameBehavior == KWFrame::AutoCreateNewFrame )
+ frameBehav = "auto-create-new-frame";
+ // the third case, AutoExtendFrame is handled by min-height
+ if ( frameBehav )
+ frameStyle.addProperty( "style:overflow-behavior", frameBehav );
+
+ return mainStyles.lookup( frameStyle, "fr" );
+}
+
+bool KWFrame::frameAtPos( const QPoint& point, bool borderOfFrameOnly) const {
+ // Forwarded to KWFrameSet to make it virtual
+ return frameSet()->isFrameAtPos( this, point, borderOfFrameOnly );
+}
+
+KoRect KWFrame::innerRect() const
+{
+ KoRect inner( this->normalize());
+ inner.moveBy( paddingLeft(), paddingTop() );
+ inner.setWidth( innerWidth() );
+ inner.setHeight( innerHeight() );
+ return inner;
+}
+
+double KWFrame::innerWidth() const
+{
+ return KMAX( 0.0, width() - m_paddingLeft - m_paddingRight );
+}
+
+double KWFrame::innerHeight() const
+{
+ return KMAX( 0.0, height() - m_paddingTop - m_paddingBottom );
+}
+
+void KWFrame::setFramePadding( double left, double top, double right, double bottom)
+{
+ m_paddingLeft = left;
+ m_paddingTop = top;
+ m_paddingRight = right;
+ m_paddingBottom = bottom;
+}
+
+bool KWFrame::compareFrameZOrder(KWFrame *f1, KWFrame *f2)
+{
+ return f1->zOrder() < f2->zOrder();
+}