~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to kword/KWFrame.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2006-04-20 21:38:53 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060420213853-j5lxluqvymxt2zny
Tags: 1:1.5.0-0ubuntu2
UbuntuĀ uploadĀ 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project
 
2
   Copyright (C) 1998, 1999, 2000 Reginald Stadlbauer <reggie@kde.org>
 
3
   Copyright (C) 2000-2006 David Faure <faure@kde.org>
 
4
   Copyright (C) 2005 Thomas Zander <zander@kde.org>
 
5
 
 
6
   This library is free software; you can redistribute it and/or
 
7
   modify it under the terms of the GNU Library General Public
 
8
   License as published by the Free Software Foundation; either
 
9
   version 2 of the License, or (at your option) any later version.
 
10
 
 
11
   This library is distributed in the hope that it will be useful,
 
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
   Library General Public License for more details.
 
15
 
 
16
   You should have received a copy of the GNU Library General Public License
 
17
   along with this library; see the file COPYING.LIB.  If not, write to
 
18
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
19
 * Boston, MA 02110-1301, USA.
 
20
*/
 
21
 
 
22
#include "KWFrame.h"
 
23
#include "KWFrameSet.h"
 
24
#include "KWFrameList.h"
 
25
#include "KWDocument.h"
 
26
#include "KWPageManager.h"
 
27
#include "KWTextFrameSet.h"
 
28
#include "KWViewMode.h"
 
29
#include "KWCanvas.h"
 
30
 
 
31
#include <KoOasisContext.h>
 
32
#include <KoXmlNS.h>
 
33
#include <KoXmlWriter.h>
 
34
#include <KoStyleStack.h>
 
35
 
 
36
#include <kcommand.h>
 
37
#include <kdebug.h>
 
38
 
 
39
#include <float.h> // for DBL_DIG
 
40
 
 
41
//#define DEBUG_DRAW
 
42
 
 
43
/******************************************************************/
 
44
/* Class: ZOrderedFrameList                                       */
 
45
/******************************************************************/
 
46
 
 
47
int ZOrderedFrameList::compareItems(QPtrCollection::Item a, QPtrCollection::Item b)
 
48
{
 
49
    int za = ((KWFrame *)a)->zOrder();
 
50
    int zb = ((KWFrame *)b)->zOrder();
 
51
    if (za == zb) return 0;
 
52
    if (za < zb) return -1;
 
53
    return 1;
 
54
}
 
55
 
 
56
 
 
57
/******************************************************************/
 
58
/* Class: KWFrame                                                 */
 
59
/******************************************************************/
 
60
 
 
61
KWFrame::KWFrame(KWFrame * frame)
 
62
{
 
63
    m_runAround = RA_NO;
 
64
    //kdDebug(32001) << "KWFrame::KWFrame this=" << this << " frame=" << frame << endl;
 
65
    copySettings( frame );
 
66
    m_minFrameHeight=0;
 
67
    m_frameStack = 0; // lazy initialisation.
 
68
}
 
69
 
 
70
KWFrame::KWFrame(KWFrameSet *fs, double left, double top, double width, double height, RunAround ra )
 
71
    : KoRect( left, top, width, height ),
 
72
      // Initialize member vars here. This ensures they are all initialized, since it's
 
73
      // easier to compare this list with the member vars list (compiler ensures order).
 
74
      m_sheetSide( AnySide ),
 
75
      m_runAround( ra ),
 
76
      m_runAroundSide( RA_BIGGEST ),
 
77
      m_frameBehavior( AutoExtendFrame ),
 
78
      m_newFrameBehavior( ( fs && fs->type() == FT_TEXT ) ? Reconnect : NoFollowup ),
 
79
      m_bCopy( false ),
 
80
      m_drawFootNoteLine( false ),
 
81
      m_runAroundLeft( 1.0 ),
 
82
      m_runAroundRight( 1.0 ),
 
83
      m_runAroundTop( 1.0 ),
 
84
      m_runAroundBottom( 1.0 ),
 
85
      m_paddingLeft( 0 ),
 
86
      m_paddingRight( 0 ),
 
87
      m_paddingTop( 0 ),
 
88
      m_paddingBottom( 0 ),
 
89
      m_minFrameHeight( 0 ),
 
90
      m_internalY( 0 ),
 
91
      m_zOrder( 0 ),
 
92
      m_backgroundColor( (fs && (fs->type() == FT_PICTURE || fs->type() == FT_PART)) ? QBrush( QColor(), Qt::NoBrush) : QBrush( QColor() ) ), // valid brush with invalid color ( default )
 
93
      m_borderLeft( QColor(), KoBorder::SOLID, 0 ),
 
94
      m_borderRight( QColor(), KoBorder::SOLID, 0 ),
 
95
      m_borderTop( QColor(), KoBorder::SOLID, 0 ),
 
96
      m_borderBottom( QColor(), KoBorder::SOLID, 0 ),
 
97
      m_frameSet( fs )
 
98
{
 
99
    //kdDebug(32001) << "KWFrame::KWFrame " << this << " left=" << left << " top=" << top << endl;
 
100
    m_frameStack = 0; // lazy initialisation.
 
101
}
 
102
 
 
103
KWFrame::~KWFrame()
 
