1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scitems.hxx"
21 #include <svtools/colorcfg.hxx>
22 #include <editeng/eeitem.hxx>
23 #include <editeng/outlobj.hxx>
24 #include <svx/sdshitm.hxx>
25 #include <svx/sdsxyitm.hxx>
26 #include <svx/sdtditm.hxx>
27 #include <svx/svditer.hxx>
28 #include <svx/svdocapt.hxx>
29 #include <svx/svdocirc.hxx>
30 #include <svx/svdopath.hxx>
31 #include <svx/svdorect.hxx>
32 #include <svx/svdpage.hxx>
33 #include <svx/svdundo.hxx>
34 #include <svx/xfillit0.hxx>
35 #include <svx/xflclit.hxx>
36 #include <svx/xlnclit.hxx>
37 #include <svx/xlnedcit.hxx>
38 #include <svx/xlnedit.hxx>
39 #include <svx/xlnedwit.hxx>
40 #include <svx/xlnstcit.hxx>
41 #include <svx/xlnstit.hxx>
42 #include <svx/xlnstwit.hxx>
43 #include <svx/xlnwtit.hxx>
44 #include <svx/xtable.hxx>
45 #include <editeng/outliner.hxx>
46 #include <editeng/editobj.hxx>
47 #include <svx/sxcecitm.hxx>
48 #include <svl/whiter.hxx>
49 #include <editeng/writingmodeitem.hxx>
51 #include <basegfx/point/b2dpoint.hxx>
52 #include <basegfx/polygon/b2dpolygontools.hxx>
53 #include <basegfx/polygon/b2dpolygon.hxx>
55 #include "detfunc.hxx"
56 #include "document.hxx"
57 #include "dociter.hxx"
58 #include "drwlayer.hxx"
59 #include "userdat.hxx"
60 #include "validat.hxx"
61 #include "formulacell.hxx"
62 #include "docpool.hxx"
63 #include "patattr.hxx"
67 #include "rangelst.hxx"
68 #include "reftokenhelper.hxx"
69 #include "formulaiter.hxx"
70 #include "cellvalue.hxx"
73 #include <boost/scoped_array.hpp>
76 using namespace com::sun::star
;
78 // line ends are now created with an empty name.
79 // The checkForUniqueItem method then finds a unique name for the item's value.
80 #define SC_LINEEND_NAME EMPTY_OUSTRING
82 enum DetInsertResult
{ // return-values for inserting in one level
94 SfxItemSet aFromTabSet
;
95 SfxItemSet aCircleSet
; //TODO: individually ?
99 ScDetectiveData( SdrModel
* pModel
);
101 SfxItemSet
& GetBoxSet() { return aBoxSet
; }
102 SfxItemSet
& GetArrowSet() { return aArrowSet
; }
103 SfxItemSet
& GetToTabSet() { return aToTabSet
; }
104 SfxItemSet
& GetFromTabSet() { return aFromTabSet
; }
105 SfxItemSet
& GetCircleSet() { return aCircleSet
; }
107 void SetMaxLevel( sal_uInt16 nVal
) { nMaxLevel
= nVal
; }
108 sal_uInt16
GetMaxLevel() const { return nMaxLevel
; }
114 ScCommentData( ScDocument
& rDoc
, SdrModel
* pModel
);
116 SfxItemSet
& GetCaptionSet() { return aCaptionSet
; }
117 void UpdateCaptionSet( const SfxItemSet
& rItemSet
);
120 SfxItemSet aCaptionSet
;
123 ColorData
ScDetectiveFunc::nArrowColor
= 0;
124 ColorData
ScDetectiveFunc::nErrorColor
= 0;
125 ColorData
ScDetectiveFunc::nCommentColor
= 0;
126 bool ScDetectiveFunc::bColorsInitialized
= false;
128 static bool lcl_HasThickLine( SdrObject
& rObj
)
130 // thin lines get width 0 -> everything greater 0 is a thick line
132 return static_cast<const XLineWidthItem
&>(rObj
.GetMergedItem(XATTR_LINEWIDTH
)).GetValue() > 0;
135 ScDetectiveData::ScDetectiveData( SdrModel
* pModel
) :
136 aBoxSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
137 aArrowSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
138 aToTabSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
139 aFromTabSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
140 aCircleSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
)
144 aBoxSet
.Put( XLineColorItem( EMPTY_OUSTRING
, Color( ScDetectiveFunc::GetArrowColor() ) ) );
145 aBoxSet
.Put( XFillStyleItem( drawing::FillStyle_NONE
) );
147 // create default line endings (like XLineEndList::Create)
148 // to be independent from the configured line endings
150 basegfx::B2DPolygon aTriangle
;
151 aTriangle
.append(basegfx::B2DPoint(10.0, 0.0));
152 aTriangle
.append(basegfx::B2DPoint(0.0, 30.0));
153 aTriangle
.append(basegfx::B2DPoint(20.0, 30.0));
154 aTriangle
.setClosed(true);
156 basegfx::B2DPolygon aSquare
;
157 aSquare
.append(basegfx::B2DPoint(0.0, 0.0));
158 aSquare
.append(basegfx::B2DPoint(10.0, 0.0));
159 aSquare
.append(basegfx::B2DPoint(10.0, 10.0));
160 aSquare
.append(basegfx::B2DPoint(0.0, 10.0));
161 aSquare
.setClosed(true);
163 basegfx::B2DPolygon
aCircle(basegfx::tools::createPolygonFromEllipse(basegfx::B2DPoint(0.0, 0.0), 100.0, 100.0));
164 aCircle
.setClosed(true);
166 OUString aName
= SC_LINEEND_NAME
;
168 aArrowSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aCircle
) ) );
169 aArrowSet
.Put( XLineStartWidthItem( 200 ) );
170 aArrowSet
.Put( XLineStartCenterItem( true ) );
171 aArrowSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
172 aArrowSet
.Put( XLineEndWidthItem( 200 ) );
173 aArrowSet
.Put( XLineEndCenterItem( false ) );
175 aToTabSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aCircle
) ) );
176 aToTabSet
.Put( XLineStartWidthItem( 200 ) );
177 aToTabSet
.Put( XLineStartCenterItem( true ) );
178 aToTabSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aSquare
) ) );
179 aToTabSet
.Put( XLineEndWidthItem( 300 ) );
180 aToTabSet
.Put( XLineEndCenterItem( false ) );
182 aFromTabSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aSquare
) ) );
183 aFromTabSet
.Put( XLineStartWidthItem( 300 ) );
184 aFromTabSet
.Put( XLineStartCenterItem( true ) );
185 aFromTabSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
186 aFromTabSet
.Put( XLineEndWidthItem( 200 ) );
187 aFromTabSet
.Put( XLineEndCenterItem( false ) );
189 aCircleSet
.Put( XLineColorItem( OUString(), Color( ScDetectiveFunc::GetErrorColor() ) ) );
190 aCircleSet
.Put( XFillStyleItem( drawing::FillStyle_NONE
) );
191 sal_uInt16 nWidth
= 55; // 54 = 1 Pixel
192 aCircleSet
.Put( XLineWidthItem( nWidth
) );
195 ScCommentData::ScCommentData( ScDocument
& rDoc
, SdrModel
* pModel
) :
196 aCaptionSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
, EE_ITEMS_START
, EE_ITEMS_END
, 0, 0 )
198 basegfx::B2DPolygon aTriangle
;
199 aTriangle
.append(basegfx::B2DPoint(10.0, 0.0));
200 aTriangle
.append(basegfx::B2DPoint(0.0, 30.0));
201 aTriangle
.append(basegfx::B2DPoint(20.0, 30.0));
202 aTriangle
.setClosed(true);
204 OUString aName
= SC_LINEEND_NAME
;
206 aCaptionSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
207 aCaptionSet
.Put( XLineStartWidthItem( 200 ) );
208 aCaptionSet
.Put( XLineStartCenterItem( false ) );
209 aCaptionSet
.Put( XFillStyleItem( drawing::FillStyle_SOLID
) );
210 Color
aYellow( ScDetectiveFunc::GetCommentColor() );
211 aCaptionSet
.Put( XFillColorItem( OUString(), aYellow
) );
214 // SdrShadowItem has sal_False, instead the shadow is set for the rectangle
215 // only with SetSpecialTextBoxShadow when the object is created
216 // (item must be set to adjust objects from older files)
217 aCaptionSet
.Put( makeSdrShadowItem( false ) );
218 aCaptionSet
.Put( makeSdrShadowXDistItem( 100 ) );
219 aCaptionSet
.Put( makeSdrShadowYDistItem( 100 ) );
222 aCaptionSet
.Put( makeSdrTextLeftDistItem( 100 ) );
223 aCaptionSet
.Put( makeSdrTextRightDistItem( 100 ) );
224 aCaptionSet
.Put( makeSdrTextUpperDistItem( 100 ) );
225 aCaptionSet
.Put( makeSdrTextLowerDistItem( 100 ) );
227 aCaptionSet
.Put( makeSdrTextAutoGrowWidthItem( false ) );
228 aCaptionSet
.Put( makeSdrTextAutoGrowHeightItem( true ) );
230 // do use the default cell style, so the user has a chance to
231 // modify the font for the annotations
232 static_cast<const ScPatternAttr
&>(rDoc
.GetPool()->GetDefaultItem(ATTR_PATTERN
)).
233 FillEditItemSet( &aCaptionSet
);
235 // support the best position for the tail connector now that
236 // that notes can be resized and repositioned.
237 aCaptionSet
.Put( SdrCaptionEscDirItem( SDRCAPT_ESCBESTFIT
) );
240 void ScCommentData::UpdateCaptionSet( const SfxItemSet
& rItemSet
)
242 SfxWhichIter
aWhichIter( rItemSet
);
243 const SfxPoolItem
* pPoolItem
= 0;
245 for( sal_uInt16 nWhich
= aWhichIter
.FirstWhich(); nWhich
> 0; nWhich
= aWhichIter
.NextWhich() )
247 if(rItemSet
.GetItemState(nWhich
, false, &pPoolItem
) == SfxItemState::SET
)
252 // use existing Caption default - appears that setting this
253 // to true screws up the tail appearance. See also comment
254 // for default setting above.
256 case SDRATTR_SHADOWXDIST
:
257 // use existing Caption default - svx sets a value of 35
258 // but default 100 gives a better appearance.
260 case SDRATTR_SHADOWYDIST
:
261 // use existing Caption default - svx sets a value of 35
262 // but default 100 gives a better appearance.
266 aCaptionSet
.Put(*pPoolItem
);
272 void ScDetectiveFunc::Modified()
274 if (pDoc
->IsStreamValid(nTab
))
275 pDoc
->SetStreamValid(nTab
, false);
278 inline bool Intersect( SCCOL nStartCol1
, SCROW nStartRow1
, SCCOL nEndCol1
, SCROW nEndRow1
,
279 SCCOL nStartCol2
, SCROW nStartRow2
, SCCOL nEndCol2
, SCROW nEndRow2
)
281 return nEndCol1
>= nStartCol2
&& nEndCol2
>= nStartCol1
&&
282 nEndRow1
>= nStartRow2
&& nEndRow2
>= nStartRow1
;
285 bool ScDetectiveFunc::HasError( const ScRange
& rRange
, ScAddress
& rErrPos
)
287 rErrPos
= rRange
.aStart
;
288 sal_uInt16 nError
= 0;
290 ScCellIterator
aIter( pDoc
, rRange
);
291 for (bool bHasCell
= aIter
.first(); bHasCell
; bHasCell
= aIter
.next())
293 if (aIter
.getType() != CELLTYPE_FORMULA
)
296 nError
= aIter
.getFormulaCell()->GetErrCode();
298 rErrPos
= aIter
.GetPos();
301 return (nError
!= 0);
304 Point
ScDetectiveFunc::GetDrawPos( SCCOL nCol
, SCROW nRow
, DrawPosMode eMode
) const
306 OSL_ENSURE( ValidColRow( nCol
, nRow
), "ScDetectiveFunc::GetDrawPos - invalid cell address" );
307 nCol
= SanitizeCol( nCol
);
308 nRow
= SanitizeRow( nRow
);
314 case DRAWPOS_TOPLEFT
:
316 case DRAWPOS_BOTTOMRIGHT
:
320 case DRAWPOS_DETARROW
:
321 aPos
.X() += pDoc
->GetColWidth( nCol
, nTab
) / 4;
322 aPos
.Y() += pDoc
->GetRowHeight( nRow
, nTab
) / 2;
324 case DRAWPOS_CAPTIONLEFT
:
327 case DRAWPOS_CAPTIONRIGHT
:
329 // find right end of passed cell position
330 const ScMergeAttr
* pMerge
= static_cast< const ScMergeAttr
* >( pDoc
->GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE
) );
331 if ( pMerge
->GetColMerge() > 1 )
332 nCol
= nCol
+ pMerge
->GetColMerge();
340 for ( SCCOL i
= 0; i
< nCol
; ++i
)
341 aPos
.X() += pDoc
->GetColWidth( i
, nTab
);
342 aPos
.Y() += pDoc
->GetRowHeight( 0, nRow
- 1, nTab
);
344 aPos
.X() = static_cast< long >( aPos
.X() * HMM_PER_TWIPS
);
345 aPos
.Y() = static_cast< long >( aPos
.Y() * HMM_PER_TWIPS
);
347 if ( pDoc
->IsNegativePage( nTab
) )
353 Rectangle
ScDetectiveFunc::GetDrawRect( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) const
356 GetDrawPos( ::std::min( nCol1
, nCol2
), ::std::min( nRow1
, nRow2
), DRAWPOS_TOPLEFT
),
357 GetDrawPos( ::std::max( nCol1
, nCol2
), ::std::max( nRow1
, nRow2
), DRAWPOS_BOTTOMRIGHT
) );
358 aRect
.Justify(); // reorder left/right in RTL sheets
362 Rectangle
ScDetectiveFunc::GetDrawRect( SCCOL nCol
, SCROW nRow
) const
364 return GetDrawRect( nCol
, nRow
, nCol
, nRow
);
367 static bool lcl_IsOtherTab( const basegfx::B2DPolyPolygon
& rPolyPolygon
)
369 // test if rPolygon is the line end for "other table" (rectangle)
370 if(1L == rPolyPolygon
.count())
372 const basegfx::B2DPolygon
aSubPoly(rPolyPolygon
.getB2DPolygon(0L));
374 // #i73305# circle consists of 4 segments, too, distinguishable from square by
375 // the use of control points
376 if(4L == aSubPoly
.count() && aSubPoly
.isClosed() && !aSubPoly
.areControlPointsUsed())
385 bool ScDetectiveFunc::HasArrow( const ScAddress
& rStart
,
386 SCCOL nEndCol
, SCROW nEndRow
, SCTAB nEndTab
)
388 bool bStartAlien
= ( rStart
.Tab() != nTab
);
389 bool bEndAlien
= ( nEndTab
!= nTab
);
391 if (bStartAlien
&& bEndAlien
)
393 OSL_FAIL("bStartAlien && bEndAlien");
397 Rectangle aStartRect
;
400 aStartRect
= GetDrawRect( rStart
.Col(), rStart
.Row() );
402 aEndRect
= GetDrawRect( nEndCol
, nEndRow
);
404 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
405 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
406 OSL_ENSURE(pPage
,"Page ?");
409 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
410 SdrObject
* pObject
= aIter
.Next();
411 while (pObject
&& !bFound
)
413 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
414 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
416 const SfxItemSet
& rSet
= pObject
->GetMergedItemSet();
418 bool bObjStartAlien
=
419 lcl_IsOtherTab( static_cast<const XLineStartItem
&>(rSet
.Get(XATTR_LINESTART
)).GetLineStartValue() );
421 lcl_IsOtherTab( static_cast<const XLineEndItem
&>(rSet
.Get(XATTR_LINEEND
)).GetLineEndValue() );
423 bool bStartHit
= bStartAlien
? bObjStartAlien
:
424 ( !bObjStartAlien
&& aStartRect
.IsInside(pObject
->GetPoint(0)) );
425 bool bEndHit
= bEndAlien
? bObjEndAlien
:
426 ( !bObjEndAlien
&& aEndRect
.IsInside(pObject
->GetPoint(1)) );
428 if ( bStartHit
&& bEndHit
)
431 pObject
= aIter
.Next();
437 bool ScDetectiveFunc::IsNonAlienArrow( SdrObject
* pObject
)
439 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
440 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
442 const SfxItemSet
& rSet
= pObject
->GetMergedItemSet();
444 bool bObjStartAlien
=
445 lcl_IsOtherTab( static_cast<const XLineStartItem
&>(rSet
.Get(XATTR_LINESTART
)).GetLineStartValue() );
447 lcl_IsOtherTab( static_cast<const XLineEndItem
&>(rSet
.Get(XATTR_LINEEND
)).GetLineEndValue() );
449 return !bObjStartAlien
&& !bObjEndAlien
;
455 // InsertXXX: called from DrawEntry/DrawAlienEntry and InsertObject
457 bool ScDetectiveFunc::InsertArrow( SCCOL nCol
, SCROW nRow
,
458 SCCOL nRefStartCol
, SCROW nRefStartRow
,
459 SCCOL nRefEndCol
, SCROW nRefEndRow
,
460 bool bFromOtherTab
, bool bRed
,
461 ScDetectiveData
& rData
)
463 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
464 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
466 bool bArea
= ( nRefStartCol
!= nRefEndCol
|| nRefStartRow
!= nRefEndRow
);
467 if (bArea
&& !bFromOtherTab
)
469 // insert the rectangle before the arrow - this is relied on in FindFrameForObject
471 Rectangle aRect
= GetDrawRect( nRefStartCol
, nRefStartRow
, nRefEndCol
, nRefEndRow
);
472 SdrRectObj
* pBox
= new SdrRectObj( aRect
);
474 pBox
->SetMergedItemSetAndBroadcast(rData
.GetBoxSet());
476 pBox
->SetLayer( SC_LAYER_INTERN
);
477 pPage
->InsertObject( pBox
);
478 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pBox
) );
480 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pBox
, true );
481 pData
->maStart
.Set( nRefStartCol
, nRefStartRow
, nTab
);
482 pData
->maEnd
.Set( nRefEndCol
, nRefEndRow
, nTab
);
485 Point aStartPos
= GetDrawPos( nRefStartCol
, nRefStartRow
, DRAWPOS_DETARROW
);
486 Point aEndPos
= GetDrawPos( nCol
, nRow
, DRAWPOS_DETARROW
);
490 bool bNegativePage
= pDoc
->IsNegativePage( nTab
);
491 long nPageSign
= bNegativePage
? -1 : 1;
493 aStartPos
= Point( aEndPos
.X() - 1000 * nPageSign
, aEndPos
.Y() - 1000 );
494 if (aStartPos
.X() * nPageSign
< 0)
495 aStartPos
.X() += 2000 * nPageSign
;
496 if (aStartPos
.Y() < 0)
497 aStartPos
.Y() += 2000;
500 SfxItemSet
& rAttrSet
= bFromOtherTab
? rData
.GetFromTabSet() : rData
.GetArrowSet();
502 if (bArea
&& !bFromOtherTab
)
503 rAttrSet
.Put( XLineWidthItem( 50 ) ); // range
505 rAttrSet
.Put( XLineWidthItem( 0 ) ); // single reference
507 ColorData nColorData
= ( bRed
? GetErrorColor() : GetArrowColor() );
508 rAttrSet
.Put( XLineColorItem( OUString(), Color( nColorData
) ) );
510 basegfx::B2DPolygon aTempPoly
;
511 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
512 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
513 SdrPathObj
* pArrow
= new SdrPathObj(OBJ_LINE
, basegfx::B2DPolyPolygon(aTempPoly
));
514 pArrow
->NbcSetLogicRect(Rectangle(aStartPos
,aEndPos
)); //TODO: needed ???
515 pArrow
->SetMergedItemSetAndBroadcast(rAttrSet
);
517 pArrow
->SetLayer( SC_LAYER_INTERN
);
518 pPage
->InsertObject( pArrow
);
519 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pArrow
) );
521 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pArrow
, true);
523 pData
->maStart
.SetInvalid();
525 pData
->maStart
.Set( nRefStartCol
, nRefStartRow
, nTab
);
527 pData
->maEnd
.Set( nCol
, nRow
, nTab
);
528 pData
->meType
= ScDrawObjData::DetectiveArrow
;
534 bool ScDetectiveFunc::InsertToOtherTab( SCCOL nStartCol
, SCROW nStartRow
,
535 SCCOL nEndCol
, SCROW nEndRow
, bool bRed
,
536 ScDetectiveData
& rData
)
538 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
539 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
541 bool bArea
= ( nStartCol
!= nEndCol
|| nStartRow
!= nEndRow
);
544 Rectangle aRect
= GetDrawRect( nStartCol
, nStartRow
, nEndCol
, nEndRow
);
545 SdrRectObj
* pBox
= new SdrRectObj( aRect
);
547 pBox
->SetMergedItemSetAndBroadcast(rData
.GetBoxSet());
549 pBox
->SetLayer( SC_LAYER_INTERN
);
550 pPage
->InsertObject( pBox
);
551 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pBox
) );
553 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pBox
, true );
554 pData
->maStart
.Set( nStartCol
, nStartRow
, nTab
);
555 pData
->maEnd
.Set( nEndCol
, nEndRow
, nTab
);
558 bool bNegativePage
= pDoc
->IsNegativePage( nTab
);
559 long nPageSign
= bNegativePage
? -1 : 1;
561 Point aStartPos
= GetDrawPos( nStartCol
, nStartRow
, DRAWPOS_DETARROW
);
562 Point aEndPos
= Point( aStartPos
.X() + 1000 * nPageSign
, aStartPos
.Y() - 1000 );
566 SfxItemSet
& rAttrSet
= rData
.GetToTabSet();
568 rAttrSet
.Put( XLineWidthItem( 50 ) ); // range
570 rAttrSet
.Put( XLineWidthItem( 0 ) ); // single reference
572 ColorData nColorData
= ( bRed
? GetErrorColor() : GetArrowColor() );
573 rAttrSet
.Put( XLineColorItem( OUString(), Color( nColorData
) ) );
575 basegfx::B2DPolygon aTempPoly
;
576 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
577 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
578 SdrPathObj
* pArrow
= new SdrPathObj(OBJ_LINE
, basegfx::B2DPolyPolygon(aTempPoly
));
579 pArrow
->NbcSetLogicRect(Rectangle(aStartPos
,aEndPos
)); //TODO: needed ???
581 pArrow
->SetMergedItemSetAndBroadcast(rAttrSet
);
583 pArrow
->SetLayer( SC_LAYER_INTERN
);
584 pPage
->InsertObject( pArrow
);
585 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pArrow
) );
587 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pArrow
, true );
588 pData
->maStart
.Set( nStartCol
, nStartRow
, nTab
);
589 pData
->maEnd
.SetInvalid();
595 // DrawEntry: formula from this spreadsheet,
596 // reference on this or other
597 // DrawAlienEntry: formula from other spreadsheet,
600 // return FALSE: there was already an arrow
602 bool ScDetectiveFunc::DrawEntry( SCCOL nCol
, SCROW nRow
,
604 ScDetectiveData
& rData
)
606 if ( HasArrow( rRef
.aStart
, nCol
, nRow
, nTab
) )
610 bool bError
= HasError( rRef
, aErrorPos
);
611 bool bAlien
= ( rRef
.aEnd
.Tab() < nTab
|| rRef
.aStart
.Tab() > nTab
);
613 return InsertArrow( nCol
, nRow
,
614 rRef
.aStart
.Col(), rRef
.aStart
.Row(),
615 rRef
.aEnd
.Col(), rRef
.aEnd
.Row(),
616 bAlien
, bError
, rData
);
619 bool ScDetectiveFunc::DrawAlienEntry( const ScRange
& rRef
,
620 ScDetectiveData
& rData
)
622 if ( HasArrow( rRef
.aStart
, 0, 0, nTab
+1 ) )
626 bool bError
= HasError( rRef
, aErrorPos
);
628 return InsertToOtherTab( rRef
.aStart
.Col(), rRef
.aStart
.Row(),
629 rRef
.aEnd
.Col(), rRef
.aEnd
.Row(),
633 void ScDetectiveFunc::DrawCircle( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
)
635 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
636 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
638 Rectangle aRect
= GetDrawRect( nCol
, nRow
);
640 aRect
.Right() += 250;
642 aRect
.Bottom() += 70;
644 SdrCircObj
* pCircle
= new SdrCircObj( OBJ_CIRC
, aRect
);
645 SfxItemSet
& rAttrSet
= rData
.GetCircleSet();
647 pCircle
->SetMergedItemSetAndBroadcast(rAttrSet
);
649 pCircle
->SetLayer( SC_LAYER_INTERN
);
650 pPage
->InsertObject( pCircle
);
651 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pCircle
) );
653 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pCircle
, true );
654 pData
->maStart
.Set( nCol
, nRow
, nTab
);
655 pData
->maEnd
.SetInvalid();
656 pData
->meType
= ScDrawObjData::ValidationCircle
;
661 void ScDetectiveFunc::DeleteArrowsAt( SCCOL nCol
, SCROW nRow
, bool bDestPnt
)
663 Rectangle aRect
= GetDrawRect( nCol
, nRow
);
665 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
666 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
667 OSL_ENSURE(pPage
,"Page ?");
669 pPage
->RecalcObjOrdNums();
671 const size_t nObjCount
= pPage
->GetObjCount();
674 size_t nDelCount
= 0;
675 boost::scoped_array
<SdrObject
*> ppObj(new SdrObject
*[nObjCount
]);
677 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
678 SdrObject
* pObject
= aIter
.Next();
681 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
682 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
684 if (aRect
.IsInside(pObject
->GetPoint(bDestPnt
? 1 : 0))) // start/destinationpoint
685 ppObj
[nDelCount
++] = pObject
;
688 pObject
= aIter
.Next();
691 for (size_t i
=1; i
<=nDelCount
; ++i
)
692 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
694 for (size_t i
=1; i
<=nDelCount
; ++i
)
695 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
703 // delete box around reference
705 #define SC_DET_TOLERANCE 50
707 inline bool RectIsPoints( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
709 return rRect
.Left() >= rStart
.X() - SC_DET_TOLERANCE
710 && rRect
.Left() <= rStart
.X() + SC_DET_TOLERANCE
711 && rRect
.Right() >= rEnd
.X() - SC_DET_TOLERANCE
712 && rRect
.Right() <= rEnd
.X() + SC_DET_TOLERANCE
713 && rRect
.Top() >= rStart
.Y() - SC_DET_TOLERANCE
714 && rRect
.Top() <= rStart
.Y() + SC_DET_TOLERANCE
715 && rRect
.Bottom() >= rEnd
.Y() - SC_DET_TOLERANCE
716 && rRect
.Bottom() <= rEnd
.Y() + SC_DET_TOLERANCE
;
719 #undef SC_DET_TOLERANCE
721 void ScDetectiveFunc::DeleteBox( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
723 Rectangle aCornerRect
= GetDrawRect( nCol1
, nRow1
, nCol2
, nRow2
);
724 Point aStartCorner
= aCornerRect
.TopLeft();
725 Point aEndCorner
= aCornerRect
.BottomRight();
728 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
729 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
730 OSL_ENSURE(pPage
,"Page ?");
732 pPage
->RecalcObjOrdNums();
734 const size_t nObjCount
= pPage
->GetObjCount();
737 size_t nDelCount
= 0;
738 boost::scoped_array
<SdrObject
*> ppObj(new SdrObject
*[nObjCount
]);
740 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
741 SdrObject
* pObject
= aIter
.Next();
744 if ( pObject
->GetLayer() == SC_LAYER_INTERN
&&
745 pObject
->Type() == TYPE(SdrRectObj
) )
747 aObjRect
= static_cast<SdrRectObj
*>(pObject
)->GetLogicRect();
749 if ( RectIsPoints( aObjRect
, aStartCorner
, aEndCorner
) )
750 ppObj
[nDelCount
++] = pObject
;
753 pObject
= aIter
.Next();
756 for (size_t i
=1; i
<=nDelCount
; ++i
)
757 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
759 for (size_t i
=1; i
<=nDelCount
; ++i
)
760 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
768 sal_uInt16
ScDetectiveFunc::InsertPredLevelArea( const ScRange
& rRef
,
769 ScDetectiveData
& rData
, sal_uInt16 nLevel
)
771 sal_uInt16 nResult
= DET_INS_EMPTY
;
773 ScCellIterator
aIter( pDoc
, rRef
);
774 for (bool bHasCell
= aIter
.first(); bHasCell
; bHasCell
= aIter
.next())
776 if (aIter
.getType() != CELLTYPE_FORMULA
)
779 const ScAddress
& rPos
= aIter
.GetPos();
780 switch (InsertPredLevel(rPos
.Col(), rPos
.Row(), rData
, nLevel
))
782 case DET_INS_INSERTED
:
783 nResult
= DET_INS_INSERTED
;
785 case DET_INS_CONTINUE
:
786 if (nResult
!= DET_INS_INSERTED
)
787 nResult
= DET_INS_CONTINUE
;
789 case DET_INS_CIRCULAR
:
790 if (nResult
== DET_INS_EMPTY
)
791 nResult
= DET_INS_CIRCULAR
;
801 sal_uInt16
ScDetectiveFunc::InsertPredLevel( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
,
804 ScRefCellValue aCell
;
805 aCell
.assign(*pDoc
, ScAddress(nCol
, nRow
, nTab
));
806 if (aCell
.meType
!= CELLTYPE_FORMULA
)
807 return DET_INS_EMPTY
;
809 ScFormulaCell
* pFCell
= aCell
.mpFormula
;
810 if (pFCell
->IsRunning())
811 return DET_INS_CIRCULAR
;
813 if (pFCell
->GetDirty())
814 pFCell
->Interpret(); // can't be called after SetRunning
815 pFCell
->SetRunning(true);
817 sal_uInt16 nResult
= DET_INS_EMPTY
;
819 ScDetectiveRefIter
aIter(pFCell
);
821 while ( aIter
.GetNextRef( aRef
) )
823 if (DrawEntry( nCol
, nRow
, aRef
, rData
))
825 nResult
= DET_INS_INSERTED
; // insert new arrow
831 if ( nLevel
< rData
.GetMaxLevel() )
833 sal_uInt16 nSubResult
;
834 bool bArea
= (aRef
.aStart
!= aRef
.aEnd
);
836 nSubResult
= InsertPredLevelArea( aRef
, rData
, nLevel
+1 );
838 nSubResult
= InsertPredLevel( aRef
.aStart
.Col(), aRef
.aStart
.Row(),
843 case DET_INS_INSERTED
:
844 nResult
= DET_INS_INSERTED
;
846 case DET_INS_CONTINUE
:
847 if (nResult
!= DET_INS_INSERTED
)
848 nResult
= DET_INS_CONTINUE
;
850 case DET_INS_CIRCULAR
:
851 if (nResult
== DET_INS_EMPTY
)
852 nResult
= DET_INS_CIRCULAR
;
854 // DET_INS_EMPTY: no change
857 else // nMaxLevel reached
858 if (nResult
!= DET_INS_INSERTED
)
859 nResult
= DET_INS_CONTINUE
;
863 pFCell
->SetRunning(false);
868 sal_uInt16
ScDetectiveFunc::FindPredLevelArea( const ScRange
& rRef
,
869 sal_uInt16 nLevel
, sal_uInt16 nDeleteLevel
)
871 sal_uInt16 nResult
= nLevel
;
873 ScCellIterator
aCellIter( pDoc
, rRef
);
874 for (bool bHasCell
= aCellIter
.first(); bHasCell
; bHasCell
= aCellIter
.next())
876 if (aCellIter
.getType() != CELLTYPE_FORMULA
)
879 sal_uInt16 nTemp
= FindPredLevel(aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(), nLevel
, nDeleteLevel
);
887 // nDeleteLevel != 0 -> delete
889 sal_uInt16
ScDetectiveFunc::FindPredLevel( SCCOL nCol
, SCROW nRow
, sal_uInt16 nLevel
, sal_uInt16 nDeleteLevel
)
891 OSL_ENSURE( nLevel
<1000, "Level" );
893 ScRefCellValue aCell
;
894 aCell
.assign(*pDoc
, ScAddress(nCol
, nRow
, nTab
));
895 if (aCell
.meType
!= CELLTYPE_FORMULA
)
898 ScFormulaCell
* pFCell
= aCell
.mpFormula
;
899 if (pFCell
->IsRunning())
902 if (pFCell
->GetDirty())
903 pFCell
->Interpret(); // can't be called after SetRunning
904 pFCell
->SetRunning(true);
906 sal_uInt16 nResult
= nLevel
;
907 bool bDelete
= ( nDeleteLevel
&& nLevel
== nDeleteLevel
-1 );
911 DeleteArrowsAt( nCol
, nRow
, true ); // arrows, that are pointing here
914 ScDetectiveRefIter
aIter(pFCell
);
916 while ( aIter
.GetNextRef( aRef
) )
918 bool bArea
= ( aRef
.aStart
!= aRef
.aEnd
);
920 if ( bDelete
) // delete frame ?
924 DeleteBox( aRef
.aStart
.Col(), aRef
.aStart
.Row(), aRef
.aEnd
.Col(), aRef
.aEnd
.Row() );
927 else // continue searching
929 if ( HasArrow( aRef
.aStart
, nCol
,nRow
,nTab
) )
933 nTemp
= FindPredLevelArea( aRef
, nLevel
+1, nDeleteLevel
);
935 nTemp
= FindPredLevel( aRef
.aStart
.Col(),aRef
.aStart
.Row(),
936 nLevel
+1, nDeleteLevel
);
943 pFCell
->SetRunning(false);
948 sal_uInt16
ScDetectiveFunc::InsertErrorLevel( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
,
951 ScRefCellValue aCell
;
952 aCell
.assign(*pDoc
, ScAddress(nCol
, nRow
, nTab
));
953 if (aCell
.meType
!= CELLTYPE_FORMULA
)
954 return DET_INS_EMPTY
;
956 ScFormulaCell
* pFCell
= aCell
.mpFormula
;
957 if (pFCell
->IsRunning())
958 return DET_INS_CIRCULAR
;
960 if (pFCell
->GetDirty())
961 pFCell
->Interpret(); // can't be called after SetRunning
962 pFCell
->SetRunning(true);
964 sal_uInt16 nResult
= DET_INS_EMPTY
;
966 ScDetectiveRefIter
aIter(pFCell
);
969 bool bHasError
= false;
970 while ( aIter
.GetNextRef( aRef
) )
972 if (HasError( aRef
, aErrorPos
))
975 if (DrawEntry( nCol
, nRow
, ScRange( aErrorPos
), rData
))
976 nResult
= DET_INS_INSERTED
;
978 if ( nLevel
< rData
.GetMaxLevel() ) // hits most of the time
980 if (InsertErrorLevel( aErrorPos
.Col(), aErrorPos
.Row(),
981 rData
, nLevel
+1 ) == DET_INS_INSERTED
)
982 nResult
= DET_INS_INSERTED
;
987 pFCell
->SetRunning(false);
991 if (InsertPredLevel( nCol
, nRow
, rData
, rData
.GetMaxLevel() ) == DET_INS_INSERTED
)
992 nResult
= DET_INS_INSERTED
;
997 sal_uInt16
ScDetectiveFunc::InsertSuccLevel( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
998 ScDetectiveData
& rData
, sal_uInt16 nLevel
)
1000 // over the entire document.
1002 sal_uInt16 nResult
= DET_INS_EMPTY
;
1003 ScCellIterator
aCellIter(pDoc
, ScRange(0,0,0,MAXCOL
,MAXROW
,MAXTAB
)); // all sheets
1004 for (bool bHas
= aCellIter
.first(); bHas
; bHas
= aCellIter
.next())
1006 if (aCellIter
.getType() != CELLTYPE_FORMULA
)
1009 ScFormulaCell
* pFCell
= aCellIter
.getFormulaCell();
1010 bool bRunning
= pFCell
->IsRunning();
1012 if (pFCell
->GetDirty())
1013 pFCell
->Interpret(); // can't be called after SetRunning
1014 pFCell
->SetRunning(true);
1016 ScDetectiveRefIter
aIter(pFCell
);
1018 while ( aIter
.GetNextRef( aRef
) )
1020 if (aRef
.aStart
.Tab() <= nTab
&& aRef
.aEnd
.Tab() >= nTab
)
1022 if (Intersect( nCol1
,nRow1
,nCol2
,nRow2
,
1023 aRef
.aStart
.Col(),aRef
.aStart
.Row(),
1024 aRef
.aEnd
.Col(),aRef
.aEnd
.Row() ))
1026 bool bAlien
= ( aCellIter
.GetPos().Tab() != nTab
);
1029 bDrawRet
= DrawAlienEntry( aRef
, rData
);
1031 bDrawRet
= DrawEntry( aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1035 nResult
= DET_INS_INSERTED
; // insert new arrow
1041 if (nResult
== DET_INS_EMPTY
)
1042 nResult
= DET_INS_CIRCULAR
;
1047 if ( nLevel
< rData
.GetMaxLevel() )
1049 sal_uInt16 nSubResult
= InsertSuccLevel(
1050 aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1051 aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1055 case DET_INS_INSERTED
:
1056 nResult
= DET_INS_INSERTED
;
1058 case DET_INS_CONTINUE
:
1059 if (nResult
!= DET_INS_INSERTED
)
1060 nResult
= DET_INS_CONTINUE
;
1062 case DET_INS_CIRCULAR
:
1063 if (nResult
== DET_INS_EMPTY
)
1064 nResult
= DET_INS_CIRCULAR
;
1066 // DET_INS_EMPTY: leave unchanged
1069 else // nMaxLevel reached
1070 if (nResult
!= DET_INS_INSERTED
)
1071 nResult
= DET_INS_CONTINUE
;
1077 pFCell
->SetRunning(bRunning
);
1083 sal_uInt16
ScDetectiveFunc::FindSuccLevel( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1084 sal_uInt16 nLevel
, sal_uInt16 nDeleteLevel
)
1086 OSL_ENSURE( nLevel
<1000, "Level" );
1088 sal_uInt16 nResult
= nLevel
;
1089 bool bDelete
= ( nDeleteLevel
&& nLevel
== nDeleteLevel
-1 );
1091 ScCellIterator
aCellIter( pDoc
, ScRange(0, 0, nTab
, MAXCOL
, MAXROW
, nTab
) );
1092 for (bool bHas
= aCellIter
.first(); bHas
; bHas
= aCellIter
.next())
1094 if (aCellIter
.getType() != CELLTYPE_FORMULA
)
1097 ScFormulaCell
* pFCell
= aCellIter
.getFormulaCell();
1098 bool bRunning
= pFCell
->IsRunning();
1100 if (pFCell
->GetDirty())
1101 pFCell
->Interpret(); // can't be called after SetRunning
1102 pFCell
->SetRunning(true);
1104 ScDetectiveRefIter
aIter(pFCell
);
1106 while ( aIter
.GetNextRef( aRef
) )
1108 if (aRef
.aStart
.Tab() <= nTab
&& aRef
.aEnd
.Tab() >= nTab
)
1110 if (Intersect( nCol1
,nRow1
,nCol2
,nRow2
,
1111 aRef
.aStart
.Col(),aRef
.aStart
.Row(),
1112 aRef
.aEnd
.Col(),aRef
.aEnd
.Row() ))
1114 if ( bDelete
) // arrows, that are starting here
1116 if (aRef
.aStart
!= aRef
.aEnd
)
1118 DeleteBox( aRef
.aStart
.Col(), aRef
.aStart
.Row(),
1119 aRef
.aEnd
.Col(), aRef
.aEnd
.Row() );
1121 DeleteArrowsAt( aRef
.aStart
.Col(), aRef
.aStart
.Row(), false );
1123 else if ( !bRunning
&&
1124 HasArrow( aRef
.aStart
,
1125 aCellIter
.GetPos().Col(),aCellIter
.GetPos().Row(),aCellIter
.GetPos().Tab() ) )
1127 sal_uInt16 nTemp
= FindSuccLevel( aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1128 aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1129 nLevel
+1, nDeleteLevel
);
1130 if (nTemp
> nResult
)
1137 pFCell
->SetRunning(bRunning
);
1143 bool ScDetectiveFunc::ShowPred( SCCOL nCol
, SCROW nRow
)
1145 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1149 ScDetectiveData
aData( pModel
);
1151 sal_uInt16 nMaxLevel
= 0;
1152 sal_uInt16 nResult
= DET_INS_CONTINUE
;
1153 while (nResult
== DET_INS_CONTINUE
&& nMaxLevel
< 1000)
1155 aData
.SetMaxLevel( nMaxLevel
);
1156 nResult
= InsertPredLevel( nCol
, nRow
, aData
, 0 );
1160 return ( nResult
== DET_INS_INSERTED
);
1163 bool ScDetectiveFunc::ShowSucc( SCCOL nCol
, SCROW nRow
)
1165 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1169 ScDetectiveData
aData( pModel
);
1171 sal_uInt16 nMaxLevel
= 0;
1172 sal_uInt16 nResult
= DET_INS_CONTINUE
;
1173 while (nResult
== DET_INS_CONTINUE
&& nMaxLevel
< 1000)
1175 aData
.SetMaxLevel( nMaxLevel
);
1176 nResult
= InsertSuccLevel( nCol
, nRow
, nCol
, nRow
, aData
, 0 );
1180 return ( nResult
== DET_INS_INSERTED
);
1183 bool ScDetectiveFunc::ShowError( SCCOL nCol
, SCROW nRow
)
1185 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1189 ScRange
aRange( nCol
, nRow
, nTab
);
1191 if ( !HasError( aRange
,aErrPos
) )
1194 ScDetectiveData
aData( pModel
);
1196 aData
.SetMaxLevel( 1000 );
1197 sal_uInt16 nResult
= InsertErrorLevel( nCol
, nRow
, aData
, 0 );
1199 return ( nResult
== DET_INS_INSERTED
);
1202 bool ScDetectiveFunc::DeleteSucc( SCCOL nCol
, SCROW nRow
)
1204 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1208 sal_uInt16 nLevelCount
= FindSuccLevel( nCol
, nRow
, nCol
, nRow
, 0, 0 );
1210 FindSuccLevel( nCol
, nRow
, nCol
, nRow
, 0, nLevelCount
); // delete
1212 return ( nLevelCount
!= 0 );
1215 bool ScDetectiveFunc::DeletePred( SCCOL nCol
, SCROW nRow
)
1217 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1221 sal_uInt16 nLevelCount
= FindPredLevel( nCol
, nRow
, 0, 0 );
1223 FindPredLevel( nCol
, nRow
, 0, nLevelCount
); // delete
1225 return ( nLevelCount
!= 0 );
1228 bool ScDetectiveFunc::DeleteAll( ScDetectiveDelete eWhat
)
1230 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1234 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
1235 OSL_ENSURE(pPage
,"Page ?");
1237 pPage
->RecalcObjOrdNums();
1239 size_t nDelCount
= 0;
1240 const size_t nObjCount
= pPage
->GetObjCount();
1243 boost::scoped_array
<SdrObject
*> ppObj(new SdrObject
*[nObjCount
]);
1245 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1246 SdrObject
* pObject
= aIter
.Next();
1249 if ( pObject
->GetLayer() == SC_LAYER_INTERN
)
1251 bool bDoThis
= true;
1252 if ( eWhat
!= SC_DET_ALL
)
1254 bool bCircle
= ( pObject
->ISA(SdrCircObj
) );
1255 bool bCaption
= ScDrawLayer::IsNoteCaption( pObject
);
1256 if ( eWhat
== SC_DET_DETECTIVE
) // detektive, from menue
1257 bDoThis
= !bCaption
; // also circles
1258 else if ( eWhat
== SC_DET_CIRCLES
) // circles, if new created
1260 else if ( eWhat
== SC_DET_ARROWS
) // DetectiveRefresh
1261 bDoThis
= !bCaption
&& !bCircle
; // don't include circles
1268 ppObj
[nDelCount
++] = pObject
;
1271 pObject
= aIter
.Next();
1274 for (size_t i
=1; i
<=nDelCount
; ++i
)
1275 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
1277 for (size_t i
=1; i
<=nDelCount
; ++i
)
1278 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
1285 return ( nDelCount
!= 0 );
1288 bool ScDetectiveFunc::MarkInvalid(bool& rOverflow
)
1291 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1295 bool bDeleted
= DeleteAll( SC_DET_CIRCLES
); // just circles
1297 ScDetectiveData
aData( pModel
);
1300 // search for valid places
1301 ScDocAttrIterator
aAttrIter( pDoc
, nTab
, 0,0,MAXCOL
,MAXROW
);
1305 const ScPatternAttr
* pPattern
= aAttrIter
.GetNext( nCol
, nRow1
, nRow2
);
1306 while ( pPattern
&& nInsCount
< SC_DET_MAXCIRCLE
)
1308 sal_uLong nIndex
= static_cast<const SfxUInt32Item
&>(pPattern
->GetItem(ATTR_VALIDDATA
)).GetValue();
1311 const ScValidationData
* pData
= pDoc
->GetValidationEntry( nIndex
);
1314 // pass cells in this area
1316 bool bMarkEmpty
= !pData
->IsIgnoreBlank();
1317 SCROW nNextRow
= nRow1
;
1319 ScCellIterator
aCellIter( pDoc
, ScRange(nCol
, nRow1
, nTab
, nCol
, nRow2
, nTab
) );
1320 for (bool bHas
= aCellIter
.first(); bHas
&& nInsCount
< SC_DET_MAXCIRCLE
; bHas
= aCellIter
.next())
1322 SCROW nCellRow
= aCellIter
.GetPos().Row();
1324 for ( nRow
= nNextRow
; nRow
< nCellRow
&& nInsCount
< SC_DET_MAXCIRCLE
; nRow
++ )
1326 DrawCircle( nCol
, nRow
, aData
);
1329 ScRefCellValue aCell
= aCellIter
.getRefCellValue();
1330 if (!pData
->IsDataValid(aCell
, aCellIter
.GetPos()))
1332 DrawCircle( nCol
, nCellRow
, aData
);
1335 nNextRow
= nCellRow
+ 1;
1338 for ( nRow
= nNextRow
; nRow
<= nRow2
&& nInsCount
< SC_DET_MAXCIRCLE
; nRow
++ )
1340 DrawCircle( nCol
, nRow
, aData
);
1346 pPattern
= aAttrIter
.GetNext( nCol
, nRow1
, nRow2
);
1349 if ( nInsCount
>= SC_DET_MAXCIRCLE
)
1352 return ( bDeleted
|| nInsCount
!= 0 );
1355 void ScDetectiveFunc::GetAllPreds(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1356 vector
<ScTokenRef
>& rRefTokens
)
1358 ScCellIterator
aIter(pDoc
, ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
));
1359 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
1361 if (aIter
.getType() != CELLTYPE_FORMULA
)
1364 ScFormulaCell
* pFCell
= aIter
.getFormulaCell();
1365 ScDetectiveRefIter
aRefIter(pFCell
);
1366 for (formula::FormulaToken
* p
= aRefIter
.GetNextRefToken(); p
; p
= aRefIter
.GetNextRefToken())
1368 ScTokenRef
pRef(p
->Clone());
1369 ScRefTokenHelper::join(rRefTokens
, pRef
, aIter
.GetPos());
1374 void ScDetectiveFunc::GetAllSuccs(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1375 vector
<ScTokenRef
>& rRefTokens
)
1377 vector
<ScTokenRef
> aSrcRange
;
1378 aSrcRange
.push_back(
1379 ScRefTokenHelper::createRefToken(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
)));
1381 ScCellIterator
aIter(pDoc
, ScRange(0, 0, nTab
, MAXCOL
, MAXROW
, nTab
));
1382 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
1384 if (aIter
.getType() != CELLTYPE_FORMULA
)
1387 ScFormulaCell
* pFCell
= aIter
.getFormulaCell();
1388 ScDetectiveRefIter
aRefIter(pFCell
);
1389 for (formula::FormulaToken
* p
= aRefIter
.GetNextRefToken(); p
; p
= aRefIter
.GetNextRefToken())
1391 const ScAddress
& aPos
= aIter
.GetPos();
1392 ScTokenRef
pRef(p
->Clone());
1393 if (ScRefTokenHelper::intersects(aSrcRange
, pRef
, aPos
))
1395 // This address is absolute.
1396 pRef
= ScRefTokenHelper::createRefToken(aPos
);
1397 ScRefTokenHelper::join(rRefTokens
, pRef
, ScAddress());
1403 void ScDetectiveFunc::UpdateAllComments( ScDocument
& rDoc
)
1405 // for all caption objects, update attributes and SpecialTextBoxShadow flag
1406 // (on all tables - nTab is ignored!)
1408 // no undo actions, this is refreshed after undo
1410 ScDrawLayer
* pModel
= rDoc
.GetDrawLayer();
1414 for( SCTAB nObjTab
= 0, nTabCount
= rDoc
.GetTableCount(); nObjTab
< nTabCount
; ++nObjTab
)
1416 SdrPage
* pPage
= pModel
->GetPage( static_cast< sal_uInt16
>( nObjTab
) );
1417 OSL_ENSURE( pPage
, "Page ?" );
1420 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1421 for( SdrObject
* pObject
= aIter
.Next(); pObject
; pObject
= aIter
.Next() )
1423 if ( ScDrawObjData
* pData
= ScDrawLayer::GetNoteCaptionData( pObject
, nObjTab
) )
1425 ScPostIt
* pNote
= rDoc
.GetNote( pData
->maStart
);
1426 // caption should exist, we iterate over drawing objects...
1427 OSL_ENSURE( pNote
&& (pNote
->GetCaption() == pObject
), "ScDetectiveFunc::UpdateAllComments - invalid cell note" );
1430 ScCommentData
aData( rDoc
, pModel
);
1431 SfxItemSet aAttrColorSet
= pObject
->GetMergedItemSet();
1432 aAttrColorSet
.Put( XFillColorItem( OUString(), GetCommentColor() ) );
1433 aData
.UpdateCaptionSet( aAttrColorSet
);
1434 pObject
->SetMergedItemSetAndBroadcast( aData
.GetCaptionSet() );
1435 if( SdrCaptionObj
* pCaption
= dynamic_cast< SdrCaptionObj
* >( pObject
) )
1437 pCaption
->SetSpecialTextBoxShadow();
1438 pCaption
->SetFixedTail();
1447 void ScDetectiveFunc::UpdateAllArrowColors()
1449 // no undo actions necessary
1451 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1455 for( SCTAB nObjTab
= 0, nTabCount
= pDoc
->GetTableCount(); nObjTab
< nTabCount
; ++nObjTab
)
1457 SdrPage
* pPage
= pModel
->GetPage( static_cast< sal_uInt16
>( nObjTab
) );
1458 OSL_ENSURE( pPage
, "Page ?" );
1461 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1462 for( SdrObject
* pObject
= aIter
.Next(); pObject
; pObject
= aIter
.Next() )
1464 if ( pObject
->GetLayer() == SC_LAYER_INTERN
)
1466 bool bArrow
= false;
1467 bool bError
= false;
1472 ScDetectiveObjType eType
= GetDetectiveObjectType( pObject
, nObjTab
, aPos
, aSource
, bDummy
);
1473 if ( eType
== SC_DETOBJ_ARROW
|| eType
== SC_DETOBJ_TOOTHERTAB
)
1475 // source is valid, determine error flag from source range
1478 if ( HasError( aSource
, aErrPos
) )
1483 else if ( eType
== SC_DETOBJ_FROMOTHERTAB
)
1485 // source range is no longer known, take error flag from formula itself
1486 // (this means, if the formula has an error, all references to other tables
1490 if ( HasError( ScRange( aPos
), aErrPos
) )
1495 else if ( eType
== SC_DETOBJ_CIRCLE
)
1497 // circles (error marks) are always red
1501 else if ( eType
== SC_DETOBJ_NONE
)
1503 // frame for area reference has no ObjType, always gets arrow color
1505 if ( pObject
->ISA( SdrRectObj
) && !pObject
->ISA( SdrCaptionObj
) )
1511 if ( bArrow
|| bError
)
1513 ColorData nColorData
= ( bError
? GetErrorColor() : GetArrowColor() );
1514 pObject
->SetMergedItem( XLineColorItem( OUString(), Color( nColorData
) ) );
1517 pObject
->ActionChanged();
1525 bool ScDetectiveFunc::FindFrameForObject( SdrObject
* pObject
, ScRange
& rRange
)
1527 // find the rectangle for an arrow (always the object directly before the arrow)
1528 // rRange must be initialized to the source cell of the arrow (start of area)
1530 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1531 if (!pModel
) return false;
1533 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
1534 OSL_ENSURE(pPage
,"Page ?");
1535 if (!pPage
) return false;
1537 // test if the object is a direct page member
1538 if( pObject
&& pObject
->GetPage() && (pObject
->GetPage() == pObject
->GetObjList()) )
1540 // Is there a previous object?
1541 const size_t nOrdNum
= pObject
->GetOrdNum();
1545 SdrObject
* pPrevObj
= pPage
->GetObj(nOrdNum
- 1);
1547 if ( pPrevObj
&& pPrevObj
->GetLayer() == SC_LAYER_INTERN
&& pPrevObj
->ISA(SdrRectObj
) )
1549 ScDrawObjData
* pPrevData
= ScDrawLayer::GetObjDataTab( pPrevObj
, rRange
.aStart
.Tab() );
1550 if ( pPrevData
&& pPrevData
->maStart
.IsValid() && pPrevData
->maEnd
.IsValid() && (pPrevData
->maStart
== rRange
.aStart
) )
1552 rRange
.aEnd
= pPrevData
->maEnd
;
1561 ScDetectiveObjType
ScDetectiveFunc::GetDetectiveObjectType( SdrObject
* pObject
, SCTAB nObjTab
,
1562 ScAddress
& rPosition
, ScRange
& rSource
, bool& rRedLine
)
1565 ScDetectiveObjType eType
= SC_DETOBJ_NONE
;
1567 if ( pObject
&& pObject
->GetLayer() == SC_LAYER_INTERN
)
1569 if ( ScDrawObjData
* pData
= ScDrawLayer::GetObjDataTab( pObject
, nObjTab
) )
1571 bool bValidStart
= pData
->maStart
.IsValid();
1572 bool bValidEnd
= pData
->maEnd
.IsValid();
1574 if ( pObject
->IsPolyObj() && pObject
->GetPointCount() == 2 )
1576 // line object -> arrow
1579 eType
= bValidEnd
? SC_DETOBJ_ARROW
: SC_DETOBJ_TOOTHERTAB
;
1580 else if ( bValidEnd
)
1581 eType
= SC_DETOBJ_FROMOTHERTAB
;
1584 rSource
= pData
->maStart
;
1586 rPosition
= pData
->maEnd
;
1588 if ( bValidStart
&& lcl_HasThickLine( *pObject
) )
1590 // thick line -> look for frame before this object
1592 FindFrameForObject( pObject
, rSource
); // modifies rSource
1595 ColorData nObjColor
= static_cast<const XLineColorItem
&>(pObject
->GetMergedItem(XATTR_LINECOLOR
)).GetColorValue().GetColor();
1596 if ( nObjColor
== GetErrorColor() && nObjColor
!= GetArrowColor() )
1599 else if ( pObject
->ISA(SdrCircObj
) )
1603 // cell position is returned in rPosition
1605 rPosition
= pData
->maStart
;
1606 eType
= SC_DETOBJ_CIRCLE
;
1615 void ScDetectiveFunc::InsertObject( ScDetectiveObjType eType
,
1616 const ScAddress
& rPosition
, const ScRange
& rSource
,
1619 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1620 if (!pModel
) return;
1621 ScDetectiveData
aData( pModel
);
1625 case SC_DETOBJ_ARROW
:
1626 case SC_DETOBJ_FROMOTHERTAB
:
1627 InsertArrow( rPosition
.Col(), rPosition
.Row(),
1628 rSource
.aStart
.Col(), rSource
.aStart
.Row(),
1629 rSource
.aEnd
.Col(), rSource
.aEnd
.Row(),
1630 (eType
== SC_DETOBJ_FROMOTHERTAB
), bRedLine
, aData
);
1632 case SC_DETOBJ_TOOTHERTAB
:
1633 InsertToOtherTab( rSource
.aStart
.Col(), rSource
.aStart
.Row(),
1634 rSource
.aEnd
.Col(), rSource
.aEnd
.Row(),
1637 case SC_DETOBJ_CIRCLE
:
1638 DrawCircle( rPosition
.Col(), rPosition
.Row(), aData
);
1642 // added to avoid warnings
1647 ColorData
ScDetectiveFunc::GetArrowColor()
1649 if (!bColorsInitialized
)
1654 ColorData
ScDetectiveFunc::GetErrorColor()
1656 if (!bColorsInitialized
)
1661 ColorData
ScDetectiveFunc::GetCommentColor()
1663 if (!bColorsInitialized
)
1665 return nCommentColor
;
1668 void ScDetectiveFunc::InitializeColors()
1670 // may be called several times to update colors from configuration
1672 const svtools::ColorConfig
& rColorCfg
= SC_MOD()->GetColorConfig();
1673 nArrowColor
= rColorCfg
.GetColorValue(svtools::CALCDETECTIVE
).nColor
;
1674 nErrorColor
= rColorCfg
.GetColorValue(svtools::CALCDETECTIVEERROR
).nColor
;
1675 nCommentColor
= rColorCfg
.GetColorValue(svtools::CALCNOTESBACKGROUND
).nColor
;
1677 bColorsInitialized
= true;
1680 bool ScDetectiveFunc::IsColorsInitialized()
1682 return bColorsInitialized
;
1685 void ScDetectiveFunc::AppendChangTrackNoteSeparator(OUString
&rDisplay
)
1687 rDisplay
+= "\n--------\n";
1690 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */