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 inline BOOL
Intersect( SCCOL nStartCol1
, SCROW nStartRow1
, SCCOL nEndCol1
, SCROW nEndRow1
,
300 SCCOL nStartCol2
, SCROW nStartRow2
, SCCOL nEndCol2
, SCROW nEndRow2
)
302 return nEndCol1
>= nStartCol2
&& nEndCol2
>= nStartCol1
&&
303 nEndRow1
>= nStartRow2
&& nEndRow2
>= nStartRow1
;
306 BOOL
ScDetectiveFunc::HasError( const ScRange
& rRange
, ScAddress
& rErrPos
)
308 rErrPos
= rRange
.aStart
;
311 ScCellIterator
aCellIter( pDoc
, rRange
);
312 ScBaseCell
* pCell
= aCellIter
.GetFirst();
315 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
317 nError
= ((ScFormulaCell
*)pCell
)->GetErrCode();
319 rErrPos
.Set( aCellIter
.GetCol(), aCellIter
.GetRow(), aCellIter
.GetTab() );
321 pCell
= aCellIter
.GetNext();
324 return (nError
!= 0);
327 Point
ScDetectiveFunc::GetDrawPos( SCCOL nCol
, SCROW nRow
, DrawPosMode eMode
) const
329 DBG_ASSERT( ValidColRow( nCol
, nRow
), "ScDetectiveFunc::GetDrawPos - invalid cell address" );
337 case DRAWPOS_TOPLEFT
:
339 case DRAWPOS_BOTTOMRIGHT
:
343 case DRAWPOS_DETARROW
:
344 aPos
.X() += pDoc
->GetColWidth( nCol
, nTab
) / 4;
345 aPos
.Y() += pDoc
->GetRowHeight( nRow
, nTab
) / 2;
347 case DRAWPOS_CAPTIONLEFT
:
350 case DRAWPOS_CAPTIONRIGHT
:
352 // find right end of passed cell position
353 const ScMergeAttr
* pMerge
= static_cast< const ScMergeAttr
* >( pDoc
->GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE
) );
354 if ( pMerge
->GetColMerge() > 1 )
355 nCol
= nCol
+ pMerge
->GetColMerge();
363 for ( SCCOL i
= 0; i
< nCol
; ++i
)
364 aPos
.X() += pDoc
->GetColWidth( i
, nTab
);
365 aPos
.Y() += pDoc
->FastGetRowHeight( 0, nRow
- 1, nTab
);
367 aPos
.X() = static_cast< long >( aPos
.X() * HMM_PER_TWIPS
);
368 aPos
.Y() = static_cast< long >( aPos
.Y() * HMM_PER_TWIPS
);
370 if ( pDoc
->IsNegativePage( nTab
) )
376 Rectangle
ScDetectiveFunc::GetDrawRect( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) const
379 GetDrawPos( ::std::min( nCol1
, nCol2
), ::std::min( nRow1
, nRow2
), DRAWPOS_TOPLEFT
),
380 GetDrawPos( ::std::max( nCol1
, nCol2
), ::std::max( nRow1
, nRow2
), DRAWPOS_BOTTOMRIGHT
) );
381 aRect
.Justify(); // reorder left/right in RTL sheets
385 Rectangle
ScDetectiveFunc::GetDrawRect( SCCOL nCol
, SCROW nRow
) const
387 return GetDrawRect( nCol
, nRow
, nCol
, nRow
);
390 BOOL
lcl_IsOtherTab( const basegfx::B2DPolyPolygon
& rPolyPolygon
)
392 // test if rPolygon is the line end for "other table" (rectangle)
393 if(1L == rPolyPolygon
.count())
395 const basegfx::B2DPolygon
aSubPoly(rPolyPolygon
.getB2DPolygon(0L));
397 // #i73305# circle consists of 4 segments, too, distinguishable from square by
398 // the use of control points
399 if(4L == aSubPoly
.count() && aSubPoly
.isClosed() && !aSubPoly
.areControlPointsUsed())
408 BOOL
ScDetectiveFunc::HasArrow( const ScAddress
& rStart
,
409 SCCOL nEndCol
, SCROW nEndRow
, SCTAB nEndTab
)
411 BOOL bStartAlien
= ( rStart
.Tab() != nTab
);
412 BOOL bEndAlien
= ( nEndTab
!= nTab
);
414 if (bStartAlien
&& bEndAlien
)
416 DBG_ERROR("bStartAlien && bEndAlien");
420 Rectangle aStartRect
;
423 aStartRect
= GetDrawRect( rStart
.Col(), rStart
.Row() );
425 aEndRect
= GetDrawRect( nEndCol
, nEndRow
);
427 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
428 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
429 DBG_ASSERT(pPage
,"Page ?");
432 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
433 SdrObject
* pObject
= aIter
.Next();
434 while (pObject
&& !bFound
)
436 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
437 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
439 const SfxItemSet
& rSet
= pObject
->GetMergedItemSet();
441 BOOL bObjStartAlien
=
442 lcl_IsOtherTab( ((const XLineStartItem
&)rSet
.Get(XATTR_LINESTART
)).GetLineStartValue() );
444 lcl_IsOtherTab( ((const XLineEndItem
&)rSet
.Get(XATTR_LINEEND
)).GetLineEndValue() );
446 BOOL bStartHit
= bStartAlien
? bObjStartAlien
:
447 ( !bObjStartAlien
&& aStartRect
.IsInside(pObject
->GetPoint(0)) );
448 BOOL bEndHit
= bEndAlien
? bObjEndAlien
:
449 ( !bObjEndAlien
&& aEndRect
.IsInside(pObject
->GetPoint(1)) );
451 if ( bStartHit
&& bEndHit
)
454 pObject
= aIter
.Next();
460 BOOL
ScDetectiveFunc::IsNonAlienArrow( SdrObject
* pObject
) // static
462 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
463 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
465 const SfxItemSet
& rSet
= pObject
->GetMergedItemSet();
467 BOOL bObjStartAlien
=
468 lcl_IsOtherTab( ((const XLineStartItem
&)rSet
.Get(XATTR_LINESTART
)).GetLineStartValue() );
470 lcl_IsOtherTab( ((const XLineEndItem
&)rSet
.Get(XATTR_LINEEND
)).GetLineEndValue() );
472 return !bObjStartAlien
&& !bObjEndAlien
;
478 //------------------------------------------------------------------------
480 // InsertXXX: called from DrawEntry/DrawAlienEntry and InsertObject
482 BOOL
ScDetectiveFunc::InsertArrow( SCCOL nCol
, SCROW nRow
,
483 SCCOL nRefStartCol
, SCROW nRefStartRow
,
484 SCCOL nRefEndCol
, SCROW nRefEndRow
,
485 BOOL bFromOtherTab
, BOOL bRed
,
486 ScDetectiveData
& rData
)
488 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
489 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
491 BOOL bArea
= ( nRefStartCol
!= nRefEndCol
|| nRefStartRow
!= nRefEndRow
);
492 if (bArea
&& !bFromOtherTab
)
494 // insert the rectangle before the arrow - this is relied on in FindFrameForObject
496 Rectangle aRect
= GetDrawRect( nRefStartCol
, nRefStartRow
, nRefEndCol
, nRefEndRow
);
497 SdrRectObj
* pBox
= new SdrRectObj( aRect
);
499 pBox
->SetMergedItemSetAndBroadcast(rData
.GetBoxSet());
501 ScDrawLayer::SetAnchor( pBox
, SCA_CELL
);
502 pBox
->SetLayer( SC_LAYER_INTERN
);
503 pPage
->InsertObject( pBox
);
504 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pBox
) );
506 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pBox
, TRUE
);
507 pData
->maStart
.Set( nRefStartCol
, nRefStartRow
, nTab
);
508 pData
->maEnd
.Set( nRefEndCol
, nRefEndRow
, nTab
);
511 Point aStartPos
= GetDrawPos( nRefStartCol
, nRefStartRow
, DRAWPOS_DETARROW
);
512 Point aEndPos
= GetDrawPos( nCol
, nRow
, DRAWPOS_DETARROW
);
516 BOOL bNegativePage
= pDoc
->IsNegativePage( nTab
);
517 long nPageSign
= bNegativePage
? -1 : 1;
519 aStartPos
= Point( aEndPos
.X() - 1000 * nPageSign
, aEndPos
.Y() - 1000 );
520 if (aStartPos
.X() * nPageSign
< 0)
521 aStartPos
.X() += 2000 * nPageSign
;
522 if (aStartPos
.Y() < 0)
523 aStartPos
.Y() += 2000;
526 SfxItemSet
& rAttrSet
= bFromOtherTab
? rData
.GetFromTabSet() : rData
.GetArrowSet();
528 if (bArea
&& !bFromOtherTab
)
529 rAttrSet
.Put( XLineWidthItem( 50 ) ); // Bereich
531 rAttrSet
.Put( XLineWidthItem( 0 ) ); // einzelne Referenz
533 ColorData nColorData
= ( bRed
? GetErrorColor() : GetArrowColor() );
534 rAttrSet
.Put( XLineColorItem( String(), Color( nColorData
) ) );
536 basegfx::B2DPolygon aTempPoly
;
537 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
538 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
539 SdrPathObj
* pArrow
= new SdrPathObj(OBJ_LINE
, basegfx::B2DPolyPolygon(aTempPoly
));
540 pArrow
->NbcSetLogicRect(Rectangle(aStartPos
,aEndPos
)); //! noetig ???
541 pArrow
->SetMergedItemSetAndBroadcast(rAttrSet
);
543 ScDrawLayer::SetAnchor( pArrow
, SCA_CELL
);
544 pArrow
->SetLayer( SC_LAYER_INTERN
);
545 pPage
->InsertObject( pArrow
);
546 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pArrow
) );
548 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pArrow
, TRUE
);
550 pData
->maStart
.SetInvalid();
552 pData
->maStart
.Set( nRefStartCol
, nRefStartRow
, nTab
);
554 pData
->maEnd
.Set( nCol
, nRow
, nTab
);
559 BOOL
ScDetectiveFunc::InsertToOtherTab( SCCOL nStartCol
, SCROW nStartRow
,
560 SCCOL nEndCol
, SCROW nEndRow
, BOOL bRed
,
561 ScDetectiveData
& rData
)
563 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
564 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
566 BOOL bArea
= ( nStartCol
!= nEndCol
|| nStartRow
!= nEndRow
);
569 Rectangle aRect
= GetDrawRect( nStartCol
, nStartRow
, nEndCol
, nEndRow
);
570 SdrRectObj
* pBox
= new SdrRectObj( aRect
);
572 pBox
->SetMergedItemSetAndBroadcast(rData
.GetBoxSet());
574 ScDrawLayer::SetAnchor( pBox
, SCA_CELL
);
575 pBox
->SetLayer( SC_LAYER_INTERN
);
576 pPage
->InsertObject( pBox
);
577 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pBox
) );
579 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pBox
, TRUE
);
580 pData
->maStart
.Set( nStartCol
, nStartRow
, nTab
);
581 pData
->maEnd
.Set( nEndCol
, nEndRow
, nTab
);
584 BOOL bNegativePage
= pDoc
->IsNegativePage( nTab
);
585 long nPageSign
= bNegativePage
? -1 : 1;
587 Point aStartPos
= GetDrawPos( nStartCol
, nStartRow
, DRAWPOS_DETARROW
);
588 Point aEndPos
= Point( aStartPos
.X() + 1000 * nPageSign
, aStartPos
.Y() - 1000 );
592 SfxItemSet
& rAttrSet
= rData
.GetToTabSet();
594 rAttrSet
.Put( XLineWidthItem( 50 ) ); // Bereich
596 rAttrSet
.Put( XLineWidthItem( 0 ) ); // einzelne Referenz
598 ColorData nColorData
= ( bRed
? GetErrorColor() : GetArrowColor() );
599 rAttrSet
.Put( XLineColorItem( String(), Color( nColorData
) ) );
601 basegfx::B2DPolygon aTempPoly
;
602 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
603 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
604 SdrPathObj
* pArrow
= new SdrPathObj(OBJ_LINE
, basegfx::B2DPolyPolygon(aTempPoly
));
605 pArrow
->NbcSetLogicRect(Rectangle(aStartPos
,aEndPos
)); //! noetig ???
607 pArrow
->SetMergedItemSetAndBroadcast(rAttrSet
);
609 ScDrawLayer::SetAnchor( pArrow
, SCA_CELL
);
610 pArrow
->SetLayer( SC_LAYER_INTERN
);
611 pPage
->InsertObject( pArrow
);
612 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pArrow
) );
614 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pArrow
, TRUE
);
615 pData
->maStart
.Set( nStartCol
, nStartRow
, nTab
);
616 pData
->maEnd
.SetInvalid();
621 //------------------------------------------------------------------------
623 // DrawEntry: Formel auf dieser Tabelle,
624 // Referenz auf dieser oder anderer
625 // DrawAlienEntry: Formel auf anderer Tabelle,
626 // Referenz auf dieser
628 // return FALSE: da war schon ein Pfeil
630 BOOL
ScDetectiveFunc::DrawEntry( SCCOL nCol
, SCROW nRow
,
632 ScDetectiveData
& rData
)
634 if ( HasArrow( rRef
.aStart
, nCol
, nRow
, nTab
) )
638 BOOL bError
= HasError( rRef
, aErrorPos
);
639 BOOL bAlien
= ( rRef
.aEnd
.Tab() < nTab
|| rRef
.aStart
.Tab() > nTab
);
641 return InsertArrow( nCol
, nRow
,
642 rRef
.aStart
.Col(), rRef
.aStart
.Row(),
643 rRef
.aEnd
.Col(), rRef
.aEnd
.Row(),
644 bAlien
, bError
, rData
);
647 BOOL
ScDetectiveFunc::DrawAlienEntry( const ScRange
& rRef
,
648 ScDetectiveData
& rData
)
650 if ( HasArrow( rRef
.aStart
, 0, 0, nTab
+1 ) )
654 BOOL bError
= HasError( rRef
, aErrorPos
);
656 return InsertToOtherTab( rRef
.aStart
.Col(), rRef
.aStart
.Row(),
657 rRef
.aEnd
.Col(), rRef
.aEnd
.Row(),
661 void ScDetectiveFunc::DrawCircle( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
)
663 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
664 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
666 Rectangle aRect
= GetDrawRect( nCol
, nRow
);
668 aRect
.Right() += 250;
670 aRect
.Bottom() += 70;
672 SdrCircObj
* pCircle
= new SdrCircObj( OBJ_CIRC
, aRect
);
673 SfxItemSet
& rAttrSet
= rData
.GetCircleSet();
675 pCircle
->SetMergedItemSetAndBroadcast(rAttrSet
);
677 ScDrawLayer::SetAnchor( pCircle
, SCA_CELL
);
678 pCircle
->SetLayer( SC_LAYER_INTERN
);
679 pPage
->InsertObject( pCircle
);
680 pModel
->AddCalcUndo( new SdrUndoInsertObj( *pCircle
) );
682 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pCircle
, TRUE
);
683 pData
->maStart
.Set( nCol
, nRow
, nTab
);
684 pData
->maEnd
.SetInvalid();
687 void ScDetectiveFunc::DeleteArrowsAt( SCCOL nCol
, SCROW nRow
, BOOL bDestPnt
)
689 Rectangle aRect
= GetDrawRect( nCol
, nRow
);
691 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
692 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
693 DBG_ASSERT(pPage
,"Page ?");
695 pPage
->RecalcObjOrdNums();
698 ULONG nObjCount
= pPage
->GetObjCount();
701 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
703 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
704 SdrObject
* pObject
= aIter
.Next();
707 if ( pObject
->GetLayer()==SC_LAYER_INTERN
&&
708 pObject
->IsPolyObj() && pObject
->GetPointCount()==2 )
710 if (aRect
.IsInside(pObject
->GetPoint(bDestPnt
))) // Start/Zielpunkt
711 ppObj
[nDelCount
++] = pObject
;
714 pObject
= aIter
.Next();
718 for (i
=1; i
<=nDelCount
; i
++)
719 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
721 for (i
=1; i
<=nDelCount
; i
++)
722 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
728 // Box um Referenz loeschen
730 #define SC_DET_TOLERANCE 50
732 inline BOOL
RectIsPoints( const Rectangle
& rRect
, const Point
& rStart
, const Point
& rEnd
)
734 return rRect
.Left() >= rStart
.X() - SC_DET_TOLERANCE
735 && rRect
.Left() <= rStart
.X() + SC_DET_TOLERANCE
736 && rRect
.Right() >= rEnd
.X() - SC_DET_TOLERANCE
737 && rRect
.Right() <= rEnd
.X() + SC_DET_TOLERANCE
738 && rRect
.Top() >= rStart
.Y() - SC_DET_TOLERANCE
739 && rRect
.Top() <= rStart
.Y() + SC_DET_TOLERANCE
740 && rRect
.Bottom() >= rEnd
.Y() - SC_DET_TOLERANCE
741 && rRect
.Bottom() <= rEnd
.Y() + SC_DET_TOLERANCE
;
744 #undef SC_DET_TOLERANCE
746 void ScDetectiveFunc::DeleteBox( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
756 InfoBox(0,aStr).Execute();
759 Rectangle aCornerRect
= GetDrawRect( nCol1
, nRow1
, nCol2
, nRow2
);
760 Point aStartCorner
= aCornerRect
.TopLeft();
761 Point aEndCorner
= aCornerRect
.BottomRight();
764 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
765 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
766 DBG_ASSERT(pPage
,"Page ?");
768 pPage
->RecalcObjOrdNums();
771 ULONG nObjCount
= pPage
->GetObjCount();
774 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
776 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
777 SdrObject
* pObject
= aIter
.Next();
780 if ( pObject
->GetLayer() == SC_LAYER_INTERN
&&
781 pObject
->Type() == TYPE(SdrRectObj
) )
783 aObjRect
= ((SdrRectObj
*)pObject
)->GetLogicRect();
785 if ( RectIsPoints( aObjRect
, aStartCorner
, aEndCorner
) )
786 ppObj
[nDelCount
++] = pObject
;
789 pObject
= aIter
.Next();
793 for (i
=1; i
<=nDelCount
; i
++)
794 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
796 for (i
=1; i
<=nDelCount
; i
++)
797 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
803 //------------------------------------------------------------------------
805 USHORT
ScDetectiveFunc::InsertPredLevelArea( const ScRange
& rRef
,
806 ScDetectiveData
& rData
, USHORT nLevel
)
808 USHORT nResult
= DET_INS_EMPTY
;
810 ScCellIterator
aCellIter( pDoc
, rRef
);
811 ScBaseCell
* pCell
= aCellIter
.GetFirst();
814 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
815 switch( InsertPredLevel( aCellIter
.GetCol(), aCellIter
.GetRow(), rData
, nLevel
) )
817 case DET_INS_INSERTED
:
818 nResult
= DET_INS_INSERTED
;
820 case DET_INS_CONTINUE
:
821 if (nResult
!= DET_INS_INSERTED
)
822 nResult
= DET_INS_CONTINUE
;
824 case DET_INS_CIRCULAR
:
825 if (nResult
== DET_INS_EMPTY
)
826 nResult
= DET_INS_CIRCULAR
;
830 pCell
= aCellIter
.GetNext();
836 USHORT
ScDetectiveFunc::InsertPredLevel( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
,
840 pDoc
->GetCell( nCol
, nRow
, nTab
, pCell
);
842 return DET_INS_EMPTY
;
843 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
844 return DET_INS_EMPTY
;
846 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
847 if (pFCell
->IsRunning())
848 return DET_INS_CIRCULAR
;
850 if (pFCell
->GetDirty())
851 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
852 pFCell
->SetRunning(TRUE
);
854 USHORT nResult
= DET_INS_EMPTY
;
856 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
858 while ( aIter
.GetNextRef( aRef
) )
860 if (DrawEntry( nCol
, nRow
, aRef
, rData
))
862 nResult
= DET_INS_INSERTED
; // neuer Pfeil eingetragen
868 if ( nLevel
< rData
.GetMaxLevel() )
871 BOOL bArea
= (aRef
.aStart
!= aRef
.aEnd
);
873 nSubResult
= InsertPredLevelArea( aRef
, rData
, nLevel
+1 );
875 nSubResult
= InsertPredLevel( aRef
.aStart
.Col(), aRef
.aStart
.Row(),
880 case DET_INS_INSERTED
:
881 nResult
= DET_INS_INSERTED
;
883 case DET_INS_CONTINUE
:
884 if (nResult
!= DET_INS_INSERTED
)
885 nResult
= DET_INS_CONTINUE
;
887 case DET_INS_CIRCULAR
:
888 if (nResult
== DET_INS_EMPTY
)
889 nResult
= DET_INS_CIRCULAR
;
891 // DET_INS_EMPTY: unveraendert lassen
894 else // nMaxLevel erreicht
895 if (nResult
!= DET_INS_INSERTED
)
896 nResult
= DET_INS_CONTINUE
;
900 pFCell
->SetRunning(FALSE
);
905 USHORT
ScDetectiveFunc::FindPredLevelArea( const ScRange
& rRef
,
906 USHORT nLevel
, USHORT nDeleteLevel
)
908 USHORT nResult
= nLevel
;
910 ScCellIterator
aCellIter( pDoc
, rRef
);
911 ScBaseCell
* pCell
= aCellIter
.GetFirst();
914 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
916 USHORT nTemp
= FindPredLevel( aCellIter
.GetCol(), aCellIter
.GetRow(), nLevel
, nDeleteLevel
);
920 pCell
= aCellIter
.GetNext();
926 // nDeleteLevel != 0 -> loeschen
928 USHORT
ScDetectiveFunc::FindPredLevel( SCCOL nCol
, SCROW nRow
, USHORT nLevel
, USHORT nDeleteLevel
)
930 DBG_ASSERT( nLevel
<1000, "Level" );
933 pDoc
->GetCell( nCol
, nRow
, nTab
, pCell
);
936 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
939 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
940 if (pFCell
->IsRunning())
943 if (pFCell
->GetDirty())
944 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
945 pFCell
->SetRunning(TRUE
);
947 USHORT nResult
= nLevel
;
948 BOOL bDelete
= ( nDeleteLevel
&& nLevel
== nDeleteLevel
-1 );
952 DeleteArrowsAt( nCol
, nRow
, TRUE
); // Pfeile, die hierher zeigen
955 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
957 while ( aIter
.GetNextRef( aRef
) )
959 BOOL bArea
= ( aRef
.aStart
!= aRef
.aEnd
);
961 if ( bDelete
) // Rahmen loeschen ?
965 DeleteBox( aRef
.aStart
.Col(), aRef
.aStart
.Row(), aRef
.aEnd
.Col(), aRef
.aEnd
.Row() );
970 if ( HasArrow( aRef
.aStart
, nCol
,nRow
,nTab
) )
974 nTemp
= FindPredLevelArea( aRef
, nLevel
+1, nDeleteLevel
);
976 nTemp
= FindPredLevel( aRef
.aStart
.Col(),aRef
.aStart
.Row(),
977 nLevel
+1, nDeleteLevel
);
984 pFCell
->SetRunning(FALSE
);
989 //------------------------------------------------------------------------
991 USHORT
ScDetectiveFunc::InsertErrorLevel( SCCOL nCol
, SCROW nRow
, ScDetectiveData
& rData
,
995 pDoc
->GetCell( nCol
, nRow
, nTab
, pCell
);
997 return DET_INS_EMPTY
;
998 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
999 return DET_INS_EMPTY
;
1001 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
1002 if (pFCell
->IsRunning())
1003 return DET_INS_CIRCULAR
;
1005 if (pFCell
->GetDirty())
1006 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
1007 pFCell
->SetRunning(TRUE
);
1009 USHORT nResult
= DET_INS_EMPTY
;
1011 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
1013 ScAddress aErrorPos
;
1014 BOOL bHasError
= FALSE
;
1015 while ( aIter
.GetNextRef( aRef
) )
1017 if (HasError( aRef
, aErrorPos
))
1020 if (DrawEntry( nCol
, nRow
, ScRange( aErrorPos
), rData
))
1021 nResult
= DET_INS_INSERTED
;
1023 // und weiterverfolgen
1025 if ( nLevel
< rData
.GetMaxLevel() ) // praktisch immer
1027 if (InsertErrorLevel( aErrorPos
.Col(), aErrorPos
.Row(),
1028 rData
, nLevel
+1 ) == DET_INS_INSERTED
)
1029 nResult
= DET_INS_INSERTED
;
1034 pFCell
->SetRunning(FALSE
);
1038 if (InsertPredLevel( nCol
, nRow
, rData
, rData
.GetMaxLevel() ) == DET_INS_INSERTED
)
1039 nResult
= DET_INS_INSERTED
;
1044 //------------------------------------------------------------------------
1046 USHORT
ScDetectiveFunc::InsertSuccLevel( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1047 ScDetectiveData
& rData
, USHORT nLevel
)
1049 // ueber ganzes Dokument
1051 USHORT nResult
= DET_INS_EMPTY
;
1052 // ScCellIterator aCellIter( pDoc, 0,0, nTab, MAXCOL,MAXROW, nTab );
1053 ScCellIterator
aCellIter( pDoc
, 0,0,0, MAXCOL
,MAXROW
,MAXTAB
); // alle Tabellen
1054 ScBaseCell
* pCell
= aCellIter
.GetFirst();
1057 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1059 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
1060 BOOL bRunning
= pFCell
->IsRunning();
1062 if (pFCell
->GetDirty())
1063 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
1064 pFCell
->SetRunning(TRUE
);
1066 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
1068 while ( aIter
.GetNextRef( aRef
) )
1070 if (aRef
.aStart
.Tab() <= nTab
&& aRef
.aEnd
.Tab() >= nTab
)
1072 if (Intersect( nCol1
,nRow1
,nCol2
,nRow2
,
1073 aRef
.aStart
.Col(),aRef
.aStart
.Row(),
1074 aRef
.aEnd
.Col(),aRef
.aEnd
.Row() ))
1076 BOOL bAlien
= ( aCellIter
.GetTab() != nTab
);
1079 bDrawRet
= DrawAlienEntry( aRef
, rData
);
1081 bDrawRet
= DrawEntry( aCellIter
.GetCol(), aCellIter
.GetRow(),
1085 nResult
= DET_INS_INSERTED
; // neuer Pfeil eingetragen
1091 if (nResult
== DET_INS_EMPTY
)
1092 nResult
= DET_INS_CIRCULAR
;
1098 if ( nLevel
< rData
.GetMaxLevel() )
1100 USHORT nSubResult
= InsertSuccLevel(
1101 aCellIter
.GetCol(), aCellIter
.GetRow(),
1102 aCellIter
.GetCol(), aCellIter
.GetRow(),
1106 case DET_INS_INSERTED
:
1107 nResult
= DET_INS_INSERTED
;
1109 case DET_INS_CONTINUE
:
1110 if (nResult
!= DET_INS_INSERTED
)
1111 nResult
= DET_INS_CONTINUE
;
1113 case DET_INS_CIRCULAR
:
1114 if (nResult
== DET_INS_EMPTY
)
1115 nResult
= DET_INS_CIRCULAR
;
1117 // DET_INS_EMPTY: unveraendert lassen
1120 else // nMaxLevel erreicht
1121 if (nResult
!= DET_INS_INSERTED
)
1122 nResult
= DET_INS_CONTINUE
;
1128 pFCell
->SetRunning(bRunning
);
1130 pCell
= aCellIter
.GetNext();
1136 USHORT
ScDetectiveFunc::FindSuccLevel( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1137 USHORT nLevel
, USHORT nDeleteLevel
)
1139 DBG_ASSERT( nLevel
<1000, "Level" );
1141 USHORT nResult
= nLevel
;
1142 BOOL bDelete
= ( nDeleteLevel
&& nLevel
== nDeleteLevel
-1 );
1144 ScCellIterator
aCellIter( pDoc
, 0,0, nTab
, MAXCOL
,MAXROW
, nTab
);
1145 ScBaseCell
* pCell
= aCellIter
.GetFirst();
1148 if (pCell
->GetCellType() == CELLTYPE_FORMULA
)
1150 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
1151 BOOL bRunning
= pFCell
->IsRunning();
1153 if (pFCell
->GetDirty())
1154 pFCell
->Interpret(); // nach SetRunning geht's nicht mehr!
1155 pFCell
->SetRunning(TRUE
);
1157 ScDetectiveRefIter
aIter( (ScFormulaCell
*) pCell
);
1159 while ( aIter
.GetNextRef( aRef
) )
1161 if (aRef
.aStart
.Tab() <= nTab
&& aRef
.aEnd
.Tab() >= nTab
)
1163 if (Intersect( nCol1
,nRow1
,nCol2
,nRow2
,
1164 aRef
.aStart
.Col(),aRef
.aStart
.Row(),
1165 aRef
.aEnd
.Col(),aRef
.aEnd
.Row() ))
1167 if ( bDelete
) // Pfeile, die hier anfangen
1169 if (aRef
.aStart
!= aRef
.aEnd
)
1171 DeleteBox( aRef
.aStart
.Col(), aRef
.aStart
.Row(),
1172 aRef
.aEnd
.Col(), aRef
.aEnd
.Row() );
1174 DeleteArrowsAt( aRef
.aStart
.Col(), aRef
.aStart
.Row(), FALSE
);
1176 else if ( !bRunning
&&
1177 HasArrow( aRef
.aStart
,
1178 aCellIter
.GetCol(),aCellIter
.GetRow(),aCellIter
.GetTab() ) )
1180 USHORT nTemp
= FindSuccLevel( aCellIter
.GetCol(), aCellIter
.GetRow(),
1181 aCellIter
.GetCol(), aCellIter
.GetRow(),
1182 nLevel
+1, nDeleteLevel
);
1183 if (nTemp
> nResult
)
1190 pFCell
->SetRunning(bRunning
);
1192 pCell
= aCellIter
.GetNext();
1200 // --------------------------------------------------------------------------------
1203 BOOL
ScDetectiveFunc::ShowPred( SCCOL nCol
, SCROW nRow
)
1205 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1209 ScDetectiveData
aData( pModel
);
1211 USHORT nMaxLevel
= 0;
1212 USHORT nResult
= DET_INS_CONTINUE
;
1213 while (nResult
== DET_INS_CONTINUE
&& nMaxLevel
< 1000)
1215 aData
.SetMaxLevel( nMaxLevel
);
1216 nResult
= InsertPredLevel( nCol
, nRow
, aData
, 0 );
1220 return ( nResult
== DET_INS_INSERTED
);
1223 BOOL
ScDetectiveFunc::ShowSucc( SCCOL nCol
, SCROW nRow
)
1225 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1229 ScDetectiveData
aData( pModel
);
1231 USHORT nMaxLevel
= 0;
1232 USHORT nResult
= DET_INS_CONTINUE
;
1233 while (nResult
== DET_INS_CONTINUE
&& nMaxLevel
< 1000)
1235 aData
.SetMaxLevel( nMaxLevel
);
1236 nResult
= InsertSuccLevel( nCol
, nRow
, nCol
, nRow
, aData
, 0 );
1240 return ( nResult
== DET_INS_INSERTED
);
1243 BOOL
ScDetectiveFunc::ShowError( SCCOL nCol
, SCROW nRow
)
1245 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1249 ScRange
aRange( nCol
, nRow
, nTab
);
1251 if ( !HasError( aRange
,aErrPos
) )
1254 ScDetectiveData
aData( pModel
);
1256 aData
.SetMaxLevel( 1000 );
1257 USHORT nResult
= InsertErrorLevel( nCol
, nRow
, aData
, 0 );
1259 return ( nResult
== DET_INS_INSERTED
);
1262 BOOL
ScDetectiveFunc::DeleteSucc( SCCOL nCol
, SCROW nRow
)
1264 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1268 USHORT nLevelCount
= FindSuccLevel( nCol
, nRow
, nCol
, nRow
, 0, 0 );
1270 FindSuccLevel( nCol
, nRow
, nCol
, nRow
, 0, nLevelCount
); // loeschen
1272 return ( nLevelCount
!= 0 );
1275 BOOL
ScDetectiveFunc::DeletePred( SCCOL nCol
, SCROW nRow
)
1277 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1281 USHORT nLevelCount
= FindPredLevel( nCol
, nRow
, 0, 0 );
1283 FindPredLevel( nCol
, nRow
, 0, nLevelCount
); // loeschen
1285 return ( nLevelCount
!= 0 );
1288 BOOL
ScDetectiveFunc::DeleteAll( ScDetectiveDelete eWhat
)
1290 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1294 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
1295 DBG_ASSERT(pPage
,"Page ?");
1297 pPage
->RecalcObjOrdNums();
1300 ULONG nObjCount
= pPage
->GetObjCount();
1303 SdrObject
** ppObj
= new SdrObject
*[nObjCount
];
1305 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1306 SdrObject
* pObject
= aIter
.Next();
1309 if ( pObject
->GetLayer() == SC_LAYER_INTERN
)
1311 BOOL bDoThis
= TRUE
;
1312 if ( eWhat
!= SC_DET_ALL
)
1314 BOOL bCircle
= ( pObject
->ISA(SdrCircObj
) );
1315 BOOL bCaption
= ScDrawLayer::IsNoteCaption( pObject
);
1316 if ( eWhat
== SC_DET_DETECTIVE
) // Detektiv, aus Menue
1317 bDoThis
= !bCaption
; // auch Kreise
1318 else if ( eWhat
== SC_DET_CIRCLES
) // Kreise, wenn neue erzeugt werden
1320 else if ( eWhat
== SC_DET_ARROWS
) // DetectiveRefresh
1321 bDoThis
= !bCaption
&& !bCircle
; // don't include circles
1328 ppObj
[nDelCount
++] = pObject
;
1331 pObject
= aIter
.Next();
1335 for (i
=1; i
<=nDelCount
; i
++)
1336 pModel
->AddCalcUndo( new SdrUndoRemoveObj( *ppObj
[nDelCount
-i
] ) );
1338 for (i
=1; i
<=nDelCount
; i
++)
1339 pPage
->RemoveObject( ppObj
[nDelCount
-i
]->GetOrdNum() );
1344 return ( nDelCount
!= 0 );
1347 BOOL
ScDetectiveFunc::MarkInvalid(BOOL
& rOverflow
)
1350 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1354 BOOL bDeleted
= DeleteAll( SC_DET_CIRCLES
); // nur die Kreise
1356 ScDetectiveData
aData( pModel
);
1359 // Stellen suchen, wo Gueltigkeit definiert ist
1361 ScDocAttrIterator
aAttrIter( pDoc
, nTab
, 0,0,MAXCOL
,MAXROW
);
1365 const ScPatternAttr
* pPattern
= aAttrIter
.GetNext( nCol
, nRow1
, nRow2
);
1366 while ( pPattern
&& nInsCount
< SC_DET_MAXCIRCLE
)
1368 ULONG nIndex
= ((const SfxUInt32Item
&)pPattern
->GetItem(ATTR_VALIDDATA
)).GetValue();
1371 const ScValidationData
* pData
= pDoc
->GetValidationEntry( nIndex
);
1374 // Zellen in dem Bereich durchgehen
1376 BOOL bMarkEmpty
= !pData
->IsIgnoreBlank();
1377 SCROW nNextRow
= nRow1
;
1379 ScCellIterator
aCellIter( pDoc
, nCol
,nRow1
,nTab
, nCol
,nRow2
,nTab
);
1380 ScBaseCell
* pCell
= aCellIter
.GetFirst();
1381 while ( pCell
&& nInsCount
< SC_DET_MAXCIRCLE
)
1383 SCROW nCellRow
= aCellIter
.GetRow();
1385 for ( nRow
= nNextRow
; nRow
< nCellRow
&& nInsCount
< SC_DET_MAXCIRCLE
; nRow
++ )
1387 DrawCircle( nCol
, nRow
, aData
);
1390 if ( !pData
->IsDataValid( pCell
, ScAddress( nCol
, nCellRow
, nTab
) ) )
1392 DrawCircle( nCol
, nCellRow
, aData
);
1395 nNextRow
= nCellRow
+ 1;
1396 pCell
= aCellIter
.GetNext();
1399 for ( nRow
= nNextRow
; nRow
<= nRow2
&& nInsCount
< SC_DET_MAXCIRCLE
; nRow
++ )
1401 DrawCircle( nCol
, nRow
, aData
);
1407 pPattern
= aAttrIter
.GetNext( nCol
, nRow1
, nRow2
);
1410 if ( nInsCount
>= SC_DET_MAXCIRCLE
)
1413 return ( bDeleted
|| nInsCount
!= 0 );
1416 void ScDetectiveFunc::GetAllPreds(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1417 vector
<ScSharedTokenRef
>& rRefTokens
)
1419 ScCellIterator
aCellIter(pDoc
, nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
);
1420 for (ScBaseCell
* pCell
= aCellIter
.GetFirst(); pCell
; pCell
= aCellIter
.GetNext())
1422 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
1425 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1426 ScDetectiveRefIter
aRefIter(pFCell
);
1427 for (ScToken
* p
= aRefIter
.GetNextRefToken(); p
; p
= aRefIter
.GetNextRefToken())
1429 ScSharedTokenRef
pRef(static_cast<ScToken
*>(p
->Clone()));
1430 ScRefTokenHelper::join(rRefTokens
, pRef
);
1435 void ScDetectiveFunc::GetAllSuccs(SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
1436 vector
<ScSharedTokenRef
>& rRefTokens
)
1438 vector
<ScSharedTokenRef
> aSrcRange
;
1439 aSrcRange
.push_back(
1440 ScRefTokenHelper::createRefToken(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
)));
1442 ScCellIterator
aCellIter(pDoc
, 0, 0, nTab
, MAXCOL
, MAXROW
, nTab
);
1443 for (ScBaseCell
* pCell
= aCellIter
.GetFirst(); pCell
; pCell
= aCellIter
.GetNext())
1445 if (pCell
->GetCellType() != CELLTYPE_FORMULA
)
1448 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1449 ScDetectiveRefIter
aRefIter(pFCell
);
1450 for (ScToken
* p
= aRefIter
.GetNextRefToken(); p
; p
= aRefIter
.GetNextRefToken())
1452 ScSharedTokenRef
pRef(static_cast<ScToken
*>(p
->Clone()));
1453 if (ScRefTokenHelper::intersects(aSrcRange
, pRef
))
1455 pRef
= ScRefTokenHelper::createRefToken(aCellIter
.GetPos());
1456 ScRefTokenHelper::join(rRefTokens
, pRef
);
1462 void ScDetectiveFunc::UpdateAllComments( ScDocument
& rDoc
)
1464 // for all caption objects, update attributes and SpecialTextBoxShadow flag
1465 // (on all tables - nTab is ignored!)
1467 // no undo actions, this is refreshed after undo
1469 ScDrawLayer
* pModel
= rDoc
.GetDrawLayer();
1473 for( SCTAB nObjTab
= 0, nTabCount
= rDoc
.GetTableCount(); nObjTab
< nTabCount
; ++nObjTab
)
1475 rDoc
.InitializeNoteCaptions( nObjTab
);
1476 SdrPage
* pPage
= pModel
->GetPage( static_cast< sal_uInt16
>( nObjTab
) );
1477 DBG_ASSERT( pPage
, "Page ?" );
1480 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1481 for( SdrObject
* pObject
= aIter
.Next(); pObject
; pObject
= aIter
.Next() )
1483 if ( ScDrawObjData
* pData
= ScDrawLayer::GetNoteCaptionData( pObject
, nObjTab
) )
1485 ScPostIt
* pNote
= rDoc
.GetNote( pData
->maStart
);
1486 // caption should exist, we iterate over drawing objects...
1487 DBG_ASSERT( pNote
&& (pNote
->GetCaption() == pObject
), "ScDetectiveFunc::UpdateAllComments - invalid cell note" );
1490 ScCommentData
aData( rDoc
, pModel
);
1491 SfxItemSet aAttrColorSet
= pObject
->GetMergedItemSet();
1492 aAttrColorSet
.Put( XFillColorItem( String(), GetCommentColor() ) );
1493 aData
.UpdateCaptionSet( aAttrColorSet
);
1494 pObject
->SetMergedItemSetAndBroadcast( aData
.GetCaptionSet() );
1495 if( SdrCaptionObj
* pCaption
= dynamic_cast< SdrCaptionObj
* >( pObject
) )
1497 pCaption
->SetSpecialTextBoxShadow();
1498 pCaption
->SetFixedTail();
1507 void ScDetectiveFunc::UpdateAllArrowColors()
1509 // no undo actions necessary
1511 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1515 for( SCTAB nObjTab
= 0, nTabCount
= pDoc
->GetTableCount(); nObjTab
< nTabCount
; ++nObjTab
)
1517 SdrPage
* pPage
= pModel
->GetPage( static_cast< sal_uInt16
>( nObjTab
) );
1518 DBG_ASSERT( pPage
, "Page ?" );
1521 SdrObjListIter
aIter( *pPage
, IM_FLAT
);
1522 for( SdrObject
* pObject
= aIter
.Next(); pObject
; pObject
= aIter
.Next() )
1524 if ( pObject
->GetLayer() == SC_LAYER_INTERN
)
1526 BOOL bArrow
= FALSE
;
1527 BOOL bError
= FALSE
;
1532 ScDetectiveObjType eType
= GetDetectiveObjectType( pObject
, nObjTab
, aPos
, aSource
, bDummy
);
1533 if ( eType
== SC_DETOBJ_ARROW
|| eType
== SC_DETOBJ_TOOTHERTAB
)
1535 // source is valid, determine error flag from source range
1538 if ( HasError( aSource
, aErrPos
) )
1543 else if ( eType
== SC_DETOBJ_FROMOTHERTAB
)
1545 // source range is no longer known, take error flag from formula itself
1546 // (this means, if the formula has an error, all references to other tables
1550 if ( HasError( ScRange( aPos
), aErrPos
) )
1555 else if ( eType
== SC_DETOBJ_CIRCLE
)
1557 // circles (error marks) are always red
1561 else if ( eType
== SC_DETOBJ_NONE
)
1563 // frame for area reference has no ObjType, always gets arrow color
1565 if ( pObject
->ISA( SdrRectObj
) && !pObject
->ISA( SdrCaptionObj
) )
1571 if ( bArrow
|| bError
)
1573 ColorData nColorData
= ( bError
? GetErrorColor() : GetArrowColor() );
1574 //pObject->SendRepaintBroadcast(pObject->GetBoundRect());
1575 pObject
->SetMergedItem( XLineColorItem( String(), Color( nColorData
) ) );
1578 pObject
->ActionChanged();
1579 // pObject->SendRepaintBroadcast(pObject->GetBoundRect());
1587 BOOL
ScDetectiveFunc::FindFrameForObject( SdrObject
* pObject
, ScRange
& rRange
)
1589 // find the rectangle for an arrow (always the object directly before the arrow)
1590 // rRange must be initialized to the source cell of the arrow (start of area)
1592 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1593 if (!pModel
) return FALSE
;
1595 SdrPage
* pPage
= pModel
->GetPage(static_cast<sal_uInt16
>(nTab
));
1596 DBG_ASSERT(pPage
,"Page ?");
1597 if (!pPage
) return FALSE
;
1599 // test if the object is a direct page member
1600 if( pObject
&& pObject
->GetPage() && (pObject
->GetPage() == pObject
->GetObjList()) )
1602 // Is there a previous object?
1603 const sal_uInt32
nOrdNum(pObject
->GetOrdNum());
1607 SdrObject
* pPrevObj
= pPage
->GetObj(nOrdNum
- 1);
1609 if ( pPrevObj
&& pPrevObj
->GetLayer() == SC_LAYER_INTERN
&& pPrevObj
->ISA(SdrRectObj
) )
1611 ScDrawObjData
* pPrevData
= ScDrawLayer::GetObjDataTab( pPrevObj
, rRange
.aStart
.Tab() );
1612 if ( pPrevData
&& pPrevData
->maStart
.IsValid() && pPrevData
->maEnd
.IsValid() && (pPrevData
->maStart
== rRange
.aStart
) )
1614 rRange
.aEnd
= pPrevData
->maEnd
;
1623 ScDetectiveObjType
ScDetectiveFunc::GetDetectiveObjectType( SdrObject
* pObject
, SCTAB nObjTab
,
1624 ScAddress
& rPosition
, ScRange
& rSource
, BOOL
& rRedLine
)
1627 ScDetectiveObjType eType
= SC_DETOBJ_NONE
;
1629 if ( pObject
&& pObject
->GetLayer() == SC_LAYER_INTERN
)
1631 if ( ScDrawObjData
* pData
= ScDrawLayer::GetObjDataTab( pObject
, nObjTab
) )
1633 bool bValidStart
= pData
->maStart
.IsValid();
1634 bool bValidEnd
= pData
->maEnd
.IsValid();
1636 if ( pObject
->IsPolyObj() && pObject
->GetPointCount() == 2 )
1638 // line object -> arrow
1641 eType
= bValidEnd
? SC_DETOBJ_ARROW
: SC_DETOBJ_TOOTHERTAB
;
1642 else if ( bValidEnd
)
1643 eType
= SC_DETOBJ_FROMOTHERTAB
;
1646 rSource
= pData
->maStart
;
1648 rPosition
= pData
->maEnd
;
1650 if ( bValidStart
&& lcl_HasThickLine( *pObject
) )
1652 // thick line -> look for frame before this object
1654 FindFrameForObject( pObject
, rSource
); // modifies rSource
1657 ColorData nObjColor
= ((const XLineColorItem
&)pObject
->GetMergedItem(XATTR_LINECOLOR
)).GetColorValue().GetColor();
1658 if ( nObjColor
== GetErrorColor() && nObjColor
!= GetArrowColor() )
1661 else if ( pObject
->ISA(SdrCircObj
) )
1665 // cell position is returned in rPosition
1667 rPosition
= pData
->maStart
;
1668 eType
= SC_DETOBJ_CIRCLE
;
1677 void ScDetectiveFunc::InsertObject( ScDetectiveObjType eType
,
1678 const ScAddress
& rPosition
, const ScRange
& rSource
,
1681 ScDrawLayer
* pModel
= pDoc
->GetDrawLayer();
1682 if (!pModel
) return;
1683 ScDetectiveData
aData( pModel
);
1687 case SC_DETOBJ_ARROW
:
1688 case SC_DETOBJ_FROMOTHERTAB
:
1689 InsertArrow( rPosition
.Col(), rPosition
.Row(),
1690 rSource
.aStart
.Col(), rSource
.aStart
.Row(),
1691 rSource
.aEnd
.Col(), rSource
.aEnd
.Row(),
1692 (eType
== SC_DETOBJ_FROMOTHERTAB
), bRedLine
, aData
);
1694 case SC_DETOBJ_TOOTHERTAB
:
1695 InsertToOtherTab( rSource
.aStart
.Col(), rSource
.aStart
.Row(),
1696 rSource
.aEnd
.Col(), rSource
.aEnd
.Row(),
1699 case SC_DETOBJ_CIRCLE
:
1700 DrawCircle( rPosition
.Col(), rPosition
.Row(), aData
);
1704 // added to avoid warnings
1710 ColorData
ScDetectiveFunc::GetArrowColor()
1712 if (!bColorsInitialized
)
1718 ColorData
ScDetectiveFunc::GetErrorColor()
1720 if (!bColorsInitialized
)
1726 ColorData
ScDetectiveFunc::GetCommentColor()
1728 if (!bColorsInitialized
)
1730 return nCommentColor
;
1734 void ScDetectiveFunc::InitializeColors()
1736 // may be called several times to update colors from configuration
1738 const svtools::ColorConfig
& rColorCfg
= SC_MOD()->GetColorConfig();
1739 nArrowColor
= rColorCfg
.GetColorValue(svtools::CALCDETECTIVE
).nColor
;
1740 nErrorColor
= rColorCfg
.GetColorValue(svtools::CALCDETECTIVEERROR
).nColor
;
1741 nCommentColor
= rColorCfg
.GetColorValue(svtools::CALCNOTESBACKGROUND
).nColor
;
1743 bColorsInitialized
= TRUE
;
1747 BOOL
ScDetectiveFunc::IsColorsInitialized()
1749 return bColorsInitialized
;