104
{
 
105
    //kdDebug(32001) << "KWFrame::~KWFrame " << this << endl;
 
106
    delete m_frameStack;
 
107
    m_frameStack = 0;
 
108
}
 
109
 
 
110
void KWFrame::setBackgroundColor( const QBrush &color )
 
111
{
 
112
    m_backgroundColor = color;
 
113
}
 
114
 
 
115
 
 
116
int KWFrame::pageNumber() const
 
117
{
 
118
    Q_ASSERT( m_frameSet );
 
119
    if( !m_frameSet ) {
 
120
        kdDebug() << k_funcinfo << this << " has no frameset!" << endl;
 
121
        return 0;
 
122
    }
 
123
    if( !m_frameSet->pageManager() ) {
 
124
        kdWarning() << k_funcinfo << this << " is not a frame that is in use; misses a pageManager!" << endl;
 
125
        return -1;
 
126
    }
 
127
    return frameSet()->pageManager()->pageNumber(this);
 
128
}
 
129
 
 
130
int KWFrame::pageNumber( KWDocument* doc ) const
 
131
{
 
132
    return doc->pageManager()->pageNumber(this);
 
133
}
 
134
 
 
135
KWFrame *KWFrame::getCopy() {
 
136
    /* returns a deep copy of self */
 
137
    return new KWFrame(this);
 
138
}
 
139
 
 
140
void KWFrame::copySettings(KWFrame *frm)
 
141
{
 
142
    setFrameSet( frm->frameSet() ); // do this first in case of debug output in the methods below
 
143
    setRect(frm->x(), frm->y(), frm->width(), frm->height());
 
144
    // Keep order identical as member var order (and init in ctor)
 
145
    setSheetSide(frm->sheetSide());
 
146
    setRunAround(frm->runAround());
 
147
    setRunAroundSide(frm->runAroundSide());
 
148
    setFrameBehavior(frm->frameBehavior());
 
149
    setNewFrameBehavior(frm->newFrameBehavior());
 
150
    setRunAroundGap(frm->runAroundLeft(), frm->runAroundRight(), frm->runAroundTop(), frm->runAroundBottom());
 
151
    setPaddingLeft(frm->paddingLeft());
 
152
    setPaddingRight(frm->paddingRight());
 
153
    setPaddingTop(frm->paddingTop());
 
154
    setPaddingBottom(frm->paddingBottom());
 
155
    setMinimumFrameHeight(frm->minimumFrameHeight());
 
156
    m_internalY = 0; // internal Y is recalculated
 
157
    setZOrder(frm->zOrder());
 
158
    setCopy(frm->isCopy());
 
159
    m_drawFootNoteLine = false; // recalculated
 
160
    setBackgroundColor( frm->backgroundColor() );
 
161
    setLeftBorder(frm->leftBorder());
 
162
    setRightBorder(frm->rightBorder());
 
163
    setTopBorder(frm->topBorder());
 
164
    setBottomBorder(frm->bottomBorder());
 
165
}
 
166
 
 
167
void KWFrame::frameBordersChanged() {
 
168
    if (frameSet()->isFloating())
 
169
        frameSet()->anchorFrameset()->invalidate();
 
170
}
 
171
 
 
172
 
 
173
void KWFrame::updateRulerHandles(){
 
174
// TODO
 
175
#if 0
 
176
    if(! isSelected())
 
177
    {
 
178
        KWDocument *doc = frameSet()->kWordDocument();
 
179
        if(doc)
 
180
            doc->updateRulerFrameStartEnd();
 
181
    }
 
182
#endif
 
183
}
 
184
 
 
185
QRect KWFrame::outerRect( KWViewMode* viewMode ) const
 
186
{
 
187
    KWDocument *doc = m_frameSet->kWordDocument();
 
188
    QRect outerRect( doc->zoomRect( *this ) );
 
189
    if ( viewMode && !m_frameSet->groupmanager() ) {
 
190
        int minBorder = viewMode->drawFrameBorders() ? 1 : 0;
 
191
        KWFrame* settingsFrame = m_frameSet->settingsFrame( this );
 
192
        outerRect.rLeft() -= KoBorder::zoomWidthX( settingsFrame->leftBorder().width(), doc, minBorder );
 
193
        outerRect.rTop() -= KoBorder::zoomWidthY( settingsFrame->topBorder().width(), doc, minBorder );
 
194
        outerRect.rRight() += KoBorder::zoomWidthX( settingsFrame->rightBorder().width(), doc, minBorder );
 
195
        outerRect.rBottom() += KoBorder::zoomWidthY( settingsFrame->bottomBorder().width(), doc, minBorder );
 
196
    }
 
197
    return outerRect;
 
198
}
 
199
 
 
200
KoRect KWFrame::outerKoRect() const
 
201
{
 
202
    KoRect outerRect = *this;
 
203
    KWDocument *doc = m_frameSet->kWordDocument();
 
204
    KWFrame* settingsFrame = m_frameSet->settingsFrame( this );
 
205
    outerRect.rLeft() -= KoBorder::zoomWidthX( settingsFrame->leftBorder().width(), doc, 1 ) / doc->zoomedResolutionX();
 
206
    outerRect.rTop() -= KoBorder::zoomWidthY( settingsFrame->topBorder().width(), doc, 1 ) / doc->zoomedResolutionY();
 
207
    outerRect.rRight() += KoBorder::zoomWidthX( settingsFrame->rightBorder().width(), doc, 1 ) / doc->zoomedResolutionX();
 
208
    outerRect.rBottom() += KoBorder::zoomWidthY( settingsFrame->bottomBorder().width(), doc, 1 ) / doc->zoomedResolutionY();
 
209
    return outerRect;
 
210
}
 
