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"
76 // line ends are now created with an empty name.
77 // The checkForUniqueItem method then finds a unique name for the item's value.
78 #define SC_LINEEND_NAME EMPTY_OUSTRING
80 enum DetInsertResult
{ // Return-Werte beim Einfuegen in einen Level
92 SfxItemSet aFromTabSet
;
93 SfxItemSet aCircleSet
; //! einzeln ?
97 ScDetectiveData( SdrModel
* pModel
);
99 SfxItemSet
& GetBoxSet() { return aBoxSet
; }
100 SfxItemSet
& GetArrowSet() { return aArrowSet
; }
101 SfxItemSet
& GetToTabSet() { return aToTabSet
; }
102 SfxItemSet
& GetFromTabSet() { return aFromTabSet
; }
103 SfxItemSet
& GetCircleSet() { return aCircleSet
; }
105 void SetMaxLevel( sal_uInt16 nVal
) { nMaxLevel
= nVal
; }
106 sal_uInt16
GetMaxLevel() const { return nMaxLevel
; }
112 ScCommentData( ScDocument
& rDoc
, SdrModel
* pModel
);
114 SfxItemSet
& GetCaptionSet() { return aCaptionSet
; }
115 void UpdateCaptionSet( const SfxItemSet
& rItemSet
);
118 SfxItemSet aCaptionSet
;
121 ColorData
ScDetectiveFunc::nArrowColor
= 0;
122 ColorData
ScDetectiveFunc::nErrorColor
= 0;
123 ColorData
ScDetectiveFunc::nCommentColor
= 0;
124 sal_Bool
ScDetectiveFunc::bColorsInitialized
= false;
126 static sal_Bool
lcl_HasThickLine( SdrObject
& rObj
)
128 // thin lines get width 0 -> everything greater 0 is a thick line
130 return ( ((const XLineWidthItem
&)rObj
.GetMergedItem(XATTR_LINEWIDTH
)).GetValue() > 0 );
133 ScDetectiveData::ScDetectiveData( SdrModel
* pModel
) :
134 aBoxSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
135 aArrowSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
136 aToTabSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
137 aFromTabSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
138 aCircleSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
)
142 aBoxSet
.Put( XLineColorItem( EMPTY_OUSTRING
, Color( ScDetectiveFunc::GetArrowColor() ) ) );
143 aBoxSet
.Put( XFillStyleItem( XFILL_NONE
) );
145 // Standard-Linienenden (wie aus XLineEndList::Create) selber zusammenbasteln,
146 // um von den konfigurierten Linienenden unabhaengig zu sein
148 basegfx::B2DPolygon aTriangle
;
149 aTriangle
.append(basegfx::B2DPoint(10.0, 0.0));
150 aTriangle
.append(basegfx::B2DPoint(0.0, 30.0));
151 aTriangle
.append(basegfx::B2DPoint(20.0, 30.0));
152 aTriangle
.setClosed(true);
154 basegfx::B2DPolygon aSquare
;
155 aSquare
.append(basegfx::B2DPoint(0.0, 0.0));
156 aSquare
.append(basegfx::B2DPoint(10.0, 0.0));
157 aSquare
.append(basegfx::B2DPoint(10.0, 10.0));
158 aSquare
.append(basegfx::B2DPoint(0.0, 10.0));
159 aSquare
.setClosed(true);
161 basegfx::B2DPolygon
aCircle(basegfx::tools::createPolygonFromEllipse(basegfx::B2DPoint(0.0, 0.0), 100.0, 100.0));
162 aCircle
.setClosed(true);
164 OUString aName
= SC_LINEEND_NAME
;
166 aArrowSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aCircle
) ) );
167 aArrowSet
.Put( XLineStartWidthItem( 200 ) );
168 aArrowSet
.Put( XLineStartCenterItem( sal_True
) );
169 aArrowSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
170 aArrowSet
.Put( XLineEndWidthItem( 200 ) );
171 aArrowSet
.Put( XLineEndCenterItem( false ) );
173 aToTabSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aCircle
) ) );
174 aToTabSet
.Put( XLineStartWidthItem( 200 ) );
175 aToTabSet
.Put( XLineStartCenterItem( sal_True
) );
176 aToTabSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aSquare
) ) );
177 aToTabSet
.Put( XLineEndWidthItem( 300 ) );
178 aToTabSet
.Put( XLineEndCenterItem( false ) );
180 aFromTabSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aSquare
) ) );
181 aFromTabSet
.Put( XLineStartWidthItem( 300 ) );
182 aFromTabSet
.Put( XLineStartCenterItem( sal_True
) );
183 aFromTabSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
184 aFromTabSet
.Put( XLineEndWidthItem( 200 ) );
185 aFromTabSet
.Put( XLineEndCenterItem( false ) );
187 aCircleSet
.Put( XLineColorItem( OUString(), Color( ScDetectiveFunc::GetErrorColor() ) ) );
188 aCircleSet
.Put( XFillStyleItem( XFILL_NONE
) );
189 sal_uInt16 nWidth
= 55; // 54 = 1 Pixel
190 aCircleSet
.Put( XLineWidthItem( nWidth
) );
193 ScCommentData::ScCommentData( ScDocument
& rDoc
, SdrModel
* pModel
) :
194 aCaptionSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
, EE_ITEMS_START
, EE_ITEMS_END
, 0, 0 )
196 basegfx::B2DPolygon aTriangle
;
197 aTriangle
.append(basegfx::B2DPoint(10.0, 0.0));
198 aTriangle
.append(basegfx::B2DPoint(0.0, 30.0));
199 aTriangle
.append(basegfx::B2DPoint(20.0, 30.0));
200 aTriangle
.setClosed(true);
202 OUString aName
= SC_LINEEND_NAME
;
204 aCaptionSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
205 aCaptionSet
.Put( XLineStartWidthItem( 200 ) );
206 aCaptionSet
.Put( XLineStartCenterItem( false ) );
207 aCaptionSet
.Put( XFillStyleItem( XFILL_SOLID
) );
208 Color
aYellow( ScDetectiveFunc::GetCommentColor() );
209 aCaptionSet
.Put( XFillColorItem( OUString(), aYellow
) );
212 // SdrShadowItem has sal_False, instead the shadow is set for the rectangle
213 // only with SetSpecialTextBoxShadow when the object is created
214 // (item must be set to adjust objects from older files)
215 aCaptionSet
.Put( SdrShadowItem( false ) );
216 aCaptionSet
.Put( SdrShadowXDistItem( 100 ) );
217 aCaptionSet
.Put( SdrShadowYDistItem( 100 ) );
220 aCaptionSet
.Put( SdrTextLeftDistItem( 100 ) );
221 aCaptionSet
.Put( SdrTextRightDistItem( 100 ) );
222 aCaptionSet
.Put( SdrTextUpperDistItem( 100 ) );
223 aCaptionSet
.Put( SdrTextLowerDistItem( 100 ) );
225 aCaptionSet
.Put( SdrTextAutoGrowWidthItem( false ) );
226 aCaptionSet
.Put( SdrTextAutoGrowHeightItem( sal_True
) );
228 // do use the default cell style, so the user has a chance to
229 // modify the font for the annotations
230 ((const ScPatternAttr
&)rDoc
.GetPool()->GetDefaultItem(ATTR_PATTERN
)).
231 FillEditItemSet( &aCaptionSet
);
233 // support the best position for the tail connector now that
234 // that notes can be resized and repositioned.
235 aCaptionSet
.Put( SdrCaptionEscDirItem( SDRCAPT_ESCBESTFIT
) );
238 void ScCommentData::UpdateCaptionSet( const SfxItemSet
& rItemSet
)
240 SfxWhichIter
aWhichIter( rItemSet
);
241 const SfxPoolItem
* pPoolItem
= 0;
243 for( sal_uInt16 nWhich
= aWhichIter
.FirstWhich(); nWhich
> 0; nWhich
= aWhichIter
.NextWhich() )
245 if(rItemSet
.GetItemState(nWhich
, false, &pPoolItem
) == SFX_ITEM_SET
)
250 // use existing Caption default - appears that setting this
251 // to true screws up the tail appearance. See also comment
252 // for default setting above.
254 case SDRATTR_SHADOWXDIST
:
255 // use existing Caption default - svx sets a value of 35
256 // but default 100 gives a better appearance.
258 case SDRATTR_SHADOWYDIST
:
259 // use existing Caption default - svx sets a value of 35
260 // but default 100 gives a better appearance.
264 aCaptionSet
.Put(*pPoolItem
);
270 void ScDetectiveFunc::Modified()
272 if (pDoc
->IsStreamValid(nTab
))
273 pDoc
->SetStreamValid(nTab
, false);
276 inline sal_Bool
Intersect( SCCOL nStartCol1
, SCROW nStartRow1
, SCCOL nEndCol1
, SCROW nEndRow1
,
277 SCCOL nStartCol2
, SCROW nStartRow2
, SCCOL nEndCol2
, SCROW nEndRow2
)
279 return nEndCol1
>= nStartCol2
&& nEndCol2
>= nStartCol1
&&
280 nEndRow1
>= nStartRow2
&& nEndRow2
>= nStartRow1
;
283 sal_Bool
ScDetectiveFunc::HasError( const ScRange
& rRange
, ScAddress
& rErrPos
)
285 rErrPos
= rRange
.aStart
;
286 sal_uInt16 nError
= 0;
288 ScCellIterator
aIter( pDoc
, rRange
);
289 for (bool bHasCell
= aIter
.first(); bHasCell
; bHasCell
= aIter
.next())
291 if (aIter
.getType() != CELLTYPE_FORMULA
)
294 nError
= aIter
.getFormulaCell()->GetErrCode();
296 rErrPos
= aIter
.GetPos();
299 return (nError
!= 0);
302 Point
ScDetectiveFunc::GetDrawPos( SCCOL nCol
, SCROW nRow
, DrawPosMode eMode
) const
304 OSL_ENSURE( ValidColRow( nCol
, nRow
), "ScDetectiveFunc::GetDrawPos - invalid cell address" );
312 case DRAWPOS_TOPLEFT
:
314 case DRAWPOS_BOTTOMRIGHT
:
318 case DRAWPOS_DETARROW
:
319 aPos
.X() += pDoc
->GetColWidth( nCol
, nTab
) / 4;
320 aPos
.Y() += pDoc
->GetRowHeight( nRow
, nTab
) / 2;
322 case DRAWPOS_CAPTIONLEFT
:
325 case DRAWPOS_CAPTIONRIGHT
:
327 // find right end of passed cell position
328 const ScMergeAttr
* pMerge
= static_cast< const ScMergeAttr
* >( pDoc
->GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE
) );
329 if ( pMerge
->GetColMerge() > 1 )
330 nCol
= nCol
+ pMerge
->GetColMerge();
338 for ( SCCOL i
= 0; i
< nCol
; ++i
)
339 aPos
.X() += pDoc
->GetColWidth( i
, nTab
);
340 aPos
.Y() += pDoc
->GetRowHeight( 0, nRow
- 1, nTab
);
342 aPos
.X() = static_cast< long >( aPos
.X() * HMM_PER_TWIPS
);
343 aPos
.Y() = static_cast< long >( aPos
.Y() * HMM_PER_TWIPS
);
345 if ( pDoc
->IsNegativePage( nTab
) )
351 Rectangle
ScDetectiveFunc::GetDrawRect( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) const
354 GetDrawPos( ::std::min( nCol1
, nCol2
), ::std::min( nRow1
, nRow2
), DRAWPOS_TOPLEFT
),
355 GetDrawPos( ::std::max( nCol1
, nCol2
), ::std::max( nRow1
, nRow2
), DRAWPOS_BOTTOMRIGHT
) );
356 aRect
.Justify(); // reorder left/right in RTL sheets
360 Rectangle
ScDetectiveFunc::GetDrawRect( SCCOL nCol
, SCROW nRow
) const
362 return GetDrawRect( nCol
, nRow
, nCol
, nRow
);
365 static sal_Bool
lcl_IsOtherTab( const basegfx::B2DPolyPolygon
& rPolyPolygon
)
367 // test if rPolygon is the line end for "other table" (rectangle)
368 if(1L == rPolyPolygon
.count())
370 const basegfx::B2DPolygon
aSubPoly(rPolyPolygon
.getB2DPolygon(0L));
372 // #i73305# circle consists of 4 segments, too, distinguishable from square by
373 // the use of control points
374 if(4L == aSubPoly
.count() && aSubPoly
.isClosed() && !aSubPoly
.areControlPointsUsed())
383 sal_Bool
ScDetectiveFunc::HasArrow( const ScAddress
& rStart
,
384 SCCOL nEndCol
, SCROW nEndRow
, SCTAB nEndTab
)
386 sal_Bool bStartAlien
= ( rStart
.Tab() != nTab
);
387 sal_Bool bEndAlien
= ( nEndTab
!= nTab
);
389 if (bStartAlien
&& bEndAlien
)
391 OSL_FAIL("bStartAlien && bEndAlien");
395 Rectangle aStartRect
;
398 aStartRect
= GetDrawRect( rStart
.Col(), rStart
.Row() );
400 aEndRect
= GetDrawRect( nEndCol
, nEndRow
);
402 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
403 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
404 OSL_ENSURE(pPage
,"Page ?");
406 sal_Bool bFound
= false;
407 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
408 SdrObject
* pObject
= aIter
.Next();
409 while (pObject
&& !bFound
)
411 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
412 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
414 const SfxItemSet
& rSet
= pObject
->GetMergedItemSet();
416 sal_Bool bObjStartAlien
=
417 lcl_IsOtherTab( ((const XLineStartItem
&)rSet
.Get(XATTR_LINESTART
)).GetLineStartValue() );
418 sal_Bool bObjEndAlien
=
419 lcl_IsOtherTab( ((const XLineEndItem
&)rSet
.Get(XATTR_LINEEND
)).GetLineEndValue() );
421 sal_Bool bStartHit
= bStartAlien
? bObjStartAlien
:
422 ( !bObjStartAlien
&& aStartRect
.IsInside(pObject
->GetPoint(0)) );
423 sal_Bool bEndHit
= bEndAlien
? bObjEndAlien
:
424 ( !bObjEndAlien
&& aEndRect
.IsInside(pObject
->GetPoint(1)) );
426 if ( bStartHit
&& bEndHit
)
429 pObject
= aIter
.Next();
435 sal_Bool
ScDetectiveFunc::IsNonAlienArrow( SdrObject
* pObject
)
437 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
438 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
440 const SfxItemSet
& rSet
= pObject
->GetMergedItemSet();
442 sal_Bool bObjStartAlien
=
443 lcl_IsOtherTab( ((const XLineStartItem
&)rSet
.Get(XATTR_LINESTART
)).GetLineStartValue() );
444 sal_Bool bObjEndAlien
=
445 lcl_IsOtherTab( ((const XLineEndItem
&)rSet
.Get(XATTR_LINEEND
)).GetLineEndValue() );
447 return !bObjStartAlien
&& !bObjEndAlien
;
453 // InsertXXX: called from DrawEntry/DrawAlienEntry and InsertObject
455 sal_Bool
ScDetectiveFunc::InsertArrow( SCCOL nCol
, SCROW nRow
,
456 SCCOL nRefStartCol
, SCROW nRefStartRow
,
457 SCCOL nRefEndCol
, SCROW nRefEndRow
,
458 sal_Bool bFromOtherTab
, sal_Bool bRed
,
459 ScDetectiveData
& rData
)
461 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
462 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
464 sal_Bool bArea
= ( nRefStartCol
!= nRefEndCol
|| nRefStartRow
!= nRefEndRow
);
465 if (bArea
&& !bFromOtherTab
)
467 // insert the rectangle before the arrow - this is relied on in FindFrameForObject
469 Rectangle aRect
= GetDrawRect( nRefStartCol
, nRefStartRow
, nRefEndCol
, nRefEndRow
);
470 SdrRectObj
* pBox
= new SdrRectObj( aRect
);
472 pBox
->SetMergedItemSetAndBroadcast(rData
.GetBoxSet());
474 pBox
->SetLayer( SC_LAYER_INTERN
);
475 pPage
->InsertObject( pBox
);
476 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pBox
) );
478 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pBox
, sal_True
);
479 pData
->maStart
.Set( nRefStartCol
, nRefStartRow
, nTab
);
480 pData
->maEnd
.Set( nRefEndCol
, nRefEndRow
, nTab
);
483 Point aStartPos
= GetDrawPos( nRefStartCol
, nRefStartRow
, DRAWPOS_DETARROW
);
484 Point aEndPos
= GetDrawPos( nCol
, nRow
, DRAWPOS_DETARROW
);
488 sal_Bool bNegativePage
= pDoc
->IsNegativePage( nTab
);
489 long nPageSign
= bNegativePage
? -1 : 1;
491 aStartPos
= Point( aEndPos
.X() - 1000 * nPageSign
, aEndPos
.Y() - 1000 );
492 if (aStartPos
.X() * nPageSign
< 0)
493 aStartPos
.X() += 2000 * nPageSign
;
494 if (aStartPos
.Y() < 0)
495 aStartPos
.Y() += 2000;
498 SfxItemSet
& rAttrSet
= bFromOtherTab
? rData
.GetFromTabSet() : rData
.GetArrowSet();
500 if (bArea
&& !bFromOtherTab
)
501 rAttrSet
.Put( XLineWidthItem( 50 ) ); // Bereich
503 rAttrSet
.Put( XLineWidthItem( 0 ) ); // einzelne Referenz
505 ColorData nColorData
= ( bRed
? GetErrorColor() : GetArrowColor() );
506 rAttrSet
.Put( XLineColorItem( OUString(), Color( nColorData
) ) );
508 basegfx::B2DPolygon aTempPoly
;
509 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
510 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
511 SdrPathObj
* pArrow
= new SdrPathObj(OBJ_LINE
, basegfx::B2DPolyPolygon(aTempPoly
));
512 pArrow
->NbcSetLogicRect(Rectangle(aStartPos
,aEndPos
)); //! noetig ???
513 pArrow
->SetMergedItemSetAndBroadcast(rAttrSet
);
515 pArrow
->SetLayer( SC_LAYER_INTERN
);
516 pPage
->InsertObject( pArrow
);
517 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pArrow
) );
519 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pArrow
, true);
521 pData
->maStart
.SetInvalid();
523 pData
->maStart
.Set( nRefStartCol
, nRefStartRow
, nTab
);
525 pData
->maEnd
.Set( nCol
, nRow
, nTab
);
526 pData
->meType
= ScDrawObjData::DetectiveArrow
;
532 sal_Bool
ScDetectiveFunc::InsertToOtherTab( SCCOL nStartCol
, SCROW nStartRow
,
533 SCCOL nEndCol
, SCROW nEndRow
, sal_Bool bRed
,
534 ScDetectiveData
& rData
)
536 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
537 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
539 sal_Bool bArea
= ( nStartCol
!= nEndCol
|| nStartRow
!= nEndRow
);
542 Rectangle aRect
= GetDrawRect( nStartCol
, nStartRow
, nEndCol
, nEndRow
);
543 SdrRectObj
* pBox
= new SdrRectObj( aRect
);
545 pBox
->SetMergedItemSetAndBroadcast(rData
.GetBoxSet());
547 pBox
->SetLayer( SC_LAYER_INTERN
);
548 pPage
->InsertObject( pBox
);
549 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pBox
) );
551 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pBox
, sal_True
);
552 pData
->maStart
.Set( nStartCol
, nStartRow
, nTab
);
553 pData
->maEnd
.Set( nEndCol
, nEndRow
, nTab
);
556 sal_Bool bNegativePage
= pDoc
->IsNegativePage( nTab
);
557 long nPageSign
= bNegativePage
? -1 : 1;
559 Point aStartPos
= GetDrawPos( nStartCol
, nStartRow
, DRAWPOS_DETARROW
);
560 Point aEndPos
= Point( aStartPos
.X() + 1000 * nPageSign
, aStartPos
.Y() - 1000 );
564 SfxItemSet
& rAttrSet
= rData
.GetToTabSet();
566 rAttrSet
.Put( XLineWidthItem( 50 ) ); // Bereich
568 rAttrSet
.Put( XLineWidthItem( 0 ) ); // einzelne Referenz
570 ColorData nColorData
= ( bRed
? GetErrorColor() : GetArrowColor() );
571 rAttrSet
.Put( XLineColorItem( OUString(), Color( nColorData
) ) );
573 basegfx::B2DPolygon aTempPoly
;
574 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
575 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
576 SdrPathObj
* pArrow
= new SdrPathObj(OBJ_LINE
, basegfx::B2DPolyPolygon(aTempPoly
));
577 pArrow
->NbcSetLogicRect(Rectangle(aStartPos
,aEndPos
)); //! noetig ???
579 pArrow
->SetMergedItemSetAndBroadcast(rAttrSet
);
581 pArrow
->SetLayer( SC_LAYER_INTERN
);
582 pPage
->InsertObject( pArrow
);
583 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pArrow
) );
585 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pArrow
, sal_True
);
586 pData
->maStart
.Set( nStartCol
, nStartRow
, nTab
);
587 pData
->maEnd
.SetInvalid();
593 // DrawEntry: Formel auf dieser Tabelle,
594 // Referenz auf dieser oder anderer
595 // DrawAlienEntry: Formel auf anderer Tabelle,
596 // Referenz auf dieser
598 // return FALSE: da war schon ein Pfeil
600 sal_Bool
ScDetectiveFunc::DrawEntry( SCCOL nCol
, SCROW nRow
,
602 ScDetectiveData
& rData
)
604 if ( HasArrow( rRef
.aStart
, nCol
, nRow
, nTab
) )
608 sal_Bool bError
= HasError( rRef
, aErrorPos
);
609 sal_Bool bAlien
= ( rRef
.aEnd
.Tab() < nTab
|| rRef
.aStart
.Tab() > nTab
);
611 return InsertArrow( nCol
, nRow
,
612 rRef
.aStart
.Col(), rRef
.aStart
.Row(),
613 rRef
.aEnd
.Col(), rRef
.aEnd
.Row(),
614 bAlien
, bError
, rData
);
617 sal_Bool
ScDetectiveFunc::DrawAlienEntry( const ScRange
& rRef
,
618 ScDetectiveData
& rData
)
620 if ( HasArrow( rRef
.aStart
, 0, 0, nTab
+1 ) )
624 sal_Bool bError
= HasError( rRef
, aErrorPos
);
626 return InsertToOtherTab( rRef
.aStart
.Col(), rRef
.aStart
.Row(),
627 rRef
.aEnd
.Col(), rRef
.aEnd
.Row(),
631 void ScDetectiveFunc::DrawCircle( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
)
633 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
634 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
636 Rectangle aRect
= GetDrawRect( nCol
, nRow
);
638 aRect
.Right() += 250;
640 aRect
.Bottom() += 70;
642 SdrCircObj
* pCircle
= new SdrCircObj( OBJ_CIRC
, aRect
);
643 SfxItemSet
& rAttrSet
= rData
.GetCircleSet();
645 pCircle
->SetMergedItemSetAndBroadcast(rAttrSet
);
647 pCircle
->SetLayer( SC_LAYER_INTERN
);
648 pPage
->InsertObject( pCircle
);
649 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pCircle
) );
651 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pCircle
, sal_True
);
652 pData
->maStart
.Set( nCol
, nRow
, nTab
);
653 pData
->maEnd
.SetInvalid();
654 pData
->meType
= ScDrawObjData::ValidationCircle
;
659 void ScDetectiveFunc::DeleteArrowsAt( SCCOL nCol
, SCROW nRow
, sal_Bool bDestPnt
)
661 Rectangle aRect
= GetDrawRect( nCol
, nRow
);
663 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
664 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
665 OSL_ENSURE(pPage
,"Page ?");
667 pPage
->RecalcObjOrdNums();
669 sal_uLong nObjCount
= pPage
->GetObjCount();
673 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
675 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
676 SdrObject
* pObject
= aIter
.Next();
679 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
680 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
682 if (aRect
.IsInside(pObject
->GetPoint(bDestPnt
))) // Start/Zielpunkt
683 ppObj
[nDelCount
++] = pObject
;
686 pObject
= aIter
.Next();
690 for (i
=1; i
<=nDelCount
; i
++)
691 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
693 for (i
=1; i
<=nDelCount
; i
++)
694 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
702 // Box um Referenz loeschen
704 #define SC_DET_TOLERANCE 50
706 inline sal_Bool
RectIsPoints( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
708 return rRect
.Left() >= rStart
.X() - SC_DET_TOLERANCE
709 && rRect
.Left() <= rStart
.X() + SC_DET_TOLERANCE
710 && rRect
.Right() >= rEnd
.X() - SC_DET_TOLERANCE
711 && rRect
.Right() <= rEnd
.X() + SC_DET_TOLERANCE
712 && rRect
.Top() >= rStart
.Y() - SC_DET_TOLERANCE
713 && rRect
.Top() <= rStart
.Y() + SC_DET_TOLERANCE
714 && rRect
.Bottom() >= rEnd
.Y() - SC_DET_TOLERANCE
715 && rRect
.Bottom() <= rEnd
.Y() + SC_DET_TOLERANCE
;
718 #undef SC_DET_TOLERANCE
720 void ScDetectiveFunc::DeleteBox( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
722 Rectangle aCornerRect
= GetDrawRect( nCol1
, nRow1
, nCol2
, nRow2
);
723 Point aStartCorner
= aCornerRect
.TopLeft();
724 Point aEndCorner
= aCornerRect
.BottomRight();
727 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
728 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
729 OSL_ENSURE(pPage
,"Page ?");
731 pPage
->RecalcObjOrdNums();
733 sal_uLong nObjCount
= pPage
->GetObjCount();
737 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
739 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
740 SdrObject
* pObject
= aIter
.Next();
743 if ( pObject
->GetLayer() == SC_LAYER_INTERN
&&
744 pObject
->Type() == TYPE(SdrRectObj
) )
746 aObjRect
= ((SdrRectObj
*)pObject
)->GetLogicRect();
748 if ( RectIsPoints( aObjRect
, aStartCorner
, aEndCorner
) )
749 ppObj
[nDelCount
++] = pObject
;
752 pObject
= aIter
.Next();
756 for (i
=1; i
<=nDelCount
; i
++)
757 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
759 for (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(); // nach SetRunning geht's nicht mehr!
815 pFCell
->SetRunning(sal_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
; // neuer Pfeil eingetragen
831 if ( nLevel
< rData
.GetMaxLevel() )
833 sal_uInt16 nSubResult
;
834 sal_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: unveraendert lassen
857 else // nMaxLevel erreicht
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 -> loeschen
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(); // nach SetRunning geht's nicht mehr!
904 pFCell
->SetRunning(sal_True
);
906 sal_uInt16 nResult
= nLevel
;
907 sal_Bool bDelete
= ( nDeleteLevel
&& nLevel
== nDeleteLevel
-1 );
911 DeleteArrowsAt( nCol
, nRow
, sal_True
); // Pfeile, die hierher zeigen
914 ScDetectiveRefIter
aIter(pFCell
);
916 while ( aIter
.GetNextRef( aRef
) )
918 sal_Bool bArea
= ( aRef
.aStart
!= aRef
.aEnd
);
920 if ( bDelete
) // Rahmen loeschen ?
924 DeleteBox( aRef
.aStart
.Col(), aRef
.aStart
.Row(), aRef
.aEnd
.Col(), aRef
.aEnd
.Row() );
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(); // nach SetRunning geht's nicht mehr!
962 pFCell
->SetRunning(sal_True
);
964 sal_uInt16 nResult
= DET_INS_EMPTY
;
966 ScDetectiveRefIter
aIter(pFCell
);
969 sal_Bool bHasError
= false;
970 while ( aIter
.GetNextRef( aRef
) )
972 if (HasError( aRef
, aErrorPos
))
974 bHasError
= sal_True
;
975 if (DrawEntry( nCol
, nRow
, ScRange( aErrorPos
), rData
))
976 nResult
= DET_INS_INSERTED
;
978 // und weiterverfolgen
980 if ( nLevel
< rData
.GetMaxLevel() ) // praktisch immer
982 if (InsertErrorLevel( aErrorPos
.Col(), aErrorPos
.Row(),
983 rData
, nLevel
+1 ) == DET_INS_INSERTED
)
984 nResult
= DET_INS_INSERTED
;
989 pFCell
->SetRunning(false);
993 if (InsertPredLevel( nCol
, nRow
, rData
, rData
.GetMaxLevel() ) == DET_INS_INSERTED
)
994 nResult
= DET_INS_INSERTED
;
999 sal_uInt16
ScDetectiveFunc::InsertSuccLevel( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1000 ScDetectiveData
& rData
, sal_uInt16 nLevel
)
1002 // over the entire document.
1004 sal_uInt16 nResult
= DET_INS_EMPTY
;
1005 ScCellIterator
aCellIter(pDoc
, ScRange(0,0,0,MAXCOL
,MAXROW
,MAXTAB
)); // all sheets
1006 for (bool bHas
= aCellIter
.first(); bHas
; bHas
= aCellIter
.next())
1008 if (aCellIter
.getType() != CELLTYPE_FORMULA
)
1011 ScFormulaCell
* pFCell
= aCellIter
.getFormulaCell();
1012 bool bRunning
= pFCell
->IsRunning();
1014 if (pFCell
->GetDirty())
1015 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
1016 pFCell
->SetRunning(true);
1018 ScDetectiveRefIter
aIter(pFCell
);
1020 while ( aIter
.GetNextRef( aRef
) )
1022 if (aRef
.aStart
.Tab() <= nTab
&& aRef
.aEnd
.Tab() >= nTab
)
1024 if (Intersect( nCol1
,nRow1
,nCol2
,nRow2
,
1025 aRef
.aStart
.Col(),aRef
.aStart
.Row(),
1026 aRef
.aEnd
.Col(),aRef
.aEnd
.Row() ))
1028 sal_Bool bAlien
= ( aCellIter
.GetPos().Tab() != nTab
);
1031 bDrawRet
= DrawAlienEntry( aRef
, rData
);
1033 bDrawRet
= DrawEntry( aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1037 nResult
= DET_INS_INSERTED
; // neuer Pfeil eingetragen
1043 if (nResult
== DET_INS_EMPTY
)
1044 nResult
= DET_INS_CIRCULAR
;
1050 if ( nLevel
< rData
.GetMaxLevel() )
1052 sal_uInt16 nSubResult
= InsertSuccLevel(
1053 aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1054 aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1058 case DET_INS_INSERTED
:
1059 nResult
= DET_INS_INSERTED
;
1061 case DET_INS_CONTINUE
:
1062 if (nResult
!= DET_INS_INSERTED
)
1063 nResult
= DET_INS_CONTINUE
;
1065 case DET_INS_CIRCULAR
:
1066 if (nResult
== DET_INS_EMPTY
)
1067 nResult
= DET_INS_CIRCULAR
;
1069 // DET_INS_EMPTY: unveraendert lassen
1072 else // nMaxLevel erreicht
1073 if (nResult
!= DET_INS_INSERTED
)
1074 nResult
= DET_INS_CONTINUE
;
1080 pFCell
->SetRunning(bRunning
);
1086 sal_uInt16
ScDetectiveFunc::FindSuccLevel( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1087 sal_uInt16 nLevel
, sal_uInt16 nDeleteLevel
)
1089 OSL_ENSURE( nLevel
<1000, "Level" );
1091 sal_uInt16 nResult
= nLevel
;
1092 sal_Bool bDelete
= ( nDeleteLevel
&& nLevel
== nDeleteLevel
-1 );
1094 ScCellIterator
aCellIter( pDoc
, ScRange(0, 0, nTab
, MAXCOL
, MAXROW
, nTab
) );
1095 for (bool bHas
= aCellIter
.first(); bHas
; bHas
= aCellIter
.next())
1097 if (aCellIter
.getType() != CELLTYPE_FORMULA
)
1100 ScFormulaCell
* pFCell
= aCellIter
.getFormulaCell();
1101 bool bRunning
= pFCell
->IsRunning();
1103 if (pFCell
->GetDirty())
1104 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
1105 pFCell
->SetRunning(true);
1107 ScDetectiveRefIter
aIter(pFCell
);
1109 while ( aIter
.GetNextRef( aRef
) )
1111 if (aRef
.aStart
.Tab() <= nTab
&& aRef
.aEnd
.Tab() >= nTab
)
1113 if (Intersect( nCol1
,nRow1
,nCol2
,nRow2
,
1114 aRef
.aStart
.Col(),aRef
.aStart
.Row(),
1115 aRef
.aEnd
.Col(),aRef
.aEnd
.Row() ))
1117 if ( bDelete
) // Pfeile, die hier anfangen
1119 if (aRef
.aStart
!= aRef
.aEnd
)
1121 DeleteBox( aRef
.aStart
.Col(), aRef
.aStart
.Row(),
1122 aRef
.aEnd
.Col(), aRef
.aEnd
.Row() );
1124 DeleteArrowsAt( aRef
.aStart
.Col(), aRef
.aStart
.Row(), false );
1126 else if ( !bRunning
&&
1127 HasArrow( aRef
.aStart
,
1128 aCellIter
.GetPos().Col(),aCellIter
.GetPos().Row(),aCellIter
.GetPos().Tab() ) )
1130 sal_uInt16 nTemp
= FindSuccLevel( aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1131 aCellIter
.GetPos().Col(), aCellIter
.GetPos().Row(),
1132 nLevel
+1, nDeleteLevel
);
1133 if (nTemp
> nResult
)
1140 pFCell
->SetRunning(bRunning
);
1150 sal_Bool
ScDetectiveFunc::ShowPred( SCCOL nCol
, SCROW nRow
)
1152 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1156 ScDetectiveData
aData( pModel
);
1158 sal_uInt16 nMaxLevel
= 0;
1159 sal_uInt16 nResult
= DET_INS_CONTINUE
;
1160 while (nResult
== DET_INS_CONTINUE
&& nMaxLevel
< 1000)
1162 aData
.SetMaxLevel( nMaxLevel
);
1163 nResult
= InsertPredLevel( nCol
, nRow
, aData
, 0 );
1167 return ( nResult
== DET_INS_INSERTED
);
1170 sal_Bool
ScDetectiveFunc::ShowSucc( SCCOL nCol
, SCROW nRow
)
1172 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1176 ScDetectiveData
aData( pModel
);
1178 sal_uInt16 nMaxLevel
= 0;
1179 sal_uInt16 nResult
= DET_INS_CONTINUE
;
1180 while (nResult
== DET_INS_CONTINUE
&& nMaxLevel
< 1000)
1182 aData
.SetMaxLevel( nMaxLevel
);
1183 nResult
= InsertSuccLevel( nCol
, nRow
, nCol
, nRow
, aData
, 0 );
1187 return ( nResult
== DET_INS_INSERTED
);
1190 sal_Bool
ScDetectiveFunc::ShowError( SCCOL nCol
, SCROW nRow
)
1192 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1196 ScRange
aRange( nCol
, nRow
, nTab
);
1198 if ( !HasError( aRange
,aErrPos
) )
1201 ScDetectiveData
aData( pModel
);
1203 aData
.SetMaxLevel( 1000 );
1204 sal_uInt16 nResult
= InsertErrorLevel( nCol
, nRow
, aData
, 0 );
1206 return ( nResult
== DET_INS_INSERTED
);
1209 sal_Bool
ScDetectiveFunc::DeleteSucc( SCCOL nCol
, SCROW nRow
)
1211 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1215 sal_uInt16 nLevelCount
= FindSuccLevel( nCol
, nRow
, nCol
, nRow
, 0, 0 );
1217 FindSuccLevel( nCol
, nRow
, nCol
, nRow
, 0, nLevelCount
); // loeschen
1219 return ( nLevelCount
!= 0 );
1222 sal_Bool
ScDetectiveFunc::DeletePred( SCCOL nCol
, SCROW nRow
)
1224 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1228 sal_uInt16 nLevelCount
= FindPredLevel( nCol
, nRow
, 0, 0 );
1230 FindPredLevel( nCol
, nRow
, 0, nLevelCount
); // loeschen
1232 return ( nLevelCount
!= 0 );
1235 sal_Bool
ScDetectiveFunc::DeleteAll( ScDetectiveDelete eWhat
)
1237 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1241 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
1242 OSL_ENSURE(pPage
,"Page ?");
1244 pPage
->RecalcObjOrdNums();
1247 sal_uLong nObjCount
= pPage
->GetObjCount();
1250 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
1252 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1253 SdrObject
* pObject
= aIter
.Next();
1256 if ( pObject
->GetLayer() == SC_LAYER_INTERN
)
1258 sal_Bool bDoThis
= sal_True
;
1259 if ( eWhat
!= SC_DET_ALL
)
1261 sal_Bool bCircle
= ( pObject
->ISA(SdrCircObj
) );
1262 sal_Bool bCaption
= ScDrawLayer::IsNoteCaption( pObject
);
1263 if ( eWhat
== SC_DET_DETECTIVE
) // Detektiv, aus Menue
1264 bDoThis
= !bCaption
; // auch Kreise
1265 else if ( eWhat
== SC_DET_CIRCLES
) // Kreise, wenn neue erzeugt werden
1267 else if ( eWhat
== SC_DET_ARROWS
) // DetectiveRefresh
1268 bDoThis
= !bCaption
&& !bCircle
; // don't include circles
1275 ppObj
[nDelCount
++] = pObject
;
1278 pObject
= aIter
.Next();
1282 for (i
=1; i
<=nDelCount
; i
++)
1283 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
1285 for (i
=1; i
<=nDelCount
; i
++)
1286 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
1293 return ( nDelCount
!= 0 );
1296 sal_Bool
ScDetectiveFunc::MarkInvalid(sal_Bool
& rOverflow
)
1299 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1303 sal_Bool bDeleted
= DeleteAll( SC_DET_CIRCLES
); // nur die Kreise
1305 ScDetectiveData
aData( pModel
);
1308 // Stellen suchen, wo Gueltigkeit definiert ist
1310 ScDocAttrIterator
aAttrIter( pDoc
, nTab
, 0,0,MAXCOL
,MAXROW
);
1314 const ScPatternAttr
* pPattern
= aAttrIter
.GetNext( nCol
, nRow1
, nRow2
);
1315 while ( pPattern
&& nInsCount
< SC_DET_MAXCIRCLE
)
1317 sal_uLong nIndex
= ((const SfxUInt32Item
&)pPattern
->GetItem(ATTR_VALIDDATA
)).GetValue();
1320 const ScValidationData
* pData
= pDoc
->GetValidationEntry( nIndex
);
1323 // Zellen in dem Bereich durchgehen
1325 sal_Bool bMarkEmpty
= !pData
->IsIgnoreBlank();
1326 SCROW nNextRow
= nRow1
;
1328 ScCellIterator
aCellIter( pDoc
, ScRange(nCol
, nRow1
, nTab
, nCol
, nRow2
, nTab
) );
1329 for (bool bHas
= aCellIter
.first(); bHas
&& nInsCount
< SC_DET_MAXCIRCLE
; bHas
= aCellIter
.next())
1331 SCROW nCellRow
= aCellIter
.GetPos().Row();
1333 for ( nRow
= nNextRow
; nRow
< nCellRow
&& nInsCount
< SC_DET_MAXCIRCLE
; nRow
++ )
1335 DrawCircle( nCol
, nRow
, aData
);
1338 ScRefCellValue aCell
= aCellIter
.getRefCellValue();
1339 if (!pData
->IsDataValid(aCell
, aCellIter
.GetPos()))
1341 DrawCircle( nCol
, nCellRow
, aData
);
1344 nNextRow
= nCellRow
+ 1;
1347 for ( nRow
= nNextRow
; nRow
<= nRow2
&& nInsCount
< SC_DET_MAXCIRCLE
; nRow
++ )
1349 DrawCircle( nCol
, nRow
, aData
);
1355 pPattern
= aAttrIter
.GetNext( nCol
, nRow1
, nRow2
);
1358 if ( nInsCount
>= SC_DET_MAXCIRCLE
)
1359 rOverflow
= sal_True
;
1361 return ( bDeleted
|| nInsCount
!= 0 );
1364 void ScDetectiveFunc::GetAllPreds(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1365 vector
<ScTokenRef
>& rRefTokens
)
1367 ScCellIterator
aIter(pDoc
, ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
));
1368 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
1370 if (aIter
.getType() != CELLTYPE_FORMULA
)
1373 ScFormulaCell
* pFCell
= aIter
.getFormulaCell();
1374 ScDetectiveRefIter
aRefIter(pFCell
);
1375 for (ScToken
* p
= aRefIter
.GetNextRefToken(); p
; p
= aRefIter
.GetNextRefToken())
1377 ScTokenRef
pRef(static_cast<ScToken
*>(p
->Clone()));
1378 ScRefTokenHelper::join(rRefTokens
, pRef
, aIter
.GetPos());
1383 void ScDetectiveFunc::GetAllSuccs(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1384 vector
<ScTokenRef
>& rRefTokens
)
1386 vector
<ScTokenRef
> aSrcRange
;
1387 aSrcRange
.push_back(
1388 ScRefTokenHelper::createRefToken(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
)));
1390 ScCellIterator
aIter(pDoc
, ScRange(0, 0, nTab
, MAXCOL
, MAXROW
, nTab
));
1391 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
1393 if (aIter
.getType() != CELLTYPE_FORMULA
)
1396 ScFormulaCell
* pFCell
= aIter
.getFormulaCell();
1397 ScDetectiveRefIter
aRefIter(pFCell
);
1398 for (ScToken
* p
= aRefIter
.GetNextRefToken(); p
; p
= aRefIter
.GetNextRefToken())
1400 const ScAddress
& aPos
= aIter
.GetPos();
1401 ScTokenRef
pRef(static_cast<ScToken
*>(p
->Clone()));
1402 if (ScRefTokenHelper::intersects(aSrcRange
, pRef
, aPos
))
1404 // This address is absolute.
1405 pRef
= ScRefTokenHelper::createRefToken(aPos
);
1406 ScRefTokenHelper::join(rRefTokens
, pRef
, ScAddress());
1412 void ScDetectiveFunc::UpdateAllComments( ScDocument
& rDoc
)
1414 // for all caption objects, update attributes and SpecialTextBoxShadow flag
1415 // (on all tables - nTab is ignored!)
1417 // no undo actions, this is refreshed after undo
1419 ScDrawLayer
* pModel
= rDoc
.GetDrawLayer();
1423 for( SCTAB nObjTab
= 0, nTabCount
= rDoc
.GetTableCount(); nObjTab
< nTabCount
; ++nObjTab
)
1425 SdrPage
* pPage
= pModel
->GetPage( static_cast< sal_uInt16
>( nObjTab
) );
1426 OSL_ENSURE( pPage
, "Page ?" );
1429 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1430 for( SdrObject
* pObject
= aIter
.Next(); pObject
; pObject
= aIter
.Next() )
1432 if ( ScDrawObjData
* pData
= ScDrawLayer::GetNoteCaptionData( pObject
, nObjTab
) )
1434 ScPostIt
* pNote
= rDoc
.GetNote( pData
->maStart
);
1435 // caption should exist, we iterate over drawing objects...
1436 OSL_ENSURE( pNote
&& (pNote
->GetCaption() == pObject
), "ScDetectiveFunc::UpdateAllComments - invalid cell note" );
1439 ScCommentData
aData( rDoc
, pModel
);
1440 SfxItemSet aAttrColorSet
= pObject
->GetMergedItemSet();
1441 aAttrColorSet
.Put( XFillColorItem( OUString(), GetCommentColor() ) );
1442 aData
.UpdateCaptionSet( aAttrColorSet
);
1443 pObject
->SetMergedItemSetAndBroadcast( aData
.GetCaptionSet() );
1444 if( SdrCaptionObj
* pCaption
= dynamic_cast< SdrCaptionObj
* >( pObject
) )
1446 pCaption
->SetSpecialTextBoxShadow();
1447 pCaption
->SetFixedTail();
1456 void ScDetectiveFunc::UpdateAllArrowColors()
1458 // no undo actions necessary
1460 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1464 for( SCTAB nObjTab
= 0, nTabCount
= pDoc
->GetTableCount(); nObjTab
< nTabCount
; ++nObjTab
)
1466 SdrPage
* pPage
= pModel
->GetPage( static_cast< sal_uInt16
>( nObjTab
) );
1467 OSL_ENSURE( pPage
, "Page ?" );
1470 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1471 for( SdrObject
* pObject
= aIter
.Next(); pObject
; pObject
= aIter
.Next() )
1473 if ( pObject
->GetLayer() == SC_LAYER_INTERN
)
1475 sal_Bool bArrow
= false;
1476 sal_Bool bError
= false;
1481 ScDetectiveObjType eType
= GetDetectiveObjectType( pObject
, nObjTab
, aPos
, aSource
, bDummy
);
1482 if ( eType
== SC_DETOBJ_ARROW
|| eType
== SC_DETOBJ_TOOTHERTAB
)
1484 // source is valid, determine error flag from source range
1487 if ( HasError( aSource
, aErrPos
) )
1492 else if ( eType
== SC_DETOBJ_FROMOTHERTAB
)
1494 // source range is no longer known, take error flag from formula itself
1495 // (this means, if the formula has an error, all references to other tables
1499 if ( HasError( ScRange( aPos
), aErrPos
) )
1504 else if ( eType
== SC_DETOBJ_CIRCLE
)
1506 // circles (error marks) are always red
1510 else if ( eType
== SC_DETOBJ_NONE
)
1512 // frame for area reference has no ObjType, always gets arrow color
1514 if ( pObject
->ISA( SdrRectObj
) && !pObject
->ISA( SdrCaptionObj
) )
1520 if ( bArrow
|| bError
)
1522 ColorData nColorData
= ( bError
? GetErrorColor() : GetArrowColor() );
1523 pObject
->SetMergedItem( XLineColorItem( OUString(), Color( nColorData
) ) );
1526 pObject
->ActionChanged();
1534 sal_Bool
ScDetectiveFunc::FindFrameForObject( SdrObject
* pObject
, ScRange
& rRange
)
1536 // find the rectangle for an arrow (always the object directly before the arrow)
1537 // rRange must be initialized to the source cell of the arrow (start of area)
1539 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1540 if (!pModel
) return false;
1542 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
1543 OSL_ENSURE(pPage
,"Page ?");
1544 if (!pPage
) return false;
1546 // test if the object is a direct page member
1547 if( pObject
&& pObject
->GetPage() && (pObject
->GetPage() == pObject
->GetObjList()) )
1549 // Is there a previous object?
1550 const sal_uInt32
nOrdNum(pObject
->GetOrdNum());
1554 SdrObject
* pPrevObj
= pPage
->GetObj(nOrdNum
- 1);
1556 if ( pPrevObj
&& pPrevObj
->GetLayer() == SC_LAYER_INTERN
&& pPrevObj
->ISA(SdrRectObj
) )
1558 ScDrawObjData
* pPrevData
= ScDrawLayer::GetObjDataTab( pPrevObj
, rRange
.aStart
.Tab() );
1559 if ( pPrevData
&& pPrevData
->maStart
.IsValid() && pPrevData
->maEnd
.IsValid() && (pPrevData
->maStart
== rRange
.aStart
) )
1561 rRange
.aEnd
= pPrevData
->maEnd
;
1570 ScDetectiveObjType
ScDetectiveFunc::GetDetectiveObjectType( SdrObject
* pObject
, SCTAB nObjTab
,
1571 ScAddress
& rPosition
, ScRange
& rSource
, bool& rRedLine
)
1574 ScDetectiveObjType eType
= SC_DETOBJ_NONE
;
1576 if ( pObject
&& pObject
->GetLayer() == SC_LAYER_INTERN
)
1578 if ( ScDrawObjData
* pData
= ScDrawLayer::GetObjDataTab( pObject
, nObjTab
) )
1580 bool bValidStart
= pData
->maStart
.IsValid();
1581 bool bValidEnd
= pData
->maEnd
.IsValid();
1583 if ( pObject
->IsPolyObj() && pObject
->GetPointCount() == 2 )
1585 // line object -> arrow
1588 eType
= bValidEnd
? SC_DETOBJ_ARROW
: SC_DETOBJ_TOOTHERTAB
;
1589 else if ( bValidEnd
)
1590 eType
= SC_DETOBJ_FROMOTHERTAB
;
1593 rSource
= pData
->maStart
;
1595 rPosition
= pData
->maEnd
;
1597 if ( bValidStart
&& lcl_HasThickLine( *pObject
) )
1599 // thick line -> look for frame before this object
1601 FindFrameForObject( pObject
, rSource
); // modifies rSource
1604 ColorData nObjColor
= ((const XLineColorItem
&)pObject
->GetMergedItem(XATTR_LINECOLOR
)).GetColorValue().GetColor();
1605 if ( nObjColor
== GetErrorColor() && nObjColor
!= GetArrowColor() )
1608 else if ( pObject
->ISA(SdrCircObj
) )
1612 // cell position is returned in rPosition
1614 rPosition
= pData
->maStart
;
1615 eType
= SC_DETOBJ_CIRCLE
;
1624 void ScDetectiveFunc::InsertObject( ScDetectiveObjType eType
,
1625 const ScAddress
& rPosition
, const ScRange
& rSource
,
1628 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1629 if (!pModel
) return;
1630 ScDetectiveData
aData( pModel
);
1634 case SC_DETOBJ_ARROW
:
1635 case SC_DETOBJ_FROMOTHERTAB
:
1636 InsertArrow( rPosition
.Col(), rPosition
.Row(),
1637 rSource
.aStart
.Col(), rSource
.aStart
.Row(),
1638 rSource
.aEnd
.Col(), rSource
.aEnd
.Row(),
1639 (eType
== SC_DETOBJ_FROMOTHERTAB
), bRedLine
, aData
);
1641 case SC_DETOBJ_TOOTHERTAB
:
1642 InsertToOtherTab( rSource
.aStart
.Col(), rSource
.aStart
.Row(),
1643 rSource
.aEnd
.Col(), rSource
.aEnd
.Row(),
1646 case SC_DETOBJ_CIRCLE
:
1647 DrawCircle( rPosition
.Col(), rPosition
.Row(), aData
);
1651 // added to avoid warnings
1656 ColorData
ScDetectiveFunc::GetArrowColor()
1658 if (!bColorsInitialized
)
1663 ColorData
ScDetectiveFunc::GetErrorColor()
1665 if (!bColorsInitialized
)
1670 ColorData
ScDetectiveFunc::GetCommentColor()
1672 if (!bColorsInitialized
)
1674 return nCommentColor
;
1677 void ScDetectiveFunc::InitializeColors()
1679 // may be called several times to update colors from configuration
1681 const svtools::ColorConfig
& rColorCfg
= SC_MOD()->GetColorConfig();
1682 nArrowColor
= rColorCfg
.GetColorValue(svtools::CALCDETECTIVE
).nColor
;
1683 nErrorColor
= rColorCfg
.GetColorValue(svtools::CALCDETECTIVEERROR
).nColor
;
1684 nCommentColor
= rColorCfg
.GetColorValue(svtools::CALCNOTESBACKGROUND
).nColor
;
1686 bColorsInitialized
= sal_True
;
1689 sal_Bool
ScDetectiveFunc::IsColorsInitialized()
1691 return bColorsInitialized
;
1694 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */