update dev300-m58
[ooovba.git] / sc / source / core / tool / detfunc.cxx
bloba1deff3e2d8df0438a33db7c37ebbc080cb56003
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"
77 #include "cell.hxx"
78 #include "docpool.hxx"
79 #include "patattr.hxx"
80 #include "attrib.hxx"
81 #include "scmod.hxx"
82 #include "postit.hxx"
83 #include "rangelst.hxx"
84 #include "reftokenhelper.hxx"
86 #include <vector>
88 using ::std::vector;
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
99 DET_INS_CONTINUE,
100 DET_INS_INSERTED,
101 DET_INS_EMPTY,
102 DET_INS_CIRCULAR };
105 //------------------------------------------------------------------------
107 class ScDetectiveData
109 private:
110 SfxItemSet aBoxSet;
111 SfxItemSet aArrowSet;
112 SfxItemSet aToTabSet;
113 SfxItemSet aFromTabSet;
114 SfxItemSet aCircleSet; //! einzeln ?
115 USHORT nMaxLevel;
117 public:
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; }
130 class ScCommentData
132 public:
133 ScCommentData( ScDocument& rDoc, SdrModel* pModel );
135 SfxItemSet& GetCaptionSet() { return aCaptionSet; }
136 void UpdateCaptionSet( const SfxItemSet& rItemSet );
138 private:
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 )
167 nMaxLevel = 0;
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 ) );
238 // shadow
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 ) );
246 // text attributes
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)
274 switch(nWhich)
276 case SDRATTR_SHADOW:
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.
280 break;
281 case SDRATTR_SHADOWXDIST:
282 // use existing Caption default - svx sets a value of 35
283 // but default 100 gives a better appearance.
284 break;
285 case SDRATTR_SHADOWYDIST:
286 // use existing Caption default - svx sets a value of 35
287 // but default 100 gives a better appearance.
288 break;
290 default:
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;
315 USHORT nError = 0;
317 ScCellIterator aCellIter( pDoc, rRange);
318 ScBaseCell* pCell = aCellIter.GetFirst();
319 while (pCell)
321 if (pCell->GetCellType() == CELLTYPE_FORMULA)
323 nError = ((ScFormulaCell*)pCell)->GetErrCode();
324 if (nError)
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" );
336 SanitizeCol( nCol );
337 SanitizeRow( nRow );
339 Point aPos;
341 switch( eMode )
343 case DRAWPOS_TOPLEFT:
344 break;
345 case DRAWPOS_BOTTOMRIGHT:
346 ++nCol;
347 ++nRow;
348 break;
349 case DRAWPOS_DETARROW:
350 aPos.X() += pDoc->GetColWidth( nCol, nTab ) / 4;
351 aPos.Y() += pDoc->GetRowHeight( nRow, nTab ) / 2;
352 break;
353 case DRAWPOS_CAPTIONLEFT:
354 aPos.X() += 6;
355 break;
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();
362 else
363 ++nCol;
364 aPos.X() -= 6;
366 break;
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 ) )
377 aPos.X() *= -1;
379 return aPos;
382 Rectangle ScDetectiveFunc::GetDrawRect( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
384 Rectangle aRect(
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
388 return aRect;
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())
407 return true;
411 return false;
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");
423 return TRUE;
426 Rectangle aStartRect;
427 Rectangle aEndRect;
428 if (!bStartAlien)
429 aStartRect = GetDrawRect( rStart.Col(), rStart.Row() );
430 if (!bEndAlien)
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 ?");
437 BOOL bFound = FALSE;
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() );
449 BOOL bObjEndAlien =
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 )
458 bFound = TRUE;
460 pObject = aIter.Next();
463 return bFound;
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() );
475 BOOL bObjEndAlien =
476 lcl_IsOtherTab( ((const XLineEndItem&)rSet.Get(XATTR_LINEEND)).GetLineEndValue() );
478 return !bObjStartAlien && !bObjEndAlien;
481 return FALSE;
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 );
520 if (bFromOtherTab)
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
536 else
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 );
555 if (bFromOtherTab)
556 pData->maStart.SetInvalid();
557 else
558 pData->maStart.Set( nRefStartCol, nRefStartRow, nTab);
560 pData->maEnd.Set( nCol, nRow, nTab);
562 Modified();
563 return TRUE;
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 );
574 if (bArea)
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 );
596 if (aEndPos.Y() < 0)
597 aEndPos.Y() += 2000;
599 SfxItemSet& rAttrSet = rData.GetToTabSet();
600 if (bArea)
601 rAttrSet.Put( XLineWidthItem( 50 ) ); // Bereich
602 else
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();
625 Modified();
626 return TRUE;
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,
639 const ScRange& rRef,
640 ScDetectiveData& rData )
642 if ( HasArrow( rRef.aStart, nCol, nRow, nTab ) )
643 return FALSE;
645 ScAddress aErrorPos;
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 ) )
659 return FALSE;
661 ScAddress aErrorPos;
662 BOOL bError = HasError( rRef, aErrorPos );
664 return InsertToOtherTab( rRef.aStart.Col(), rRef.aStart.Row(),
665 rRef.aEnd.Col(), rRef.aEnd.Row(),
666 bError, rData );
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 );
675 aRect.Left() -= 250;
676 aRect.Right() += 250;
677 aRect.Top() -= 70;
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();
694 Modified();
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();
707 long nDelCount = 0;
708 ULONG nObjCount = pPage->GetObjCount();
709 if (nObjCount)
711 SdrObject** ppObj = new SdrObject*[nObjCount];
713 SdrObjListIter aIter( *pPage, IM_FLAT );
714 SdrObject* pObject = aIter.Next();
715 while (pObject)
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();
727 long i;
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() );
734 delete[] ppObj;
736 Modified();
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 )
760 /* String aStr;
761 aStr += nCol1;
762 aStr += '/';
763 aStr += nRow1;
764 aStr += '/';
765 aStr += nCol2;
766 aStr += '/';
767 aStr += nRow2;
768 InfoBox(0,aStr).Execute();
771 Rectangle aCornerRect = GetDrawRect( nCol1, nRow1, nCol2, nRow2 );
772 Point aStartCorner = aCornerRect.TopLeft();
773 Point aEndCorner = aCornerRect.BottomRight();
774 Rectangle aObjRect;
776 ScDrawLayer* pModel = pDoc->GetDrawLayer();
777 SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
778 DBG_ASSERT(pPage,"Page ?");
780 pPage->RecalcObjOrdNums();
782 long nDelCount = 0;
783 ULONG nObjCount = pPage->GetObjCount();
784 if (nObjCount)
786 SdrObject** ppObj = new SdrObject*[nObjCount];
788 SdrObjListIter aIter( *pPage, IM_FLAT );
789 SdrObject* pObject = aIter.Next();
790 while (pObject)
792 if ( pObject->GetLayer() == SC_LAYER_INTERN &&
793 pObject->Type() == TYPE(SdrRectObj) )
795 aObjRect = ((SdrRectObj*)pObject)->GetLogicRect();
796 aObjRect.Justify();
797 if ( RectIsPoints( aObjRect, aStartCorner, aEndCorner ) )
798 ppObj[nDelCount++] = pObject;
801 pObject = aIter.Next();
804 long i;
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() );
811 delete[] ppObj;
813 Modified();
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();
826 while (pCell)
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;
833 break;
834 case DET_INS_CONTINUE:
835 if (nResult != DET_INS_INSERTED)
836 nResult = DET_INS_CONTINUE;
837 break;
838 case DET_INS_CIRCULAR:
839 if (nResult == DET_INS_EMPTY)
840 nResult = DET_INS_CIRCULAR;
841 break;
844 pCell = aCellIter.GetNext();
847 return nResult;
850 USHORT ScDetectiveFunc::InsertPredLevel( SCCOL nCol, SCROW nRow, ScDetectiveData& rData,
851 USHORT nLevel )
853 ScBaseCell* pCell;
854 pDoc->GetCell( nCol, nRow, nTab, pCell );
855 if (!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 );
871 ScRange aRef;
872 while ( aIter.GetNextRef( aRef ) )
874 if (DrawEntry( nCol, nRow, aRef, rData ))
876 nResult = DET_INS_INSERTED; // neuer Pfeil eingetragen
878 else
880 // weiterverfolgen
882 if ( nLevel < rData.GetMaxLevel() )
884 USHORT nSubResult;
885 BOOL bArea = (aRef.aStart != aRef.aEnd);
886 if (bArea)
887 nSubResult = InsertPredLevelArea( aRef, rData, nLevel+1 );
888 else
889 nSubResult = InsertPredLevel( aRef.aStart.Col(), aRef.aStart.Row(),
890 rData, nLevel+1 );
892 switch (nSubResult)
894 case DET_INS_INSERTED:
895 nResult = DET_INS_INSERTED;
896 break;
897 case DET_INS_CONTINUE:
898 if (nResult != DET_INS_INSERTED)
899 nResult = DET_INS_CONTINUE;
900 break;
901 case DET_INS_CIRCULAR:
902 if (nResult == DET_INS_EMPTY)
903 nResult = DET_INS_CIRCULAR;
904 break;
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);
916 return nResult;
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();
926 while (pCell)
928 if (pCell->GetCellType() == CELLTYPE_FORMULA)
930 USHORT nTemp = FindPredLevel( aCellIter.GetCol(), aCellIter.GetRow(), nLevel, nDeleteLevel );
931 if (nTemp > nResult)
932 nResult = nTemp;
934 pCell = aCellIter.GetNext();
937 return nResult;
940 // nDeleteLevel != 0 -> loeschen
942 USHORT ScDetectiveFunc::FindPredLevel( SCCOL nCol, SCROW nRow, USHORT nLevel, USHORT nDeleteLevel )
944 DBG_ASSERT( nLevel<1000, "Level" );
946 ScBaseCell* pCell;
947 pDoc->GetCell( nCol, nRow, nTab, pCell );
948 if (!pCell)
949 return nLevel;
950 if (pCell->GetCellType() != CELLTYPE_FORMULA)
951 return nLevel;
953 ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
954 if (pFCell->IsRunning())
955 return nLevel;
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 );
964 if ( bDelete )
966 DeleteArrowsAt( nCol, nRow, TRUE ); // Pfeile, die hierher zeigen
969 ScDetectiveRefIter aIter( (ScFormulaCell*) pCell );
970 ScRange aRef;
971 while ( aIter.GetNextRef( aRef) )
973 BOOL bArea = ( aRef.aStart != aRef.aEnd );
975 if ( bDelete ) // Rahmen loeschen ?
977 if (bArea)
979 DeleteBox( aRef.aStart.Col(), aRef.aStart.Row(), aRef.aEnd.Col(), aRef.aEnd.Row() );
982 else // weitersuchen
984 if ( HasArrow( aRef.aStart, nCol,nRow,nTab ) )
986 USHORT nTemp;
987 if (bArea)
988 nTemp = FindPredLevelArea( aRef, nLevel+1, nDeleteLevel );
989 else
990 nTemp = FindPredLevel( aRef.aStart.Col(),aRef.aStart.Row(),
991 nLevel+1, nDeleteLevel );
992 if (nTemp > nResult)
993 nResult = nTemp;
998 pFCell->SetRunning(FALSE);
1000 return nResult;
1003 //------------------------------------------------------------------------
1005 USHORT ScDetectiveFunc::InsertErrorLevel( SCCOL nCol, SCROW nRow, ScDetectiveData& rData,
1006 USHORT nLevel )
1008 ScBaseCell* pCell;
1009 pDoc->GetCell( nCol, nRow, nTab, pCell );
1010 if (!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 );
1026 ScRange aRef;
1027 ScAddress aErrorPos;
1028 BOOL bHasError = FALSE;
1029 while ( aIter.GetNextRef( aRef ) )
1031 if (HasError( aRef, aErrorPos ))
1033 bHasError = TRUE;
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);
1050 // Blaetter ?
1051 if (!bHasError)
1052 if (InsertPredLevel( nCol, nRow, rData, rData.GetMaxLevel() ) == DET_INS_INSERTED)
1053 nResult = DET_INS_INSERTED;
1055 return nResult;
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();
1069 while (pCell)
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 );
1081 ScRange aRef;
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 );
1091 BOOL bDrawRet;
1092 if (bAlien)
1093 bDrawRet = DrawAlienEntry( aRef, rData );
1094 else
1095 bDrawRet = DrawEntry( aCellIter.GetCol(), aCellIter.GetRow(),
1096 aRef, rData );
1097 if (bDrawRet)
1099 nResult = DET_INS_INSERTED; // neuer Pfeil eingetragen
1101 else
1103 if (bRunning)
1105 if (nResult == DET_INS_EMPTY)
1106 nResult = DET_INS_CIRCULAR;
1108 else
1110 // weiterverfolgen
1112 if ( nLevel < rData.GetMaxLevel() )
1114 USHORT nSubResult = InsertSuccLevel(
1115 aCellIter.GetCol(), aCellIter.GetRow(),
1116 aCellIter.GetCol(), aCellIter.GetRow(),
1117 rData, nLevel+1 );
1118 switch (nSubResult)
1120 case DET_INS_INSERTED:
1121 nResult = DET_INS_INSERTED;
1122 break;
1123 case DET_INS_CONTINUE:
1124 if (nResult != DET_INS_INSERTED)
1125 nResult = DET_INS_CONTINUE;
1126 break;
1127 case DET_INS_CIRCULAR:
1128 if (nResult == DET_INS_EMPTY)
1129 nResult = DET_INS_CIRCULAR;
1130 break;
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();
1147 return nResult;
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();
1160 while (pCell)
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 );
1172 ScRange aRef;
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)
1198 nResult = nTemp;
1204 pFCell->SetRunning(bRunning);
1206 pCell = aCellIter.GetNext();
1209 return nResult;
1214 // --------------------------------------------------------------------------------
1217 BOOL ScDetectiveFunc::ShowPred( SCCOL nCol, SCROW nRow )
1219 ScDrawLayer* pModel = pDoc->GetDrawLayer();
1220 if (!pModel)
1221 return FALSE;
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 );
1231 ++nMaxLevel;
1234 return ( nResult == DET_INS_INSERTED );
1237 BOOL ScDetectiveFunc::ShowSucc( SCCOL nCol, SCROW nRow )
1239 ScDrawLayer* pModel = pDoc->GetDrawLayer();
1240 if (!pModel)
1241 return FALSE;
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 );
1251 ++nMaxLevel;
1254 return ( nResult == DET_INS_INSERTED );
1257 BOOL ScDetectiveFunc::ShowError( SCCOL nCol, SCROW nRow )
1259 ScDrawLayer* pModel = pDoc->GetDrawLayer();
1260 if (!pModel)
1261 return FALSE;
1263 ScRange aRange( nCol, nRow, nTab );
1264 ScAddress aErrPos;
1265 if ( !HasError( aRange,aErrPos ) )
1266 return FALSE;
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();
1279 if (!pModel)
1280 return FALSE;
1282 USHORT nLevelCount = FindSuccLevel( nCol, nRow, nCol, nRow, 0, 0 );
1283 if ( nLevelCount )
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();
1292 if (!pModel)
1293 return FALSE;
1295 USHORT nLevelCount = FindPredLevel( nCol, nRow, 0, 0 );
1296 if ( nLevelCount )
1297 FindPredLevel( nCol, nRow, 0, nLevelCount ); // loeschen
1299 return ( nLevelCount != 0 );
1302 BOOL ScDetectiveFunc::DeleteAll( ScDetectiveDelete eWhat )
1304 ScDrawLayer* pModel = pDoc->GetDrawLayer();
1305 if (!pModel)
1306 return FALSE;
1308 SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
1309 DBG_ASSERT(pPage,"Page ?");
1311 pPage->RecalcObjOrdNums();
1313 long nDelCount = 0;
1314 ULONG nObjCount = pPage->GetObjCount();
1315 if (nObjCount)
1317 SdrObject** ppObj = new SdrObject*[nObjCount];
1319 SdrObjListIter aIter( *pPage, IM_FLAT );
1320 SdrObject* pObject = aIter.Next();
1321 while (pObject)
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
1333 bDoThis = bCircle;
1334 else if ( eWhat == SC_DET_ARROWS ) // DetectiveRefresh
1335 bDoThis = !bCaption && !bCircle; // don't include circles
1336 else
1338 DBG_ERROR("wat?");
1341 if ( bDoThis )
1342 ppObj[nDelCount++] = pObject;
1345 pObject = aIter.Next();
1348 long i;
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() );
1355 delete[] ppObj;
1357 Modified();
1360 return ( nDelCount != 0 );
1363 BOOL ScDetectiveFunc::MarkInvalid(BOOL& rOverflow)
1365 rOverflow = FALSE;
1366 ScDrawLayer* pModel = pDoc->GetDrawLayer();
1367 if (!pModel)
1368 return FALSE;
1370 BOOL bDeleted = DeleteAll( SC_DET_CIRCLES ); // nur die Kreise
1372 ScDetectiveData aData( pModel );
1373 long nInsCount = 0;
1375 // Stellen suchen, wo Gueltigkeit definiert ist
1377 ScDocAttrIterator aAttrIter( pDoc, nTab, 0,0,MAXCOL,MAXROW );
1378 SCCOL nCol;
1379 SCROW nRow1;
1380 SCROW nRow2;
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();
1385 if (nIndex)
1387 const ScValidationData* pData = pDoc->GetValidationEntry( nIndex );
1388 if ( pData )
1390 // Zellen in dem Bereich durchgehen
1392 BOOL bMarkEmpty = !pData->IsIgnoreBlank();
1393 SCROW nNextRow = nRow1;
1394 SCROW nRow;
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();
1400 if ( bMarkEmpty )
1401 for ( nRow = nNextRow; nRow < nCellRow && nInsCount < SC_DET_MAXCIRCLE; nRow++ )
1403 DrawCircle( nCol, nRow, aData );
1404 ++nInsCount;
1406 if ( !pData->IsDataValid( pCell, ScAddress( nCol, nCellRow, nTab ) ) )
1408 DrawCircle( nCol, nCellRow, aData );
1409 ++nInsCount;
1411 nNextRow = nCellRow + 1;
1412 pCell = aCellIter.GetNext();
1414 if ( bMarkEmpty )
1415 for ( nRow = nNextRow; nRow <= nRow2 && nInsCount < SC_DET_MAXCIRCLE; nRow++ )
1417 DrawCircle( nCol, nRow, aData );
1418 ++nInsCount;
1423 pPattern = aAttrIter.GetNext( nCol, nRow1, nRow2 );
1426 if ( nInsCount >= SC_DET_MAXCIRCLE )
1427 rOverflow = TRUE;
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)
1439 continue;
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)
1462 continue;
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();
1486 if (!pModel)
1487 return;
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 ?" );
1494 if( pPage )
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" );
1504 if( pNote )
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();
1528 if (!pModel)
1529 return;
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 ?" );
1535 if( pPage )
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;
1545 ScAddress aPos;
1546 ScRange aSource;
1547 BOOL bDummy;
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
1553 ScAddress aErrPos;
1554 if ( HasError( aSource, aErrPos ) )
1555 bError = TRUE;
1556 else
1557 bArrow = TRUE;
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
1563 // are marked red)
1565 ScAddress aErrPos;
1566 if ( HasError( ScRange( aPos), aErrPos ) )
1567 bError = TRUE;
1568 else
1569 bArrow = TRUE;
1571 else if ( eType == SC_DETOBJ_CIRCLE )
1573 // circles (error marks) are always red
1575 bError = TRUE;
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 ) )
1583 bArrow = TRUE;
1587 if ( bArrow || bError )
1589 ColorData nColorData = ( bError ? GetErrorColor() : GetArrowColor() );
1590 //pObject->SendRepaintBroadcast(pObject->GetBoundRect());
1591 pObject->SetMergedItem( XLineColorItem( String(), Color( nColorData ) ) );
1593 // repaint only
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());
1621 if(nOrdNum > 0)
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;
1631 return TRUE;
1636 return FALSE;
1639 ScDetectiveObjType ScDetectiveFunc::GetDetectiveObjectType( SdrObject* pObject, SCTAB nObjTab,
1640 ScAddress& rPosition, ScRange& rSource, BOOL& rRedLine )
1642 rRedLine = FALSE;
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
1656 if ( bValidStart )
1657 eType = bValidEnd ? SC_DETOBJ_ARROW : SC_DETOBJ_TOOTHERTAB;
1658 else if ( bValidEnd )
1659 eType = SC_DETOBJ_FROMOTHERTAB;
1661 if ( bValidStart )
1662 rSource = pData->maStart;
1663 if ( bValidEnd )
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() )
1675 rRedLine = TRUE;
1677 else if ( pObject->ISA(SdrCircObj) )
1679 if ( bValidStart )
1681 // cell position is returned in rPosition
1683 rPosition = pData->maStart;
1684 eType = SC_DETOBJ_CIRCLE;
1690 return eType;
1693 void ScDetectiveFunc::InsertObject( ScDetectiveObjType eType,
1694 const ScAddress& rPosition, const ScRange& rSource,
1695 BOOL bRedLine )
1697 ScDrawLayer* pModel = pDoc->GetDrawLayer();
1698 if (!pModel) return;
1699 ScDetectiveData aData( pModel );
1701 switch (eType)
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 );
1709 break;
1710 case SC_DETOBJ_TOOTHERTAB:
1711 InsertToOtherTab( rSource.aStart.Col(), rSource.aStart.Row(),
1712 rSource.aEnd.Col(), rSource.aEnd.Row(),
1713 bRedLine, aData );
1714 break;
1715 case SC_DETOBJ_CIRCLE:
1716 DrawCircle( rPosition.Col(), rPosition.Row(), aData );
1717 break;
1718 default:
1720 // added to avoid warnings
1725 // static
1726 ColorData ScDetectiveFunc::GetArrowColor()
1728 if (!bColorsInitialized)
1729 InitializeColors();
1730 return nArrowColor;
1733 // static
1734 ColorData ScDetectiveFunc::GetErrorColor()
1736 if (!bColorsInitialized)
1737 InitializeColors();
1738 return nErrorColor;
1741 // static
1742 ColorData ScDetectiveFunc::GetCommentColor()
1744 if (!bColorsInitialized)
1745 InitializeColors();
1746 return nCommentColor;
1749 // static
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;
1762 // static
1763 BOOL ScDetectiveFunc::IsColorsInitialized()
1765 return bColorsInitialized;