211
 
 
212
KoRect KWFrame::runAroundRect() const
 
213
{
 
214
    KoRect raRect = outerKoRect();
 
215
    raRect.rLeft() -= m_runAroundLeft;
 
216
    raRect.rRight() += m_runAroundRight;
 
217
    raRect.rTop() -= m_runAroundTop;
 
218
    raRect.rBottom() += m_runAroundBottom;
 
219
    return raRect;
 
220
}
 
221
 
 
222
void KWFrame::save( QDomElement &frameElem )
 
223
{
 
224
    // setAttribute( double ) uses a default precision of 6, and this seems
 
225
    // to be 6 digits, even like '123.123' !
 
226
    frameElem.setAttribute( "left", QString::number( left(), 'g', DBL_DIG ) );
 
227
    frameElem.setAttribute( "top", QString::number( top(), 'g', DBL_DIG ) );
 
228
    frameElem.setAttribute( "right", QString::number( right(), 'g', DBL_DIG ) );
 
229
    frameElem.setAttribute( "bottom", QString::number( bottom(), 'g', DBL_DIG ) );
 
230
    if ( minimumFrameHeight() > 0 )
 
231
        frameElem.setAttribute( "min-height", QString::number( minimumFrameHeight(), 'g', DBL_DIG ) );
 
232
 
 
233
    if ( !m_frameSet->isHeaderOrFooter() && !m_frameSet->isMainFrameset() )
 
234
    {
 
235
        if(runAround()!=RA_NO)
 
236
        {
 
237
            frameElem.setAttribute( "runaround", static_cast<int>( runAround() ) );
 
238
            if (runAround() == RA_BOUNDINGRECT)
 
239
            {
 
240
                if (runAroundSide()==RA_LEFT)
 
241
                    frameElem.setAttribute( "runaroundSide", "left" );
 
242
                else if (runAroundSide()==RA_RIGHT)
 
243
                    frameElem.setAttribute( "runaroundSide", "right" );
 
244
                else
 
245
                    frameElem.setAttribute( "runaroundSide", "biggest" );
 
246
            }
 
247
        }
 
248
        if(runAroundLeft()!=0 || runAroundRight()!=0 || runAroundTop()!=0 || runAroundBottom()!=0) {
 
249
            frameElem.setAttribute( "runaroundLeft", m_runAroundLeft );
 
250
            frameElem.setAttribute( "runaroundRight", m_runAroundRight );
 
251
            frameElem.setAttribute( "runaroundTop", m_runAroundTop );
 
252
            frameElem.setAttribute( "runaroundBottom", m_runAroundBottom );
 
253
            // The old file format had only one value, keep compat
 
254
            double runAroundGap = QMAX( QMAX( m_runAroundLeft, m_runAroundRight ), QMAX( m_runAroundTop, m_runAroundBottom ) );
 
255
            frameElem.setAttribute( "runaroundGap", runAroundGap );
 
256
        }
 
257
    }
 
258
 
 
259
    if(leftBorder().penWidth()!=0)
 
260
        frameElem.setAttribute( "lWidth", leftBorder().penWidth() );
 
261
 
 
262
    if(leftBorder().color.isValid())
 
263
    {
 
264
        frameElem.setAttribute( "lRed", leftBorder().color.red() );
 
265
        frameElem.setAttribute( "lGreen", leftBorder().color.green() );
 
266
        frameElem.setAttribute( "lBlue", leftBorder().color.blue() );
 
267
    }
 
268
    if(leftBorder().getStyle() != KoBorder::SOLID)
 
269
        frameElem.setAttribute( "lStyle", static_cast<int>( leftBorder().getStyle()) );
 
270
 
 
271
    if(rightBorder().penWidth()!=0)
 
272
        frameElem.setAttribute( "rWidth", rightBorder().penWidth() );
 
273
 
 
274
    if(rightBorder().color.isValid())
 
275
    {
 
276
        frameElem.setAttribute( "rRed", rightBorder().color.red() );
 
277
        frameElem.setAttribute( "rGreen", rightBorder().color.green() );
 
278
        frameElem.setAttribute( "rBlue", rightBorder().color.blue() );
 
279
    }
 
280
    if(rightBorder().getStyle() != KoBorder::SOLID)
 
281
        frameElem.setAttribute( "rStyle", static_cast<int>( rightBorder().getStyle() ) );
 
282
 
 
283
    if(topBorder().penWidth()!=0)
 
284
        frameElem.setAttribute( "tWidth", topBorder().penWidth() );
 
285
 
 
286
    if(topBorder().color.isValid())
 
287
    {
 
288
        frameElem.setAttribute( "tRed", topBorder().color.red() );
 
289
        frameElem.setAttribute( "tGreen", topBorder().color.green() );
 
290
        frameElem.setAttribute( "tBlue", topBorder().color.blue() );
 
291
    }
 
292
    if(topBorder().getStyle() != KoBorder::SOLID)
 
293
        frameElem.setAttribute( "tStyle", static_cast<int>( topBorder().getStyle() ) );
 
294
 
 
295
    if(bottomBorder().penWidth()!=0) {
 
296
        frameElem.setAttribute( "bWidth", bottomBorder().penWidth() );
 
297
    }
 
298
    if(bottomBorder().color.isValid()) {
 
299
        frameElem.setAttribute( "bRed", bottomBorder().color.red() );
 
300
        frameElem.setAttribute( "bGreen", bottomBorder().color.green() );
 
301
        frameElem.setAttribute( "bBlue", bottomBorder().color.blue() );
 
302
    }
 
303
    if(bottomBorder().getStyle() != KoBorder::SOLID)
 
304
        frameElem.setAttribute( "bStyle", static_cast<int>( bottomBorder().getStyle() ) );
 
305
 
 
306
    if(backgroundColor().color().isValid())
 
307
    {
 
308
        frameElem.setAttribute( "bkRed", backgroundColor().color().red() );
 
309
        frameElem.setAttribute( "bkGreen", backgroundColor().color().green() );
 
310
        frameElem.setAttribute( "bkBlue", backgroundColor().color().blue() );
 
311
        frameElem.setAttribute( "bkStyle", (int)backgroundColor().style ());
 
312
    }
 
313
    if(paddingLeft() != 0)
 
314
        frameElem.setAttribute( "bleftpt", paddingLeft() );
 
315
 
 
316
    if(paddingRight()!=0)
 
317
        frameElem.setAttribute( "brightpt", paddingRight() );
 
318
 
 
319
    if(paddingTop()!=0)
 
320
        frameElem.setAttribute( "btoppt", paddingTop() );
 
321
 
 
322
    if(paddingBottom()!=0)
 
323
        frameElem.setAttribute( "bbottompt", paddingBottom() );
 
324
 
 
325
    if(frameBehavior()!=AutoCreateNewFrame)
 
326
        frameElem.setAttribute( "autoCreateNewFrame", static_cast<int>( frameBehavior()) );
 
327
 
 
328
    //if(newFrameBehavior()!=Reconnect) // always save this one, since the default value depends on the type of frame, etc.
 
329
    frameElem.setAttribute( "newFrameBehavior", static_cast<int>( newFrameBehavior()) );
 
330
 
 
331
    //same reason
 
332
    frameElem.setAttribute( "copy", static_cast<int>( m_bCopy ) );
 
333
 
 
334
    if(sheetSide()!= AnySide)
 
335
        frameElem.setAttribute( "sheetSide", static_cast<int>( sheetSide()) );
 
336
 
 
337
    frameElem.setAttribute( "z-index", zOrder() );
 
338
}
 
