1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: detfunc.cxx,v $
10 * $Revision: 1.30.20.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include "scitems.hxx"
37 #include <svtools/colorcfg.hxx>
38 #include <svx/eeitem.hxx>
39 #include <svx/outlobj.hxx>
40 #include <svx/sdshitm.hxx>
41 #include <svx/sdsxyitm.hxx>
42 #include <svx/sdtditm.hxx>
43 #include <svx/svditer.hxx>
44 #include <svx/svdocapt.hxx>
45 #include <svx/svdocirc.hxx>
46 #include <svx/svdopath.hxx>
47 #include <svx/svdorect.hxx>
48 #include <svx/svdpage.hxx>
49 #include <svx/svdundo.hxx>
50 #include <svx/xfillit0.hxx>
51 #include <svx/xflclit.hxx>
52 #include <svx/xlnclit.hxx>
53 #include <svx/xlnedcit.hxx>
54 #include <svx/xlnedit.hxx>
55 #include <svx/xlnedwit.hxx>
56 #include <svx/xlnstcit.hxx>
57 #include <svx/xlnstit.hxx>
58 #include <svx/xlnstwit.hxx>
59 #include <svx/xlnwtit.hxx>
60 #include <svx/xtable.hxx>
61 #include <svx/outliner.hxx>
62 #include <svx/editobj.hxx>
63 #include <svx/sxcecitm.hxx>
64 #include <svtools/whiter.hxx>
65 #include <svx/writingmodeitem.hxx>
67 #include <basegfx/point/b2dpoint.hxx>
68 #include <basegfx/polygon/b2dpolygontools.hxx>
69 #include <basegfx/polygon/b2dpolygon.hxx>
71 #include "detfunc.hxx"
72 #include "document.hxx"
73 #include "dociter.hxx"
74 #include "drwlayer.hxx"
75 #include "userdat.hxx"
76 #include "validat.hxx"
78 #include "docpool.hxx"
79 #include "patattr.hxx"
83 #include "rangelst.hxx"
84 #include "reftokenhelper.hxx"
90 //------------------------------------------------------------------------
92 // #99319# line ends are now created with an empty name.
93 // The checkForUniqueItem method then finds a unique name for the item's value.
94 #define SC_LINEEND_NAME EMPTY_STRING
96 //------------------------------------------------------------------------
98 enum DetInsertResult
{ // Return-Werte beim Einfuegen in einen Level
105 //------------------------------------------------------------------------
107 class ScDetectiveData
111 SfxItemSet aArrowSet
;
112 SfxItemSet aToTabSet
;
113 SfxItemSet aFromTabSet
;
114 SfxItemSet aCircleSet
; //! einzeln ?
118 ScDetectiveData( SdrModel
* pModel
);
120 SfxItemSet
& GetBoxSet() { return aBoxSet
; }
121 SfxItemSet
& GetArrowSet() { return aArrowSet
; }
122 SfxItemSet
& GetToTabSet() { return aToTabSet
; }
123 SfxItemSet
& GetFromTabSet() { return aFromTabSet
; }
124 SfxItemSet
& GetCircleSet() { return aCircleSet
; }
126 void SetMaxLevel( USHORT nVal
) { nMaxLevel
= nVal
; }
127 USHORT
GetMaxLevel() const { return nMaxLevel
; }
133 ScCommentData( ScDocument
& rDoc
, SdrModel
* pModel
);
135 SfxItemSet
& GetCaptionSet() { return aCaptionSet
; }
136 void UpdateCaptionSet( const SfxItemSet
& rItemSet
);
139 SfxItemSet aCaptionSet
;
142 //------------------------------------------------------------------------
144 ColorData
ScDetectiveFunc::nArrowColor
= 0;
145 ColorData
ScDetectiveFunc::nErrorColor
= 0;
146 ColorData
ScDetectiveFunc::nCommentColor
= 0;
147 BOOL
ScDetectiveFunc::bColorsInitialized
= FALSE
;
149 //------------------------------------------------------------------------
151 BOOL
lcl_HasThickLine( SdrObject
& rObj
)
153 // thin lines get width 0 -> everything greater 0 is a thick line
155 return ( ((const XLineWidthItem
&)rObj
.GetMergedItem(XATTR_LINEWIDTH
)).GetValue() > 0 );
158 //------------------------------------------------------------------------
160 ScDetectiveData::ScDetectiveData( SdrModel
* pModel
) :
161 aBoxSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
162 aArrowSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
163 aToTabSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
164 aFromTabSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
),
165 aCircleSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
)
169 aBoxSet
.Put( XLineColorItem( EMPTY_STRING
, Color( ScDetectiveFunc::GetArrowColor() ) ) );
170 aBoxSet
.Put( XFillStyleItem( XFILL_NONE
) );
172 // #66479# Standard-Linienenden (wie aus XLineEndList::Create) selber zusammenbasteln,
173 // um von den konfigurierten Linienenden unabhaengig zu sein
175 basegfx::B2DPolygon aTriangle
;
176 aTriangle
.append(basegfx::B2DPoint(10.0, 0.0));
177 aTriangle
.append(basegfx::B2DPoint(0.0, 30.0));
178 aTriangle
.append(basegfx::B2DPoint(20.0, 30.0));
179 aTriangle
.setClosed(true);
181 basegfx::B2DPolygon aSquare
;
182 aSquare
.append(basegfx::B2DPoint(0.0, 0.0));
183 aSquare
.append(basegfx::B2DPoint(10.0, 0.0));
184 aSquare
.append(basegfx::B2DPoint(10.0, 10.0));
185 aSquare
.append(basegfx::B2DPoint(0.0, 10.0));
186 aSquare
.setClosed(true);
188 basegfx::B2DPolygon
aCircle(basegfx::tools::createPolygonFromEllipse(basegfx::B2DPoint(0.0, 0.0), 100.0, 100.0));
189 aCircle
.setClosed(true);
191 String aName
= SC_LINEEND_NAME
;
193 aArrowSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aCircle
) ) );
194 aArrowSet
.Put( XLineStartWidthItem( 200 ) );
195 aArrowSet
.Put( XLineStartCenterItem( TRUE
) );
196 aArrowSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
197 aArrowSet
.Put( XLineEndWidthItem( 200 ) );
198 aArrowSet
.Put( XLineEndCenterItem( FALSE
) );
200 aToTabSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aCircle
) ) );
201 aToTabSet
.Put( XLineStartWidthItem( 200 ) );
202 aToTabSet
.Put( XLineStartCenterItem( TRUE
) );
203 aToTabSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aSquare
) ) );
204 aToTabSet
.Put( XLineEndWidthItem( 300 ) );
205 aToTabSet
.Put( XLineEndCenterItem( FALSE
) );
207 aFromTabSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aSquare
) ) );
208 aFromTabSet
.Put( XLineStartWidthItem( 300 ) );
209 aFromTabSet
.Put( XLineStartCenterItem( TRUE
) );
210 aFromTabSet
.Put( XLineEndItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
211 aFromTabSet
.Put( XLineEndWidthItem( 200 ) );
212 aFromTabSet
.Put( XLineEndCenterItem( FALSE
) );
214 aCircleSet
.Put( XLineColorItem( String(), Color( ScDetectiveFunc::GetErrorColor() ) ) );
215 aCircleSet
.Put( XFillStyleItem( XFILL_NONE
) );
216 USHORT nWidth
= 55; // 54 = 1 Pixel
217 aCircleSet
.Put( XLineWidthItem( nWidth
) );
220 ScCommentData::ScCommentData( ScDocument
& rDoc
, SdrModel
* pModel
) :
221 aCaptionSet( pModel
->GetItemPool(), SDRATTR_START
, SDRATTR_END
, EE_ITEMS_START
, EE_ITEMS_END
, 0, 0 )
223 basegfx::B2DPolygon aTriangle
;
224 aTriangle
.append(basegfx::B2DPoint(10.0, 0.0));
225 aTriangle
.append(basegfx::B2DPoint(0.0, 30.0));
226 aTriangle
.append(basegfx::B2DPoint(20.0, 30.0));
227 aTriangle
.setClosed(true);
229 String aName
= SC_LINEEND_NAME
;
231 aCaptionSet
.Put( XLineStartItem( aName
, basegfx::B2DPolyPolygon(aTriangle
) ) );
232 aCaptionSet
.Put( XLineStartWidthItem( 200 ) );
233 aCaptionSet
.Put( XLineStartCenterItem( FALSE
) );
234 aCaptionSet
.Put( XFillStyleItem( XFILL_SOLID
) );
235 Color
aYellow( ScDetectiveFunc::GetCommentColor() );
236 aCaptionSet
.Put( XFillColorItem( String(), aYellow
) );
239 // SdrShadowItem has FALSE, instead the shadow is set for the rectangle
240 // only with SetSpecialTextBoxShadow when the object is created
241 // (item must be set to adjust objects from older files)
242 aCaptionSet
.Put( SdrShadowItem( FALSE
) );
243 aCaptionSet
.Put( SdrShadowXDistItem( 100 ) );
244 aCaptionSet
.Put( SdrShadowYDistItem( 100 ) );
247 aCaptionSet
.Put( SdrTextLeftDistItem( 100 ) );
248 aCaptionSet
.Put( SdrTextRightDistItem( 100 ) );
249 aCaptionSet
.Put( SdrTextUpperDistItem( 100 ) );
250 aCaptionSet
.Put( SdrTextLowerDistItem( 100 ) );
252 aCaptionSet
.Put( SdrTextAutoGrowWidthItem( FALSE
) );
253 aCaptionSet
.Put( SdrTextAutoGrowHeightItem( TRUE
) );
255 // #78943# do use the default cell style, so the user has a chance to
256 // modify the font for the annotations
257 ((const ScPatternAttr
&)rDoc
.GetPool()->GetDefaultItem(ATTR_PATTERN
)).
258 FillEditItemSet( &aCaptionSet
);
260 // support the best position for the tail connector now that
261 // that notes can be resized and repositioned.
262 aCaptionSet
.Put( SdrCaptionEscDirItem( SDRCAPT_ESCBESTFIT
) );
265 void ScCommentData::UpdateCaptionSet( const SfxItemSet
& rItemSet
)
267 SfxWhichIter
aWhichIter( rItemSet
);
268 const SfxPoolItem
* pPoolItem
= 0;
270 for( USHORT nWhich
= aWhichIter
.FirstWhich(); nWhich
> 0; nWhich
= aWhichIter
.NextWhich() )
272 if(rItemSet
.GetItemState(nWhich
, FALSE
, &pPoolItem
) == SFX_ITEM_SET
)
277 // use existing Caption default - appears that setting this
278 // to true screws up the tail appearance. See also comment
279 // for default setting above.
281 case SDRATTR_SHADOWXDIST
:
282 // use existing Caption default - svx sets a value of 35
283 // but default 100 gives a better appearance.
285 case SDRATTR_SHADOWYDIST
:
286 // use existing Caption default - svx sets a value of 35
287 // but default 100 gives a better appearance.
291 aCaptionSet
.Put(*pPoolItem
);
297 //------------------------------------------------------------------------
299 void ScDetectiveFunc::Modified()
301 if (pDoc
->IsStreamValid(nTab
))
302 pDoc
->SetStreamValid(nTab
, FALSE
);
305 inline BOOL
Intersect( SCCOL nStartCol1
, SCROW nStartRow1
, SCCOL nEndCol1
, SCROW nEndRow1
,
306 SCCOL nStartCol2
, SCROW nStartRow2
, SCCOL nEndCol2
, SCROW nEndRow2
)
308 return nEndCol1
>= nStartCol2
&& nEndCol2
>= nStartCol1
&&
309 nEndRow1
>= nStartRow2
&& nEndRow2
>= nStartRow1
;
312 BOOL
ScDetectiveFunc::HasError( const ScRange
& rRange
, ScAddress
& rErrPos
)
314 rErrPos
= rRange
.aStart
;
317 ScCellIterator
aCellIter( pDoc
, rRange
);
318 ScBaseCell
* pCell
= aCellIter
.GetFirst();
321 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
323 nError
= ((ScFormulaCell
*)pCell
)->GetErrCode();
325 rErrPos
.Set( aCellIter
.GetCol(), aCellIter
.GetRow(), aCellIter
.GetTab() );
327 pCell
= aCellIter
.GetNext();
330 return (nError
!= 0);
333 Point
ScDetectiveFunc::GetDrawPos( SCCOL nCol
, SCROW nRow
, DrawPosMode eMode
) const
335 DBG_ASSERT( ValidColRow( nCol
, nRow
), "ScDetectiveFunc::GetDrawPos - invalid cell address" );
343 case DRAWPOS_TOPLEFT
:
345 case DRAWPOS_BOTTOMRIGHT
:
349 case DRAWPOS_DETARROW
:
350 aPos
.X() += pDoc
->GetColWidth( nCol
, nTab
) / 4;
351 aPos
.Y() += pDoc
->GetRowHeight( nRow
, nTab
) / 2;
353 case DRAWPOS_CAPTIONLEFT
:
356 case DRAWPOS_CAPTIONRIGHT
:
358 // find right end of passed cell position
359 const ScMergeAttr
* pMerge
= static_cast< const ScMergeAttr
* >( pDoc
->GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE
) );
360 if ( pMerge
->GetColMerge() > 1 )
361 nCol
= nCol
+ pMerge
->GetColMerge();
369 for ( SCCOL i
= 0; i
< nCol
; ++i
)
370 aPos
.X() += pDoc
->GetColWidth( i
, nTab
);
371 aPos
.Y() += pDoc
->FastGetRowHeight( 0, nRow
- 1, nTab
);
373 aPos
.X() = static_cast< long >( aPos
.X() * HMM_PER_TWIPS
);
374 aPos
.Y() = static_cast< long >( aPos
.Y() * HMM_PER_TWIPS
);
376 if ( pDoc
->IsNegativePage( nTab
) )
382 Rectangle
ScDetectiveFunc::GetDrawRect( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) const
385 GetDrawPos( ::std::min( nCol1
, nCol2
), ::std::min( nRow1
, nRow2
), DRAWPOS_TOPLEFT
),
386 GetDrawPos( ::std::max( nCol1
, nCol2
), ::std::max( nRow1
, nRow2
), DRAWPOS_BOTTOMRIGHT
) );
387 aRect
.Justify(); // reorder left/right in RTL sheets
391 Rectangle
ScDetectiveFunc::GetDrawRect( SCCOL nCol
, SCROW nRow
) const
393 return GetDrawRect( nCol
, nRow
, nCol
, nRow
);
396 BOOL
lcl_IsOtherTab( const basegfx::B2DPolyPolygon
& rPolyPolygon
)
398 // test if rPolygon is the line end for "other table" (rectangle)
399 if(1L == rPolyPolygon
.count())
401 const basegfx::B2DPolygon
aSubPoly(rPolyPolygon
.getB2DPolygon(0L));
403 // #i73305# circle consists of 4 segments, too, distinguishable from square by
404 // the use of control points
405 if(4L == aSubPoly
.count() && aSubPoly
.isClosed() && !aSubPoly
.areControlPointsUsed())
414 BOOL
ScDetectiveFunc::HasArrow( const ScAddress
& rStart
,
415 SCCOL nEndCol
, SCROW nEndRow
, SCTAB nEndTab
)
417 BOOL bStartAlien
= ( rStart
.Tab() != nTab
);
418 BOOL bEndAlien
= ( nEndTab
!= nTab
);
420 if (bStartAlien
&& bEndAlien
)
422 DBG_ERROR("bStartAlien && bEndAlien");
426 Rectangle aStartRect
;
429 aStartRect
= GetDrawRect( rStart
.Col(), rStart
.Row() );
431 aEndRect
= GetDrawRect( nEndCol
, nEndRow
);
433 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
434 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
435 DBG_ASSERT(pPage
,"Page ?");
438 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
439 SdrObject
* pObject
= aIter
.Next();
440 while (pObject
&& !bFound
)
442 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
443 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
445 const SfxItemSet
& rSet
= pObject
->GetMergedItemSet();
447 BOOL bObjStartAlien
=
448 lcl_IsOtherTab( ((const XLineStartItem
&)rSet
.Get(XATTR_LINESTART
)).GetLineStartValue() );
450 lcl_IsOtherTab( ((const XLineEndItem
&)rSet
.Get(XATTR_LINEEND
)).GetLineEndValue() );
452 BOOL bStartHit
= bStartAlien
? bObjStartAlien
:
453 ( !bObjStartAlien
&& aStartRect
.IsInside(pObject
->GetPoint(0)) );
454 BOOL bEndHit
= bEndAlien
? bObjEndAlien
:
455 ( !bObjEndAlien
&& aEndRect
.IsInside(pObject
->GetPoint(1)) );
457 if ( bStartHit
&& bEndHit
)
460 pObject
= aIter
.Next();
466 BOOL
ScDetectiveFunc::IsNonAlienArrow( SdrObject
* pObject
) // static
468 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
469 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
471 const SfxItemSet
& rSet
= pObject
->GetMergedItemSet();
473 BOOL bObjStartAlien
=
474 lcl_IsOtherTab( ((const XLineStartItem
&)rSet
.Get(XATTR_LINESTART
)).GetLineStartValue() );
476 lcl_IsOtherTab( ((const XLineEndItem
&)rSet
.Get(XATTR_LINEEND
)).GetLineEndValue() );
478 return !bObjStartAlien
&& !bObjEndAlien
;
484 //------------------------------------------------------------------------
486 // InsertXXX: called from DrawEntry/DrawAlienEntry and InsertObject
488 BOOL
ScDetectiveFunc::InsertArrow( SCCOL nCol
, SCROW nRow
,
489 SCCOL nRefStartCol
, SCROW nRefStartRow
,
490 SCCOL nRefEndCol
, SCROW nRefEndRow
,
491 BOOL bFromOtherTab
, BOOL bRed
,
492 ScDetectiveData
& rData
)
494 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
495 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
497 BOOL bArea
= ( nRefStartCol
!= nRefEndCol
|| nRefStartRow
!= nRefEndRow
);
498 if (bArea
&& !bFromOtherTab
)
500 // insert the rectangle before the arrow - this is relied on in FindFrameForObject
502 Rectangle aRect
= GetDrawRect( nRefStartCol
, nRefStartRow
, nRefEndCol
, nRefEndRow
);
503 SdrRectObj
* pBox
= new SdrRectObj( aRect
);
505 pBox
->SetMergedItemSetAndBroadcast(rData
.GetBoxSet());
507 ScDrawLayer::SetAnchor( pBox
, SCA_CELL
);
508 pBox
->SetLayer( SC_LAYER_INTERN
);
509 pPage
->InsertObject( pBox
);
510 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pBox
) );
512 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pBox
, TRUE
);
513 pData
->maStart
.Set( nRefStartCol
, nRefStartRow
, nTab
);
514 pData
->maEnd
.Set( nRefEndCol
, nRefEndRow
, nTab
);
517 Point aStartPos
= GetDrawPos( nRefStartCol
, nRefStartRow
, DRAWPOS_DETARROW
);
518 Point aEndPos
= GetDrawPos( nCol
, nRow
, DRAWPOS_DETARROW
);
522 BOOL bNegativePage
= pDoc
->IsNegativePage( nTab
);
523 long nPageSign
= bNegativePage
? -1 : 1;
525 aStartPos
= Point( aEndPos
.X() - 1000 * nPageSign
, aEndPos
.Y() - 1000 );
526 if (aStartPos
.X() * nPageSign
< 0)
527 aStartPos
.X() += 2000 * nPageSign
;
528 if (aStartPos
.Y() < 0)
529 aStartPos
.Y() += 2000;
532 SfxItemSet
& rAttrSet
= bFromOtherTab
? rData
.GetFromTabSet() : rData
.GetArrowSet();
534 if (bArea
&& !bFromOtherTab
)
535 rAttrSet
.Put( XLineWidthItem( 50 ) ); // Bereich
537 rAttrSet
.Put( XLineWidthItem( 0 ) ); // einzelne Referenz
539 ColorData nColorData
= ( bRed
? GetErrorColor() : GetArrowColor() );
540 rAttrSet
.Put( XLineColorItem( String(), Color( nColorData
) ) );
542 basegfx::B2DPolygon aTempPoly
;
543 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
544 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
545 SdrPathObj
* pArrow
= new SdrPathObj(OBJ_LINE
, basegfx::B2DPolyPolygon(aTempPoly
));
546 pArrow
->NbcSetLogicRect(Rectangle(aStartPos
,aEndPos
)); //! noetig ???
547 pArrow
->SetMergedItemSetAndBroadcast(rAttrSet
);
549 ScDrawLayer::SetAnchor( pArrow
, SCA_CELL
);
550 pArrow
->SetLayer( SC_LAYER_INTERN
);
551 pPage
->InsertObject( pArrow
);
552 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pArrow
) );
554 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pArrow
, TRUE
);
556 pData
->maStart
.SetInvalid();
558 pData
->maStart
.Set( nRefStartCol
, nRefStartRow
, nTab
);
560 pData
->maEnd
.Set( nCol
, nRow
, nTab
);
566 BOOL
ScDetectiveFunc::InsertToOtherTab( SCCOL nStartCol
, SCROW nStartRow
,
567 SCCOL nEndCol
, SCROW nEndRow
, BOOL bRed
,
568 ScDetectiveData
& rData
)
570 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
571 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
573 BOOL bArea
= ( nStartCol
!= nEndCol
|| nStartRow
!= nEndRow
);
576 Rectangle aRect
= GetDrawRect( nStartCol
, nStartRow
, nEndCol
, nEndRow
);
577 SdrRectObj
* pBox
= new SdrRectObj( aRect
);
579 pBox
->SetMergedItemSetAndBroadcast(rData
.GetBoxSet());
581 ScDrawLayer::SetAnchor( pBox
, SCA_CELL
);
582 pBox
->SetLayer( SC_LAYER_INTERN
);
583 pPage
->InsertObject( pBox
);
584 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pBox
) );
586 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pBox
, TRUE
);
587 pData
->maStart
.Set( nStartCol
, nStartRow
, nTab
);
588 pData
->maEnd
.Set( nEndCol
, nEndRow
, nTab
);
591 BOOL bNegativePage
= pDoc
->IsNegativePage( nTab
);
592 long nPageSign
= bNegativePage
? -1 : 1;
594 Point aStartPos
= GetDrawPos( nStartCol
, nStartRow
, DRAWPOS_DETARROW
);
595 Point aEndPos
= Point( aStartPos
.X() + 1000 * nPageSign
, aStartPos
.Y() - 1000 );
599 SfxItemSet
& rAttrSet
= rData
.GetToTabSet();
601 rAttrSet
.Put( XLineWidthItem( 50 ) ); // Bereich
603 rAttrSet
.Put( XLineWidthItem( 0 ) ); // einzelne Referenz
605 ColorData nColorData
= ( bRed
? GetErrorColor() : GetArrowColor() );
606 rAttrSet
.Put( XLineColorItem( String(), Color( nColorData
) ) );
608 basegfx::B2DPolygon aTempPoly
;
609 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
610 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
611 SdrPathObj
* pArrow
= new SdrPathObj(OBJ_LINE
, basegfx::B2DPolyPolygon(aTempPoly
));
612 pArrow
->NbcSetLogicRect(Rectangle(aStartPos
,aEndPos
)); //! noetig ???
614 pArrow
->SetMergedItemSetAndBroadcast(rAttrSet
);
616 ScDrawLayer::SetAnchor( pArrow
, SCA_CELL
);
617 pArrow
->SetLayer( SC_LAYER_INTERN
);
618 pPage
->InsertObject( pArrow
);
619 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pArrow
) );
621 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pArrow
, TRUE
);
622 pData
->maStart
.Set( nStartCol
, nStartRow
, nTab
);
623 pData
->maEnd
.SetInvalid();
629 //------------------------------------------------------------------------
631 // DrawEntry: Formel auf dieser Tabelle,
632 // Referenz auf dieser oder anderer
633 // DrawAlienEntry: Formel auf anderer Tabelle,
634 // Referenz auf dieser
636 // return FALSE: da war schon ein Pfeil
638 BOOL
ScDetectiveFunc::DrawEntry( SCCOL nCol
, SCROW nRow
,
640 ScDetectiveData
& rData
)
642 if ( HasArrow( rRef
.aStart
, nCol
, nRow
, nTab
) )
646 BOOL bError
= HasError( rRef
, aErrorPos
);
647 BOOL bAlien
= ( rRef
.aEnd
.Tab() < nTab
|| rRef
.aStart
.Tab() > nTab
);
649 return InsertArrow( nCol
, nRow
,
650 rRef
.aStart
.Col(), rRef
.aStart
.Row(),
651 rRef
.aEnd
.Col(), rRef
.aEnd
.Row(),
652 bAlien
, bError
, rData
);
655 BOOL
ScDetectiveFunc::DrawAlienEntry( const ScRange
& rRef
,
656 ScDetectiveData
& rData
)
658 if ( HasArrow( rRef
.aStart
, 0, 0, nTab
+1 ) )
662 BOOL bError
= HasError( rRef
, aErrorPos
);
664 return InsertToOtherTab( rRef
.aStart
.Col(), rRef
.aStart
.Row(),
665 rRef
.aEnd
.Col(), rRef
.aEnd
.Row(),
669 void ScDetectiveFunc::DrawCircle( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
)
671 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
672 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
674 Rectangle aRect
= GetDrawRect( nCol
, nRow
);
676 aRect
.Right() += 250;
678 aRect
.Bottom() += 70;
680 SdrCircObj
* pCircle
= new SdrCircObj( OBJ_CIRC
, aRect
);
681 SfxItemSet
& rAttrSet
= rData
.GetCircleSet();
683 pCircle
->SetMergedItemSetAndBroadcast(rAttrSet
);
685 ScDrawLayer::SetAnchor( pCircle
, SCA_CELL
);
686 pCircle
->SetLayer( SC_LAYER_INTERN
);
687 pPage
->InsertObject( pCircle
);
688 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pCircle
) );
690 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pCircle
, TRUE
);
691 pData
->maStart
.Set( nCol
, nRow
, nTab
);
692 pData
->maEnd
.SetInvalid();
697 void ScDetectiveFunc::DeleteArrowsAt( SCCOL nCol
, SCROW nRow
, BOOL bDestPnt
)
699 Rectangle aRect
= GetDrawRect( nCol
, nRow
);
701 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
702 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
703 DBG_ASSERT(pPage
,"Page ?");
705 pPage
->RecalcObjOrdNums();
708 ULONG nObjCount
= pPage
->GetObjCount();
711 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
713 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
714 SdrObject
* pObject
= aIter
.Next();
717 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
718 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
720 if (aRect
.IsInside(pObject
->GetPoint(bDestPnt
))) // Start/Zielpunkt
721 ppObj
[nDelCount
++] = pObject
;
724 pObject
= aIter
.Next();
728 for (i
=1; i
<=nDelCount
; i
++)
729 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
731 for (i
=1; i
<=nDelCount
; i
++)
732 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
740 // Box um Referenz loeschen
742 #define SC_DET_TOLERANCE 50
744 inline BOOL
RectIsPoints( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
746 return rRect
.Left() >= rStart
.X() - SC_DET_TOLERANCE
747 && rRect
.Left() <= rStart
.X() + SC_DET_TOLERANCE
748 && rRect
.Right() >= rEnd
.X() - SC_DET_TOLERANCE
749 && rRect
.Right() <= rEnd
.X() + SC_DET_TOLERANCE
750 && rRect
.Top() >= rStart
.Y() - SC_DET_TOLERANCE
751 && rRect
.Top() <= rStart
.Y() + SC_DET_TOLERANCE
752 && rRect
.Bottom() >= rEnd
.Y() - SC_DET_TOLERANCE
753 && rRect
.Bottom() <= rEnd
.Y() + SC_DET_TOLERANCE
;
756 #undef SC_DET_TOLERANCE
758 void ScDetectiveFunc::DeleteBox( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
768 InfoBox(0,aStr).Execute();
771 Rectangle aCornerRect
= GetDrawRect( nCol1
, nRow1
, nCol2
, nRow2
);
772 Point aStartCorner
= aCornerRect
.TopLeft();
773 Point aEndCorner
= aCornerRect
.BottomRight();
776 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
777 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
778 DBG_ASSERT(pPage
,"Page ?");
780 pPage
->RecalcObjOrdNums();
783 ULONG nObjCount
= pPage
->GetObjCount();
786 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
788 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
789 SdrObject
* pObject
= aIter
.Next();
792 if ( pObject
->GetLayer() == SC_LAYER_INTERN
&&
793 pObject
->Type() == TYPE(SdrRectObj
) )
795 aObjRect
= ((SdrRectObj
*)pObject
)->GetLogicRect();
797 if ( RectIsPoints( aObjRect
, aStartCorner
, aEndCorner
) )
798 ppObj
[nDelCount
++] = pObject
;
801 pObject
= aIter
.Next();
805 for (i
=1; i
<=nDelCount
; i
++)
806 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
808 for (i
=1; i
<=nDelCount
; i
++)
809 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
817 //------------------------------------------------------------------------
819 USHORT
ScDetectiveFunc::InsertPredLevelArea( const ScRange
& rRef
,
820 ScDetectiveData
& rData
, USHORT nLevel
)
822 USHORT nResult
= DET_INS_EMPTY
;
824 ScCellIterator
aCellIter( pDoc
, rRef
);
825 ScBaseCell
* pCell
= aCellIter
.GetFirst();
828 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
829 switch( InsertPredLevel( aCellIter
.GetCol(), aCellIter
.GetRow(), rData
, nLevel
) )
831 case DET_INS_INSERTED
:
832 nResult
= DET_INS_INSERTED
;
834 case DET_INS_CONTINUE
:
835 if (nResult
!= DET_INS_INSERTED
)
836 nResult
= DET_INS_CONTINUE
;
838 case DET_INS_CIRCULAR
:
839 if (nResult
== DET_INS_EMPTY
)
840 nResult
= DET_INS_CIRCULAR
;
844 pCell
= aCellIter
.GetNext();
850 USHORT
ScDetectiveFunc::InsertPredLevel( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
,
854 pDoc
->GetCell( nCol
, nRow
, nTab
, pCell
);
856 return DET_INS_EMPTY
;
857 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
858 return DET_INS_EMPTY
;
860 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
861 if (pFCell
->IsRunning())
862 return DET_INS_CIRCULAR
;
864 if (pFCell
->GetDirty())
865 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
866 pFCell
->SetRunning(TRUE
);
868 USHORT nResult
= DET_INS_EMPTY
;
870 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
872 while ( aIter
.GetNextRef( aRef
) )
874 if (DrawEntry( nCol
, nRow
, aRef
, rData
))
876 nResult
= DET_INS_INSERTED
; // neuer Pfeil eingetragen
882 if ( nLevel
< rData
.GetMaxLevel() )
885 BOOL bArea
= (aRef
.aStart
!= aRef
.aEnd
);
887 nSubResult
= InsertPredLevelArea( aRef
, rData
, nLevel
+1 );
889 nSubResult
= InsertPredLevel( aRef
.aStart
.Col(), aRef
.aStart
.Row(),
894 case DET_INS_INSERTED
:
895 nResult
= DET_INS_INSERTED
;
897 case DET_INS_CONTINUE
:
898 if (nResult
!= DET_INS_INSERTED
)
899 nResult
= DET_INS_CONTINUE
;
901 case DET_INS_CIRCULAR
:
902 if (nResult
== DET_INS_EMPTY
)
903 nResult
= DET_INS_CIRCULAR
;
905 // DET_INS_EMPTY: unveraendert lassen
908 else // nMaxLevel erreicht
909 if (nResult
!= DET_INS_INSERTED
)
910 nResult
= DET_INS_CONTINUE
;
914 pFCell
->SetRunning(FALSE
);
919 USHORT
ScDetectiveFunc::FindPredLevelArea( const ScRange
& rRef
,
920 USHORT nLevel
, USHORT nDeleteLevel
)
922 USHORT nResult
= nLevel
;
924 ScCellIterator
aCellIter( pDoc
, rRef
);
925 ScBaseCell
* pCell
= aCellIter
.GetFirst();
928 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
930 USHORT nTemp
= FindPredLevel( aCellIter
.GetCol(), aCellIter
.GetRow(), nLevel
, nDeleteLevel
);
934 pCell
= aCellIter
.GetNext();
940 // nDeleteLevel != 0 -> loeschen
942 USHORT
ScDetectiveFunc::FindPredLevel( SCCOL nCol
, SCROW nRow
, USHORT nLevel
, USHORT nDeleteLevel
)
944 DBG_ASSERT( nLevel
<1000, "Level" );
947 pDoc
->GetCell( nCol
, nRow
, nTab
, pCell
);
950 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
953 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
954 if (pFCell
->IsRunning())
957 if (pFCell
->GetDirty())
958 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
959 pFCell
->SetRunning(TRUE
);
961 USHORT nResult
= nLevel
;
962 BOOL bDelete
= ( nDeleteLevel
&& nLevel
== nDeleteLevel
-1 );
966 DeleteArrowsAt( nCol
, nRow
, TRUE
); // Pfeile, die hierher zeigen
969 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
971 while ( aIter
.GetNextRef( aRef
) )
973 BOOL bArea
= ( aRef
.aStart
!= aRef
.aEnd
);
975 if ( bDelete
) // Rahmen loeschen ?
979 DeleteBox( aRef
.aStart
.Col(), aRef
.aStart
.Row(), aRef
.aEnd
.Col(), aRef
.aEnd
.Row() );
984 if ( HasArrow( aRef
.aStart
, nCol
,nRow
,nTab
) )
988 nTemp
= FindPredLevelArea( aRef
, nLevel
+1, nDeleteLevel
);
990 nTemp
= FindPredLevel( aRef
.aStart
.Col(),aRef
.aStart
.Row(),
991 nLevel
+1, nDeleteLevel
);
998 pFCell
->SetRunning(FALSE
);
1003 //------------------------------------------------------------------------
1005 USHORT
ScDetectiveFunc::InsertErrorLevel( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
,
1009 pDoc
->GetCell( nCol
, nRow
, nTab
, pCell
);
1011 return DET_INS_EMPTY
;
1012 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
1013 return DET_INS_EMPTY
;
1015 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
1016 if (pFCell
->IsRunning())
1017 return DET_INS_CIRCULAR
;
1019 if (pFCell
->GetDirty())
1020 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
1021 pFCell
->SetRunning(TRUE
);
1023 USHORT nResult
= DET_INS_EMPTY
;
1025 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
1027 ScAddress aErrorPos
;
1028 BOOL bHasError
= FALSE
;
1029 while ( aIter
.GetNextRef( aRef
) )
1031 if (HasError( aRef
, aErrorPos
))
1034 if (DrawEntry( nCol
, nRow
, ScRange( aErrorPos
), rData
))
1035 nResult
= DET_INS_INSERTED
;
1037 // und weiterverfolgen
1039 if ( nLevel
< rData
.GetMaxLevel() ) // praktisch immer
1041 if (InsertErrorLevel( aErrorPos
.Col(), aErrorPos
.Row(),
1042 rData
, nLevel
+1 ) == DET_INS_INSERTED
)
1043 nResult
= DET_INS_INSERTED
;
1048 pFCell
->SetRunning(FALSE
);
1052 if (InsertPredLevel( nCol
, nRow
, rData
, rData
.GetMaxLevel() ) == DET_INS_INSERTED
)
1053 nResult
= DET_INS_INSERTED
;
1058 //------------------------------------------------------------------------
1060 USHORT
ScDetectiveFunc::InsertSuccLevel( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1061 ScDetectiveData
& rData
, USHORT nLevel
)
1063 // ueber ganzes Dokument
1065 USHORT nResult
= DET_INS_EMPTY
;
1066 // ScCellIterator aCellIter( pDoc, 0,0, nTab, MAXCOL,MAXROW, nTab );
1067 ScCellIterator
aCellIter( pDoc
, 0,0,0, MAXCOL
,MAXROW
,MAXTAB
); // alle Tabellen
1068 ScBaseCell
* pCell
= aCellIter
.GetFirst();
1071 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1073 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
1074 BOOL bRunning
= pFCell
->IsRunning();
1076 if (pFCell
->GetDirty())
1077 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
1078 pFCell
->SetRunning(TRUE
);
1080 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
1082 while ( aIter
.GetNextRef( aRef
) )
1084 if (aRef
.aStart
.Tab() <= nTab
&& aRef
.aEnd
.Tab() >= nTab
)
1086 if (Intersect( nCol1
,nRow1
,nCol2
,nRow2
,
1087 aRef
.aStart
.Col(),aRef
.aStart
.Row(),
1088 aRef
.aEnd
.Col(),aRef
.aEnd
.Row() ))
1090 BOOL bAlien
= ( aCellIter
.GetTab() != nTab
);
1093 bDrawRet
= DrawAlienEntry( aRef
, rData
);
1095 bDrawRet
= DrawEntry( aCellIter
.GetCol(), aCellIter
.GetRow(),
1099 nResult
= DET_INS_INSERTED
; // neuer Pfeil eingetragen
1105 if (nResult
== DET_INS_EMPTY
)
1106 nResult
= DET_INS_CIRCULAR
;
1112 if ( nLevel
< rData
.GetMaxLevel() )
1114 USHORT nSubResult
= InsertSuccLevel(
1115 aCellIter
.GetCol(), aCellIter
.GetRow(),
1116 aCellIter
.GetCol(), aCellIter
.GetRow(),
1120 case DET_INS_INSERTED
:
1121 nResult
= DET_INS_INSERTED
;
1123 case DET_INS_CONTINUE
:
1124 if (nResult
!= DET_INS_INSERTED
)
1125 nResult
= DET_INS_CONTINUE
;
1127 case DET_INS_CIRCULAR
:
1128 if (nResult
== DET_INS_EMPTY
)
1129 nResult
= DET_INS_CIRCULAR
;
1131 // DET_INS_EMPTY: unveraendert lassen
1134 else // nMaxLevel erreicht
1135 if (nResult
!= DET_INS_INSERTED
)
1136 nResult
= DET_INS_CONTINUE
;
1142 pFCell
->SetRunning(bRunning
);
1144 pCell
= aCellIter
.GetNext();
1150 USHORT
ScDetectiveFunc::FindSuccLevel( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1151 USHORT nLevel
, USHORT nDeleteLevel
)
1153 DBG_ASSERT( nLevel
<1000, "Level" );
1155 USHORT nResult
= nLevel
;
1156 BOOL bDelete
= ( nDeleteLevel
&& nLevel
== nDeleteLevel
-1 );
1158 ScCellIterator
aCellIter( pDoc
, 0,0, nTab
, MAXCOL
,MAXROW
, nTab
);
1159 ScBaseCell
* pCell
= aCellIter
.GetFirst();
1162 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1164 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
1165 BOOL bRunning
= pFCell
->IsRunning();
1167 if (pFCell
->GetDirty())
1168 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
1169 pFCell
->SetRunning(TRUE
);
1171 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
1173 while ( aIter
.GetNextRef( aRef
) )
1175 if (aRef
.aStart
.Tab() <= nTab
&& aRef
.aEnd
.Tab() >= nTab
)
1177 if (Intersect( nCol1
,nRow1
,nCol2
,nRow2
,
1178 aRef
.aStart
.Col(),aRef
.aStart
.Row(),
1179 aRef
.aEnd
.Col(),aRef
.aEnd
.Row() ))
1181 if ( bDelete
) // Pfeile, die hier anfangen
1183 if (aRef
.aStart
!= aRef
.aEnd
)
1185 DeleteBox( aRef
.aStart
.Col(), aRef
.aStart
.Row(),
1186 aRef
.aEnd
.Col(), aRef
.aEnd
.Row() );
1188 DeleteArrowsAt( aRef
.aStart
.Col(), aRef
.aStart
.Row(), FALSE
);
1190 else if ( !bRunning
&&
1191 HasArrow( aRef
.aStart
,
1192 aCellIter
.GetCol(),aCellIter
.GetRow(),aCellIter
.GetTab() ) )
1194 USHORT nTemp
= FindSuccLevel( aCellIter
.GetCol(), aCellIter
.GetRow(),
1195 aCellIter
.GetCol(), aCellIter
.GetRow(),
1196 nLevel
+1, nDeleteLevel
);
1197 if (nTemp
> nResult
)
1204 pFCell
->SetRunning(bRunning
);
1206 pCell
= aCellIter
.GetNext();
1214 // --------------------------------------------------------------------------------
1217 BOOL
ScDetectiveFunc::ShowPred( SCCOL nCol
, SCROW nRow
)
1219 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1223 ScDetectiveData
aData( pModel
);
1225 USHORT nMaxLevel
= 0;
1226 USHORT nResult
= DET_INS_CONTINUE
;
1227 while (nResult
== DET_INS_CONTINUE
&& nMaxLevel
< 1000)
1229 aData
.SetMaxLevel( nMaxLevel
);
1230 nResult
= InsertPredLevel( nCol
, nRow
, aData
, 0 );
1234 return ( nResult
== DET_INS_INSERTED
);
1237 BOOL
ScDetectiveFunc::ShowSucc( SCCOL nCol
, SCROW nRow
)
1239 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1243 ScDetectiveData
aData( pModel
);
1245 USHORT nMaxLevel
= 0;
1246 USHORT nResult
= DET_INS_CONTINUE
;
1247 while (nResult
== DET_INS_CONTINUE
&& nMaxLevel
< 1000)
1249 aData
.SetMaxLevel( nMaxLevel
);
1250 nResult
= InsertSuccLevel( nCol
, nRow
, nCol
, nRow
, aData
, 0 );
1254 return ( nResult
== DET_INS_INSERTED
);
1257 BOOL
ScDetectiveFunc::ShowError( SCCOL nCol
, SCROW nRow
)
1259 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1263 ScRange
aRange( nCol
, nRow
, nTab
);
1265 if ( !HasError( aRange
,aErrPos
) )
1268 ScDetectiveData
aData( pModel
);
1270 aData
.SetMaxLevel( 1000 );
1271 USHORT nResult
= InsertErrorLevel( nCol
, nRow
, aData
, 0 );
1273 return ( nResult
== DET_INS_INSERTED
);
1276 BOOL
ScDetectiveFunc::DeleteSucc( SCCOL nCol
, SCROW nRow
)
1278 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1282 USHORT nLevelCount
= FindSuccLevel( nCol
, nRow
, nCol
, nRow
, 0, 0 );
1284 FindSuccLevel( nCol
, nRow
, nCol
, nRow
, 0, nLevelCount
); // loeschen
1286 return ( nLevelCount
!= 0 );
1289 BOOL
ScDetectiveFunc::DeletePred( SCCOL nCol
, SCROW nRow
)
1291 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1295 USHORT nLevelCount
= FindPredLevel( nCol
, nRow
, 0, 0 );
1297 FindPredLevel( nCol
, nRow
, 0, nLevelCount
); // loeschen
1299 return ( nLevelCount
!= 0 );
1302 BOOL
ScDetectiveFunc::DeleteAll( ScDetectiveDelete eWhat
)
1304 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1308 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
1309 DBG_ASSERT(pPage
,"Page ?");
1311 pPage
->RecalcObjOrdNums();
1314 ULONG nObjCount
= pPage
->GetObjCount();
1317 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
1319 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1320 SdrObject
* pObject
= aIter
.Next();
1323 if ( pObject
->GetLayer() == SC_LAYER_INTERN
)
1325 BOOL bDoThis
= TRUE
;
1326 if ( eWhat
!= SC_DET_ALL
)
1328 BOOL bCircle
= ( pObject
->ISA(SdrCircObj
) );
1329 BOOL bCaption
= ScDrawLayer::IsNoteCaption( pObject
);
1330 if ( eWhat
== SC_DET_DETECTIVE
) // Detektiv, aus Menue
1331 bDoThis
= !bCaption
; // auch Kreise
1332 else if ( eWhat
== SC_DET_CIRCLES
) // Kreise, wenn neue erzeugt werden
1334 else if ( eWhat
== SC_DET_ARROWS
) // DetectiveRefresh
1335 bDoThis
= !bCaption
&& !bCircle
; // don't include circles
1342 ppObj
[nDelCount
++] = pObject
;
1345 pObject
= aIter
.Next();
1349 for (i
=1; i
<=nDelCount
; i
++)
1350 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
1352 for (i
=1; i
<=nDelCount
; i
++)
1353 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
1360 return ( nDelCount
!= 0 );
1363 BOOL
ScDetectiveFunc::MarkInvalid(BOOL
& rOverflow
)
1366 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1370 BOOL bDeleted
= DeleteAll( SC_DET_CIRCLES
); // nur die Kreise
1372 ScDetectiveData
aData( pModel
);
1375 // Stellen suchen, wo Gueltigkeit definiert ist
1377 ScDocAttrIterator
aAttrIter( pDoc
, nTab
, 0,0,MAXCOL
,MAXROW
);
1381 const ScPatternAttr
* pPattern
= aAttrIter
.GetNext( nCol
, nRow1
, nRow2
);
1382 while ( pPattern
&& nInsCount
< SC_DET_MAXCIRCLE
)
1384 ULONG nIndex
= ((const SfxUInt32Item
&)pPattern
->GetItem(ATTR_VALIDDATA
)).GetValue();
1387 const ScValidationData
* pData
= pDoc
->GetValidationEntry( nIndex
);
1390 // Zellen in dem Bereich durchgehen
1392 BOOL bMarkEmpty
= !pData
->IsIgnoreBlank();
1393 SCROW nNextRow
= nRow1
;
1395 ScCellIterator
aCellIter( pDoc
, nCol
,nRow1
,nTab
, nCol
,nRow2
,nTab
);
1396 ScBaseCell
* pCell
= aCellIter
.GetFirst();
1397 while ( pCell
&& nInsCount
< SC_DET_MAXCIRCLE
)
1399 SCROW nCellRow
= aCellIter
.GetRow();
1401 for ( nRow
= nNextRow
; nRow
< nCellRow
&& nInsCount
< SC_DET_MAXCIRCLE
; nRow
++ )
1403 DrawCircle( nCol
, nRow
, aData
);
1406 if ( !pData
->IsDataValid( pCell
, ScAddress( nCol
, nCellRow
, nTab
) ) )
1408 DrawCircle( nCol
, nCellRow
, aData
);
1411 nNextRow
= nCellRow
+ 1;
1412 pCell
= aCellIter
.GetNext();
1415 for ( nRow
= nNextRow
; nRow
<= nRow2
&& nInsCount
< SC_DET_MAXCIRCLE
; nRow
++ )
1417 DrawCircle( nCol
, nRow
, aData
);
1423 pPattern
= aAttrIter
.GetNext( nCol
, nRow1
, nRow2
);
1426 if ( nInsCount
>= SC_DET_MAXCIRCLE
)
1429 return ( bDeleted
|| nInsCount
!= 0 );
1432 void ScDetectiveFunc::GetAllPreds(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1433 vector
<ScSharedTokenRef
>& rRefTokens
)
1435 ScCellIterator
aCellIter(pDoc
, nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
);
1436 for (ScBaseCell
* pCell
= aCellIter
.GetFirst(); pCell
; pCell
= aCellIter
.GetNext())
1438 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
1441 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1442 ScDetectiveRefIter
aRefIter(pFCell
);
1443 for (ScToken
* p
= aRefIter
.GetNextRefToken(); p
; p
= aRefIter
.GetNextRefToken())
1445 ScSharedTokenRef
pRef(static_cast<ScToken
*>(p
->Clone()));
1446 ScRefTokenHelper::join(rRefTokens
, pRef
);
1451 void ScDetectiveFunc::GetAllSuccs(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1452 vector
<ScSharedTokenRef
>& rRefTokens
)
1454 vector
<ScSharedTokenRef
> aSrcRange
;
1455 aSrcRange
.push_back(
1456 ScRefTokenHelper::createRefToken(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
)));
1458 ScCellIterator
aCellIter(pDoc
, 0, 0, nTab
, MAXCOL
, MAXROW
, nTab
);
1459 for (ScBaseCell
* pCell
= aCellIter
.GetFirst(); pCell
; pCell
= aCellIter
.GetNext())
1461 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
1464 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1465 ScDetectiveRefIter
aRefIter(pFCell
);
1466 for (ScToken
* p
= aRefIter
.GetNextRefToken(); p
; p
= aRefIter
.GetNextRefToken())
1468 ScSharedTokenRef
pRef(static_cast<ScToken
*>(p
->Clone()));
1469 if (ScRefTokenHelper::intersects(aSrcRange
, pRef
))
1471 pRef
= ScRefTokenHelper::createRefToken(aCellIter
.GetPos());
1472 ScRefTokenHelper::join(rRefTokens
, pRef
);
1478 void ScDetectiveFunc::UpdateAllComments( ScDocument
& rDoc
)
1480 // for all caption objects, update attributes and SpecialTextBoxShadow flag
1481 // (on all tables - nTab is ignored!)
1483 // no undo actions, this is refreshed after undo
1485 ScDrawLayer
* pModel
= rDoc
.GetDrawLayer();
1489 for( SCTAB nObjTab
= 0, nTabCount
= rDoc
.GetTableCount(); nObjTab
< nTabCount
; ++nObjTab
)
1491 rDoc
.InitializeNoteCaptions( nObjTab
);
1492 SdrPage
* pPage
= pModel
->GetPage( static_cast< sal_uInt16
>( nObjTab
) );
1493 DBG_ASSERT( pPage
, "Page ?" );
1496 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1497 for( SdrObject
* pObject
= aIter
.Next(); pObject
; pObject
= aIter
.Next() )
1499 if ( ScDrawObjData
* pData
= ScDrawLayer::GetNoteCaptionData( pObject
, nObjTab
) )
1501 ScPostIt
* pNote
= rDoc
.GetNote( pData
->maStart
);
1502 // caption should exist, we iterate over drawing objects...
1503 DBG_ASSERT( pNote
&& (pNote
->GetCaption() == pObject
), "ScDetectiveFunc::UpdateAllComments - invalid cell note" );
1506 ScCommentData
aData( rDoc
, pModel
);
1507 SfxItemSet aAttrColorSet
= pObject
->GetMergedItemSet();
1508 aAttrColorSet
.Put( XFillColorItem( String(), GetCommentColor() ) );
1509 aData
.UpdateCaptionSet( aAttrColorSet
);
1510 pObject
->SetMergedItemSetAndBroadcast( aData
.GetCaptionSet() );
1511 if( SdrCaptionObj
* pCaption
= dynamic_cast< SdrCaptionObj
* >( pObject
) )
1513 pCaption
->SetSpecialTextBoxShadow();
1514 pCaption
->SetFixedTail();
1523 void ScDetectiveFunc::UpdateAllArrowColors()
1525 // no undo actions necessary
1527 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1531 for( SCTAB nObjTab
= 0, nTabCount
= pDoc
->GetTableCount(); nObjTab
< nTabCount
; ++nObjTab
)
1533 SdrPage
* pPage
= pModel
->GetPage( static_cast< sal_uInt16
>( nObjTab
) );
1534 DBG_ASSERT( pPage
, "Page ?" );
1537 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1538 for( SdrObject
* pObject
= aIter
.Next(); pObject
; pObject
= aIter
.Next() )
1540 if ( pObject
->GetLayer() == SC_LAYER_INTERN
)
1542 BOOL bArrow
= FALSE
;
1543 BOOL bError
= FALSE
;
1548 ScDetectiveObjType eType
= GetDetectiveObjectType( pObject
, nObjTab
, aPos
, aSource
, bDummy
);
1549 if ( eType
== SC_DETOBJ_ARROW
|| eType
== SC_DETOBJ_TOOTHERTAB
)
1551 // source is valid, determine error flag from source range
1554 if ( HasError( aSource
, aErrPos
) )
1559 else if ( eType
== SC_DETOBJ_FROMOTHERTAB
)
1561 // source range is no longer known, take error flag from formula itself
1562 // (this means, if the formula has an error, all references to other tables
1566 if ( HasError( ScRange( aPos
), aErrPos
) )
1571 else if ( eType
== SC_DETOBJ_CIRCLE
)
1573 // circles (error marks) are always red
1577 else if ( eType
== SC_DETOBJ_NONE
)
1579 // frame for area reference has no ObjType, always gets arrow color
1581 if ( pObject
->ISA( SdrRectObj
) && !pObject
->ISA( SdrCaptionObj
) )
1587 if ( bArrow
|| bError
)
1589 ColorData nColorData
= ( bError
? GetErrorColor() : GetArrowColor() );
1590 //pObject->SendRepaintBroadcast(pObject->GetBoundRect());
1591 pObject
->SetMergedItem( XLineColorItem( String(), Color( nColorData
) ) );
1594 pObject
->ActionChanged();
1595 // pObject->SendRepaintBroadcast(pObject->GetBoundRect());
1603 BOOL
ScDetectiveFunc::FindFrameForObject( SdrObject
* pObject
, ScRange
& rRange
)
1605 // find the rectangle for an arrow (always the object directly before the arrow)
1606 // rRange must be initialized to the source cell of the arrow (start of area)
1608 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1609 if (!pModel
) return FALSE
;
1611 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
1612 DBG_ASSERT(pPage
,"Page ?");
1613 if (!pPage
) return FALSE
;
1615 // test if the object is a direct page member
1616 if( pObject
&& pObject
->GetPage() && (pObject
->GetPage() == pObject
->GetObjList()) )
1618 // Is there a previous object?
1619 const sal_uInt32
nOrdNum(pObject
->GetOrdNum());
1623 SdrObject
* pPrevObj
= pPage
->GetObj(nOrdNum
- 1);
1625 if ( pPrevObj
&& pPrevObj
->GetLayer() == SC_LAYER_INTERN
&& pPrevObj
->ISA(SdrRectObj
) )
1627 ScDrawObjData
* pPrevData
= ScDrawLayer::GetObjDataTab( pPrevObj
, rRange
.aStart
.Tab() );
1628 if ( pPrevData
&& pPrevData
->maStart
.IsValid() && pPrevData
->maEnd
.IsValid() && (pPrevData
->maStart
== rRange
.aStart
) )
1630 rRange
.aEnd
= pPrevData
->maEnd
;
1639 ScDetectiveObjType
ScDetectiveFunc::GetDetectiveObjectType( SdrObject
* pObject
, SCTAB nObjTab
,
1640 ScAddress
& rPosition
, ScRange
& rSource
, BOOL
& rRedLine
)
1643 ScDetectiveObjType eType
= SC_DETOBJ_NONE
;
1645 if ( pObject
&& pObject
->GetLayer() == SC_LAYER_INTERN
)
1647 if ( ScDrawObjData
* pData
= ScDrawLayer::GetObjDataTab( pObject
, nObjTab
) )
1649 bool bValidStart
= pData
->maStart
.IsValid();
1650 bool bValidEnd
= pData
->maEnd
.IsValid();
1652 if ( pObject
->IsPolyObj() && pObject
->GetPointCount() == 2 )
1654 // line object -> arrow
1657 eType
= bValidEnd
? SC_DETOBJ_ARROW
: SC_DETOBJ_TOOTHERTAB
;
1658 else if ( bValidEnd
)
1659 eType
= SC_DETOBJ_FROMOTHERTAB
;
1662 rSource
= pData
->maStart
;
1664 rPosition
= pData
->maEnd
;
1666 if ( bValidStart
&& lcl_HasThickLine( *pObject
) )
1668 // thick line -> look for frame before this object
1670 FindFrameForObject( pObject
, rSource
); // modifies rSource
1673 ColorData nObjColor
= ((const XLineColorItem
&)pObject
->GetMergedItem(XATTR_LINECOLOR
)).GetColorValue().GetColor();
1674 if ( nObjColor
== GetErrorColor() && nObjColor
!= GetArrowColor() )
1677 else if ( pObject
->ISA(SdrCircObj
) )
1681 // cell position is returned in rPosition
1683 rPosition
= pData
->maStart
;
1684 eType
= SC_DETOBJ_CIRCLE
;
1693 void ScDetectiveFunc::InsertObject( ScDetectiveObjType eType
,
1694 const ScAddress
& rPosition
, const ScRange
& rSource
,
1697 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1698 if (!pModel
) return;
1699 ScDetectiveData
aData( pModel
);
1703 case SC_DETOBJ_ARROW
:
1704 case SC_DETOBJ_FROMOTHERTAB
:
1705 InsertArrow( rPosition
.Col(), rPosition
.Row(),
1706 rSource
.aStart
.Col(), rSource
.aStart
.Row(),
1707 rSource
.aEnd
.Col(), rSource
.aEnd
.Row(),
1708 (eType
== SC_DETOBJ_FROMOTHERTAB
), bRedLine
, aData
);
1710 case SC_DETOBJ_TOOTHERTAB
:
1711 InsertToOtherTab( rSource
.aStart
.Col(), rSource
.aStart
.Row(),
1712 rSource
.aEnd
.Col(), rSource
.aEnd
.Row(),
1715 case SC_DETOBJ_CIRCLE
:
1716 DrawCircle( rPosition
.Col(), rPosition
.Row(), aData
);
1720 // added to avoid warnings
1726 ColorData
ScDetectiveFunc::GetArrowColor()
1728 if (!bColorsInitialized
)
1734 ColorData
ScDetectiveFunc::GetErrorColor()
1736 if (!bColorsInitialized
)
1742 ColorData
ScDetectiveFunc::GetCommentColor()
1744 if (!bColorsInitialized
)
1746 return nCommentColor
;
1750 void ScDetectiveFunc::InitializeColors()
1752 // may be called several times to update colors from configuration
1754 const svtools::ColorConfig
& rColorCfg
= SC_MOD()->GetColorConfig();
1755 nArrowColor
= rColorCfg
.GetColorValue(svtools::CALCDETECTIVE
).nColor
;
1756 nErrorColor
= rColorCfg
.GetColorValue(svtools::CALCDETECTIVEERROR
).nColor
;
1757 nCommentColor
= rColorCfg
.GetColorValue(svtools::CALCNOTESBACKGROUND
).nColor
;
1759 bColorsInitialized
= TRUE
;
1763 BOOL
ScDetectiveFunc::IsColorsInitialized()
1765 return bColorsInitialized
;