You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kword/KWFrame.cpp

754 lines
32 KiB

/* 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(TQPtrCollection::Item a, TQPtrCollection::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)) ? TQBrush( TQColor(), TQt::NoBrush) : TQBrush( TQColor() ) ), // valid brush with invalid color ( default )
m_borderLeft( TQColor(), KoBorder::SOLID, 0 ),
m_borderRight( TQColor(), KoBorder::SOLID, 0 ),
m_borderTop( TQColor(), KoBorder::SOLID, 0 ),
m_borderBottom( TQColor(), 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 TQBrush &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()->tqinvalidate();
}
void KWFrame::updateRulerHandles(){
// TODO
#if 0
if(! isSelected())
{
KWDocument *doc = frameSet()->kWordDocument();
if(doc)
doc->updateRulerFrameStartEnd();
}
#endif
}
TQRect KWFrame::outerRect( KWViewMode* viewMode ) const
{
KWDocument *doc = m_frameSet->kWordDocument();
TQRect 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( TQDomElement &frameElem )
{
// setAttribute( double ) uses a default precision of 6, and this seems
// to be 6 digits, even like '123.123' !
frameElem.setAttribute( "left", TQString::number( left(), 'g', DBL_DIG ) );
frameElem.setAttribute( "top", TQString::number( top(), 'g', DBL_DIG ) );
frameElem.setAttribute( "right", TQString::number( right(), 'g', DBL_DIG ) );
frameElem.setAttribute( "bottom", TQString::number( bottom(), 'g', DBL_DIG ) );
if ( minimumFrameHeight() > 0 )
frameElem.setAttribute( "min-height", TQString::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 = TQMAX( TQMAX( m_runAroundLeft, m_runAroundRight ), TQMAX( 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( TQDomElement &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 ) );
TQString 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 ) ));
TQColor 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 = TQBrush( c );
if( frameElem.hasAttribute("bkStyle"))
m_backgroundColor.setStyle (static_cast<Qt::BrushStyle>(KWDocument::getAttribute( frameElem, "bkStyle", TQt::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" ) ) {
TQString color = styleStack.attributeNS( KoXmlNS::fo, "background-color" );
if ( color == "transparent" )
m_backgroundColor = TQBrush( TQColor(), TQt::NoBrush );
else
{
m_backgroundColor = TQBrush( TQColor( 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" ) ) {
TQString 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" ) ) {
TQString color = styleStack.attributeNS( KoXmlNS::draw, "fill-color" );
if ( color == "transparent" )
m_backgroundColor = TQBrush( TQColor(), TQt::NoBrush );
else
{
m_backgroundColor = TQBrush( TQColor( 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 TQCString 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 TQCString 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 TQString& name, const TQString& 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() == TQt::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
}
TQString KWFrame::saveOasisFrameStyle( KoGenStyles& mainStyles ) const
{
KoGenStyle frameStyle( KWDocument::STYLE_FRAME_AUTO, "graphic" );
TQString 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() == TQt::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 TQPoint& 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();
}