339
 
 
340
void KWFrame::load( QDomElement &frameElem, KWFrameSet* frameSet, int syntaxVersion )
 
341
{
 
342
    m_minFrameHeight = KWDocument::getAttribute( frameElem, "min-height", 0.0 );
 
343
    m_runAround = static_cast<RunAround>( KWDocument::getAttribute( frameElem, "runaround", RA_NO ) );
 
344
    QString str = frameElem.attribute( "runaroundSide" );
 
345
    if ( str == "left" )
 
346
        m_runAroundSide = RA_LEFT;
 
347
    else if ( str == "right" )
 
348
        m_runAroundSide = RA_RIGHT;
 
349
    else
 
350
        m_runAroundSide = RA_BIGGEST;
 
351
 
 
352
    double runAroundGap = ( frameElem.hasAttribute( "runaroundGap" ) )
 
353
                          ? frameElem.attribute( "runaroundGap" ).toDouble()
 
354
                          : frameElem.attribute( "runaGapPT" ).toDouble();
 
355
    setRunAroundGap( KWDocument::getAttribute( frameElem, "runaroundLeft", runAroundGap ),
 
356
                     KWDocument::getAttribute( frameElem, "runaroundRight", runAroundGap ),
 
357
                     KWDocument::getAttribute( frameElem, "runaroundTop", runAroundGap ),
 
358
                     KWDocument::getAttribute( frameElem, "runaroundBottom", runAroundGap ) );
 
359
 
 
360
    m_sheetSide = static_cast<SheetSide>( KWDocument::getAttribute( frameElem, "sheetSide", AnySide ) );
 
361
    m_frameBehavior = static_cast<FrameBehavior>( KWDocument::getAttribute( frameElem, "autoCreateNewFrame", AutoCreateNewFrame ) );
 
362
    // Old documents had no "NewFrameBehavior" for footers/headers -> default to Copy.
 
363
    NewFrameBehavior defaultValue = frameSet->isHeaderOrFooter() ? Copy : Reconnect;
 
364
    // for old document we used the British spelling (newFrameBehaviour), so this is for backwards compatibility.
 
365
    defaultValue = static_cast<NewFrameBehavior>( KWDocument::getAttribute( frameElem, "newFrameBehaviour", defaultValue ) );
 
366
    m_newFrameBehavior = static_cast<NewFrameBehavior>( KWDocument::getAttribute( frameElem, "newFrameBehavior", defaultValue ) );
 
367
    if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet
 
368
        m_newFrameBehavior = NoFollowup;
 
369
 
 
370
    KoBorder l, r, t, b;
 
371
    l.setPenWidth( KWDocument::getAttribute( frameElem, "lWidth", 0.0 ));
 
372
    r.setPenWidth(KWDocument::getAttribute( frameElem, "rWidth", 0.0 ));
 
373
    t.setPenWidth(KWDocument::getAttribute( frameElem, "tWidth", 0.0 ));
 
374
    b.setPenWidth(KWDocument::getAttribute( frameElem, "bWidth", 0.0 ));
 
375
    if ( frameElem.hasAttribute("lRed") )
 
376
        l.color.setRgb(
 
377
            KWDocument::getAttribute( frameElem, "lRed", 0 ),
 
378
            KWDocument::getAttribute( frameElem, "lGreen", 0 ),
 
379
            KWDocument::getAttribute( frameElem, "lBlue", 0 ) );
 
380
    if ( frameElem.hasAttribute("rRed") )
 
381
        r.color.setRgb(
 
382
            KWDocument::getAttribute( frameElem, "rRed", 0 ),
 
383
            KWDocument::getAttribute( frameElem, "rGreen", 0 ),
 
384
            KWDocument::getAttribute( frameElem, "rBlue", 0 ) );
 
385
    if ( frameElem.hasAttribute("tRed") )
 
386
        t.color.setRgb(
 
387
            KWDocument::getAttribute( frameElem, "tRed", 0 ),
 
388
            KWDocument::getAttribute( frameElem, "tGreen", 0 ),
 
389
            KWDocument::getAttribute( frameElem, "tBlue", 0 ) );
 
390
    if ( frameElem.hasAttribute("bRed") )
 
391
        b.color.setRgb(
 
392
            KWDocument::getAttribute( frameElem, "bRed", 0 ),
 
393
            KWDocument::getAttribute( frameElem, "bGreen", 0 ),
 
394
            KWDocument::getAttribute( frameElem, "bBlue", 0 ) );
 
395
    l.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "lStyle", KoBorder::SOLID ) ));
 
396
    r.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "rStyle", KoBorder::SOLID ) ));
 
397
    t.setStyle(static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "tStyle", KoBorder::SOLID ) ));
 
398
    b.setStyle( static_cast<KoBorder::BorderStyle>( KWDocument::getAttribute( frameElem, "bStyle", KoBorder::SOLID ) ));
 
399
    QColor c;
 
400
    if ( frameElem.hasAttribute("bkRed") )
 
401
        c.setRgb(
 
402
            KWDocument::getAttribute( frameElem, "bkRed", 0 ),
 
403
            KWDocument::getAttribute( frameElem, "bkGreen", 0 ),
 
404
            KWDocument::getAttribute( frameElem, "bkBlue", 0 ) );
 
405
 
 
406
    if ( syntaxVersion < 2 ) // Activate old "white border == no border" conversion
 
407
    {
 
408
        if(c==l.color && l.penWidth()==1 && l.getStyle()==0 )
 
409
            l.setPenWidth(0);
 
410
        if(c==r.color  && r.penWidth()==1 && r.getStyle()==0)
 
411
            r.setPenWidth(0);
 
412
        if(c==t.color && t.penWidth()==1 && t.getStyle()==0 )
 
413
            t.setPenWidth(0);
 
414
        if(c==b.color && b.penWidth()==1 && b.getStyle()==0 )
 
415
            b.setPenWidth(0);
 
416
    }
 
417
    m_borderLeft = l;
 
418
    m_borderRight = r;
 
419
    m_borderTop = t;
 
420
    m_borderBottom = b;
 
421
    m_backgroundColor = QBrush( c );
 
422
 
 
423
 
 
424
    if( frameElem.hasAttribute("bkStyle"))
 
425
        m_backgroundColor.setStyle (static_cast<Qt::BrushStyle>(KWDocument::getAttribute( frameElem, "bkStyle", Qt::SolidPattern )));
 
426
 
 
427
    m_paddingLeft = frameElem.attribute( "bleftpt" ).toDouble();
 
428
    m_paddingRight = frameElem.attribute( "brightpt" ).toDouble();
 
429
    m_paddingTop = frameElem.attribute( "btoppt" ).toDouble();
 
430
    m_paddingBottom = frameElem.attribute( "bbottompt" ).toDouble();
 
431
    m_bCopy = KWDocument::getAttribute( frameElem, "copy", frameSet->isHeaderOrFooter() /* default to true for h/f */ );
 
432
    m_zOrder = frameElem.attribute( "z-index" ).toInt();
 
433
}
 
434
 
 
435
// This is shared with table cells - so, no runaround and newframebehavior etc.
 
436
// Only background, borders, padding.
 
437
void KWFrame::loadBorderProperties( KoStyleStack& styleStack )
 
438
{
 
439
    // padding. fo:padding for 4 values or padding-left/right/top/bottom
 
440
    m_paddingLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "left" ) );
 
441
    m_paddingRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "right" ) );
 
442
    m_paddingTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "top" ) );
 
443
    m_paddingBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "bottom" ) );
 
444
 
 
445
    // background color (3.11.25)
 
446
    if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color" ) ) {
 
447
        QString color = styleStack.attributeNS( KoXmlNS::fo, "background-color" );
 
448
        if ( color == "transparent" )
 
449
            m_backgroundColor = QBrush( QColor(), Qt::NoBrush );
 
450
        else
 
451
        {
 
452
            m_backgroundColor = QBrush( QColor( color ) /*, brush style is a dead feature, ignored */ );
 
453
        }
 
454
    }
 
455
    // OOo compatibility: it uses background-transparency=100% instead of background-color="transparent"
 
456
    if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-transparency" ) ) {
 
457
        QString transp = styleStack.attributeNS( KoXmlNS::fo, "background-transparency" );
 
458
        if ( transp == "100%" )
 
459
            m_backgroundColor.setStyle( Qt::NoBrush );
 
460
    }
 
461
 
 
462
    // borders (3.11.27)
 
463
    // can be none/hidden, solid and double. General form is the XSL/FO "width|style|color"
 
464
    {
 
465
        m_borderLeft.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "left") );
 
466
        m_borderRight.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "right") );
 
467
        m_borderTop.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "top") );
 
468
        m_borderBottom.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "bottom") );
 
469
    }
 
470
    // TODO more refined border spec for double borders (3.11.28)
 
471
}
 
472
 
 
473
void KWFrame::loadCommonOasisProperties( KoOasisContext& context, KWFrameSet* frameSet, const char* typeProperties )
 
474
{
 
475
    KoStyleStack& styleStack = context.styleStack();
 
476
    styleStack.setTypeProperties( typeProperties );
 
477
 
 
478
    loadBorderProperties( styleStack );
 
479
 
 
480
#if 0 // not allowed in the current OASIS spec
 
481
    // margins, i.e. runAroundGap. fo:margin for 4 values or padding-left/right/top/bottom
 
482
    m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "left" ) );
 
483
    m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "right" ) );
 
484
    m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "top" ) );
 
485
    m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "bottom" ) );
 
486
#endif
 
487
    // margins, i.e. runAroundGap. fo:margin-left/right/top/bottom
 
488
    m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) );
 
489
    m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) );
 
490
    m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) );
 
491
    m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) );
 
492
 
 
493
    // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering
 
494
    // of existing documents, only editing (and only KWord has this kind of option until now).
 
495
    const QCString frameBehaviorOnNewPage = styleStack.attributeNS( KoXmlNS::koffice, "frame-behavior-on-new-page" ).latin1();
 
496
    if ( frameBehaviorOnNewPage == "followup" )
 
497
        m_newFrameBehavior = Reconnect;
 
498
    else if ( frameBehaviorOnNewPage == "copy" )
 
499
        m_newFrameBehavior = Copy;
 
500
    else if ( frameBehaviorOnNewPage == "none" )
 
501
        m_newFrameBehavior = NoFollowup;
 
502
    else { // Defaults for OASIS documents not created by KWord
 
503
        m_newFrameBehavior = frameSet->isHeaderOrFooter() ? Copy : NoFollowup;
 
504
        if ( !frameBehaviorOnNewPage.isEmpty() )
 
505
            kdWarning(32001) << "Unknown value for koffice:frame-behavior-on-new-page: " << frameBehaviorOnNewPage << endl;
 
506
    }
 
507
    // Footnotes and endnotes are handled in a special way.
 
508
    if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet
 
509
        m_newFrameBehavior = NoFollowup;
 
510
 
 
511
    KWFrame::RunAround runAround = KWFrame::RA_BOUNDINGRECT;
 
512
    KWFrame::RunAroundSide runAroundSide = KWFrame::RA_BIGGEST;
 
513
    const QCString oowrap = styleStack.attributeNS( KoXmlNS::style, "wrap" ).latin1();
 
514
    if ( oowrap == "none" )        // 'no wrap' means 'avoid horizontal space'
 
515
        runAround = KWFrame::RA_SKIP;
 
516
    else if ( oowrap == "left" )
 
517
        runAroundSide = KWFrame::RA_LEFT;
 
518
    else if ( oowrap == "right" )
 
519
        runAroundSide= KWFrame::RA_RIGHT;
 
520
    else if ( oowrap == "run-through" )
 
521
        runAround = KWFrame::RA_NO;
 
522
    //if ( oowrap == "biggest" ) // OASIS extension
 
523
    // ->( KWFrame::RA_BOUNDINGRECT, KWFrame::RA_BIGGEST ), already set above
 
524
    //if ( oowrap == "parallel" || oowrap == "dynamic" )
 
525
    // dynamic is called "optimal" in the OO GUI. It's different from biggest because it can lead to parallel.
 
526
    // Those are not supported in KWord, let's use biggest instead
 
527
    setRunAround( runAround );
 
528
    setRunAroundSide( runAroundSide );
 
529
}
 
530
 
 
531
void KWFrame::startOasisFrame( KoXmlWriter &writer, KoGenStyles& mainStyles, const QString& name, const QString& lastFrameName ) const
 
532
{
 
533
    writer.startElement( "draw:frame" );
 
534
    writer.addAttribute( "draw:name", name );
 
535
    writer.addAttribute( "draw:style-name", saveOasisFrameStyle( mainStyles ) );
 
536
 
 
537
    if ( !frameSet()->isFloating() )
 
538
    { // non-inline frame, anchored to page
 
539
        const int pgNum = pageNumber();
 
540
        const double yInPage = top() - frameSet()->pageManager()->topOfPage(pgNum);
 
541
        writer.addAttributePt( "svg:x", left() );
 
542
        writer.addAttributePt( "svg:y", yInPage );
 
543
        writer.addAttribute( "text:anchor-type", "page" );
 
544
        writer.addAttribute( "text:anchor-page-number", pgNum );
 
545
        writer.addAttribute( "draw:z-index", zOrder() );
 
546
    }
 
547
    writer.addAttributePt( "svg:width", width() );
 
548
    writer.addAttributePt( "svg:height", height() );
 
549
    if ( isCopy() )
 
550
        writer.addAttribute( "draw:copy-of", lastFrameName );
 
551
}
 
552
 
 
553
// shared between startOasisFrame and table cells.
 
554
// Only background, borders, padding.
 
555
void KWFrame::saveBorderProperties( KoGenStyle& frameStyle ) const
 
556
{
 
557
    // Background: color and transparency
 
558
    // OOo seems to use style:background-transparency="100%", but the schema allows background-color=transparent
 
559
    if ( m_backgroundColor.style() == Qt::NoBrush )
 
560
        frameStyle.addProperty( "fo:background-color", "transparent" );
 
561
    else if ( m_backgroundColor.color().isValid() )
 
562
        frameStyle.addProperty( "fo:background-color", m_backgroundColor.color().name() );
 
563
 
 
564
    // Borders
 
565
    if (  ( m_borderLeft == m_borderRight )
 
566
          && ( m_borderLeft == m_borderTop )
 
567
          && ( m_borderLeft == m_borderBottom ) )
 
568
    {
 
569
        frameStyle.addProperty( "fo:border", m_borderLeft.saveFoBorder() );
 
570
    }
 
571
    else
 
572
    {
 
573
        frameStyle.addProperty( "fo:border-left", m_borderLeft.saveFoBorder() );
 
574
        frameStyle.addProperty( "fo:border-right", m_borderRight.saveFoBorder() );
 
575
        frameStyle.addProperty( "fo:border-top", m_borderTop.saveFoBorder() );
 
576
        frameStyle.addProperty( "fo:border-bottom", m_borderBottom.saveFoBorder() );
 
577
    }
 
578
 
 
579
    if ( m_paddingLeft != 0 && ( ( m_paddingLeft == m_paddingRight )
 
580
                                 && ( m_paddingLeft == m_paddingTop )
 
581
                                 && ( m_paddingLeft == m_paddingBottom ) ) )
 
582
        frameStyle.addPropertyPt( "fo:padding", m_paddingLeft );
 
583
    else
 
584
    {
 
585
        if ( m_paddingLeft != 0 )
 
586
            frameStyle.addPropertyPt( "fo:padding-left", m_paddingLeft );
 
587
        if ( m_paddingRight != 0 )
 
588
            frameStyle.addPropertyPt( "fo:padding-right", m_paddingRight );
 
589
        if ( m_paddingTop != 0 )
 
590
            frameStyle.addPropertyPt( "fo:padding-top", m_paddingTop );
 
591
        if ( m_paddingBottom != 0 )
 
592
            frameStyle.addPropertyPt( "fo:padding-bottom", m_paddingBottom );
 
593
    }
 
594
}
 
595
 
 
596
void KWFrame::saveMarginAttributes( KoXmlWriter &writer ) const
 
597
{
 
598
    if ( m_runAroundLeft != 0 )
 
599
        writer.addAttributePt( "fo:margin-left", m_runAroundLeft );
 
600
    if ( m_runAroundRight != 0 )
 
601
        writer.addAttributePt( "fo:margin-right", m_runAroundRight );
 
602
    if ( m_runAroundTop != 0 )
 
603
        writer.addAttributePt( "fo:margin-top", m_runAroundTop );
 
604
    if ( m_runAroundBottom != 0 )
 
605
        writer.addAttributePt( "fo:margin-bottom", m_runAroundBottom );
 
606
}
 
607
 
 
608
void KWFrame::saveMarginProperties( KoGenStyle& frameStyle ) const
 
609
{
 
610
#if 0 // not allowed in the current OASIS spec
 
611
    if ( m_runAroundLeft != 0 && ( ( m_runAroundLeft == m_runAroundRight )
 
612
                                 && ( m_runAroundLeft == m_runAroundTop )
 
613
                                 && ( m_runAroundLeft == m_runAroundBottom ) ) )
 
614
        frameStyle.addPropertyPt( "fo:margin", m_runAroundLeft );
 
615
    else
 
616
    {
 
617
#endif
 
618
        if ( m_runAroundLeft != 0 )
 
619
            frameStyle.addPropertyPt( "fo:margin-left", m_runAroundLeft );
 
620
        if ( m_runAroundRight != 0 )
 
621
            frameStyle.addPropertyPt( "fo:margin-right", m_runAroundRight );
 
622
        if ( m_runAroundTop != 0 )
 
623
            frameStyle.addPropertyPt( "fo:margin-top", m_runAroundTop );
 
624
        if ( m_runAroundBottom != 0 )
 
625
            frameStyle.addPropertyPt( "fo:margin-bottom", m_runAroundBottom );
 
626
#if 0 // not allowed in the current OASIS spec
 
627
    }
 
628
#endif
 
629
}
 
630
 
 
631
QString KWFrame::saveOasisFrameStyle( KoGenStyles& mainStyles ) const
 
632
{
 
633
    KoGenStyle frameStyle( KWDocument::STYLE_FRAME_AUTO, "graphic" );
 
634
    QString protect;
 
635
    if ( frameSet()->protectContent() )
 
636
        protect = "content";
 
637
    if ( frameSet()->isProtectSize() ) // ## should be moved for frame
 
638
    {
 
639
        if ( !protect.isEmpty() )
 
640
            protect+=" ";
 
641
        protect+="size";
 
642
    }
 
643
    if ( !protect.isEmpty() )
 
644
        frameStyle.addProperty( "style:protect", protect );
 
645
 
 
646
    if ( !frameSet()->isFloating() )
 
647
    { // non-inline frame, anchored to page
 
648
        frameStyle.addProperty( "style:horizontal-rel", "page" );
 
649
        frameStyle.addProperty( "style:vertical-rel", "page" );
 
650
        frameStyle.addProperty( "style:horizontal-pos", "from-left" );
 
651
        frameStyle.addProperty( "style:vertical-pos", "from-top" );
 
652
    }
 
653
 
 
654
    saveBorderProperties( frameStyle );
 
655
    saveMarginProperties( frameStyle );
 
656
 
 
657
    if ( runAround() == KWFrame::RA_SKIP )
 
658
        frameStyle.addProperty( "style:wrap", "none" );
 
659
    else if ( runAround() == KWFrame::RA_NO )
 
660
        frameStyle.addProperty( "style:wrap", "run-through" );
 
661
    else // RA_BOUNDINGRECT
 
662
    {
 
663
        if ( runAroundSide() ==  KWFrame::RA_LEFT )
 
664
            frameStyle.addProperty( "style:wrap", "left" );
 
665
        else if ( runAroundSide() == KWFrame::RA_RIGHT )
 
666
            frameStyle.addProperty( "style:wrap", "right" );
 
667
        else if ( runAroundSide() == KWFrame::RA_BIGGEST )
 
668
            frameStyle.addProperty( "style:wrap", "biggest" );
 
669
    }
 
670
 
 
671
    // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering
 
672
    // of existing documents, only editing (and only KWord has this kind of option until now).
 
673
    NewFrameBehavior defaultNfb = frameSet()->isHeaderOrFooter() ? Copy : NoFollowup;
 
674
    if ( m_newFrameBehavior != defaultNfb ) {
 
675
        const char* value = "none";
 
676
        if ( m_newFrameBehavior == Reconnect )
 
677
            value = "followup";
 
678
        else if ( m_newFrameBehavior == Copy )
 
679
            value = "copy";
 
680
        else if ( m_newFrameBehavior == NoFollowup )
 
681
            value = "none";
 
682
        frameStyle.addProperty( "koffice:frame-behavior-on-new-page", value );
 
683
    }
 
684
 
 
685
    // The loading code for this one is in kwtextframeset, maybe this should be moved there too
 
686
    const char* frameBehav = 0;
 
687
    if ( m_frameBehavior == KWFrame::Ignore )
 
688
        frameBehav = "clip";
 
689
    else if ( m_frameBehavior == KWFrame::AutoCreateNewFrame )
 
690
        frameBehav = "auto-create-new-frame";
 
691
    // the third case, AutoExtendFrame is handled by min-height
 
692
    if ( frameBehav )
 
693
        frameStyle.addProperty( "style:overflow-behavior", frameBehav );
 
694
 
 
695
    return mainStyles.lookup( frameStyle, "fr" );
 
696
}
 
697
 
 
698
bool KWFrame::frameAtPos( const QPoint& point, bool borderOfFrameOnly) const {
 
699
    // Forwarded to KWFrameSet to make it virtual
 
700
    return frameSet()->isFrameAtPos( this, point, borderOfFrameOnly );
 
701
}
 
702
 
 
703
KoRect KWFrame::innerRect() const
 
704
{
 
705
    KoRect inner( this->normalize());
 
706
    inner.moveBy( paddingLeft(), paddingTop() );
 
707
    inner.setWidth( innerWidth() );
 
708
    inner.setHeight( innerHeight() );
 
709
    return inner;
 
710
}
 
711
 
 
712
double KWFrame::innerWidth() const
 
713
{
 
714
    return KMAX( 0.0, width() - m_paddingLeft - m_paddingRight );
 
715
}
 
716
 
 
717
double KWFrame::innerHeight() const
 
718
{
 
719
    return KMAX( 0.0, height() - m_paddingTop - m_paddingBottom );
 
720
}
 
721
 
 
722
void KWFrame::setFramePadding( double left, double top, double right, double bottom)
 
723
{
 
724
    m_paddingLeft = left;
 
725
    m_paddingTop = top;
 
726
    m_paddingRight = right;
 
727
    m_paddingBottom = bottom;
 
728
}
 
729
 
 
730
bool KWFrame::compareFrameZOrder(KWFrame *f1, KWFrame *f2)
 
731
{
 
732
    return f1->zOrder() < f2->zOrder();
 
733
}