LibreOffice Module sc (master)  1
detfunc.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <scitems.hxx>
21 #include <svtools/colorcfg.hxx>
22 #include <editeng/eeitem.hxx>
23 #include <formula/errorcodes.hxx>
24 #include <o3tl/unit_conversion.hxx>
25 #include <svx/sdshitm.hxx>
26 #include <svx/sdsxyitm.hxx>
27 #include <svx/sdtditm.hxx>
28 #include <svx/svditer.hxx>
29 #include <svx/svdocapt.hxx>
30 #include <svx/svdocirc.hxx>
31 #include <svx/svdopath.hxx>
32 #include <svx/svdorect.hxx>
33 #include <svx/svdpage.hxx>
34 #include <svx/svdundo.hxx>
35 #include <svx/xfillit0.hxx>
36 #include <svx/xflclit.hxx>
37 #include <svx/xlnclit.hxx>
38 #include <svx/xlnedcit.hxx>
39 #include <svx/xlnedit.hxx>
40 #include <svx/xlnedwit.hxx>
41 #include <svx/xlnstcit.hxx>
42 #include <svx/xlnstit.hxx>
43 #include <svx/xlnstwit.hxx>
44 #include <svx/xlnwtit.hxx>
45 #include <svx/sdtagitm.hxx>
46 #include <svx/sxcecitm.hxx>
47 #include <svl/whiter.hxx>
48 #include <osl/diagnose.h>
49 
53 
54 #include <attrib.hxx>
55 #include <detfunc.hxx>
56 #include <document.hxx>
57 #include <dociter.hxx>
58 #include <drwlayer.hxx>
59 #include <userdat.hxx>
60 #include <validat.hxx>
61 #include <formulacell.hxx>
62 #include <docpool.hxx>
63 #include <patattr.hxx>
64 #include <scmod.hxx>
65 #include <postit.hxx>
66 #include <reftokenhelper.hxx>
67 #include <formulaiter.hxx>
68 #include <cellvalue.hxx>
69 
70 #include <vector>
71 #include <memory>
72 
73 using ::std::vector;
74 using namespace com::sun::star;
75 
76 // line ends are now created with an empty name.
77 // The checkForUniqueItem method then finds a unique name for the item's value.
78 #define SC_LINEEND_NAME EMPTY_OUSTRING
79 
80 namespace {
81 
82 enum DetInsertResult { // return-values for inserting in one level
83  DET_INS_CONTINUE,
84  DET_INS_INSERTED,
85  DET_INS_EMPTY,
86  DET_INS_CIRCULAR };
87 
88 }
89 
91 {
92 private:
97  SfxItemSet aCircleSet; //TODO: individually ?
98  sal_uInt16 nMaxLevel;
99 
100 public:
101  explicit ScDetectiveData( SdrModel* pModel );
102 
103  SfxItemSet& GetBoxSet() { return aBoxSet; }
104  SfxItemSet& GetArrowSet() { return aArrowSet; }
105  SfxItemSet& GetToTabSet() { return aToTabSet; }
106  SfxItemSet& GetFromTabSet() { return aFromTabSet; }
107  SfxItemSet& GetCircleSet() { return aCircleSet; }
108 
109  void SetMaxLevel( sal_uInt16 nVal ) { nMaxLevel = nVal; }
110  sal_uInt16 GetMaxLevel() const { return nMaxLevel; }
111 };
112 
113 namespace {
114 
115 class ScCommentData
116 {
117 public:
118  ScCommentData( ScDocument& rDoc, SdrModel* pModel );
119 
120  SfxItemSet& GetCaptionSet() { return aCaptionSet; }
121  void UpdateCaptionSet( const SfxItemSet& rItemSet );
122 
123 private:
124  SfxItemSet aCaptionSet;
125 };
126 
127 }
128 
133 
134 static bool lcl_HasThickLine( const SdrObject& rObj )
135 {
136  // thin lines get width 0 -> everything greater 0 is a thick line
137 
138  return rObj.GetMergedItem(XATTR_LINEWIDTH).GetValue() > 0;
139 }
140 
142  aBoxSet( pModel->GetItemPool(), svl::Items<SDRATTR_START, SDRATTR_END> ),
143  aArrowSet( pModel->GetItemPool(), svl::Items<SDRATTR_START, SDRATTR_END> ),
144  aToTabSet( pModel->GetItemPool(), svl::Items<SDRATTR_START, SDRATTR_END> ),
145  aFromTabSet( pModel->GetItemPool(), svl::Items<SDRATTR_START, SDRATTR_END> ),
146  aCircleSet( pModel->GetItemPool(), svl::Items<SDRATTR_START, SDRATTR_END> ),
147  nMaxLevel(0)
148 {
149 
151  aBoxSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
152 
153  // create default line endings (like XLineEndList::Create)
154  // to be independent from the configured line endings
155 
156  basegfx::B2DPolygon aTriangle;
157  aTriangle.append(basegfx::B2DPoint(10.0, 0.0));
158  aTriangle.append(basegfx::B2DPoint(0.0, 30.0));
159  aTriangle.append(basegfx::B2DPoint(20.0, 30.0));
160  aTriangle.setClosed(true);
161 
162  basegfx::B2DPolygon aSquare;
163  aSquare.append(basegfx::B2DPoint(0.0, 0.0));
164  aSquare.append(basegfx::B2DPoint(10.0, 0.0));
165  aSquare.append(basegfx::B2DPoint(10.0, 10.0));
166  aSquare.append(basegfx::B2DPoint(0.0, 10.0));
167  aSquare.setClosed(true);
168 
170  aCircle.setClosed(true);
171 
172  OUString aName = SC_LINEEND_NAME;
173 
174  aArrowSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aCircle) ) );
177  aArrowSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aTriangle) ) );
178  aArrowSet.Put( XLineEndWidthItem( 200 ) );
179  aArrowSet.Put( XLineEndCenterItem( false ) );
180 
181  aToTabSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aCircle) ) );
184  aToTabSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aSquare) ) );
185  aToTabSet.Put( XLineEndWidthItem( 300 ) );
186  aToTabSet.Put( XLineEndCenterItem( false ) );
187 
191  aFromTabSet.Put( XLineEndItem( aName, basegfx::B2DPolyPolygon(aTriangle) ) );
193  aFromTabSet.Put( XLineEndCenterItem( false ) );
194 
196  aCircleSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
197  aCircleSet.Put( XLineWidthItem( 55 ) ); // 54 = 1 Pixel
198 }
199 
200 ScCommentData::ScCommentData( ScDocument& rDoc, SdrModel* pModel ) :
201  aCaptionSet( pModel->GetItemPool(), svl::Items<SDRATTR_START, SDRATTR_END, EE_ITEMS_START, EE_ITEMS_END> )
202 {
203  basegfx::B2DPolygon aTriangle;
204  aTriangle.append(basegfx::B2DPoint(10.0, 0.0));
205  aTriangle.append(basegfx::B2DPoint(0.0, 30.0));
206  aTriangle.append(basegfx::B2DPoint(20.0, 30.0));
207  aTriangle.setClosed(true);
208 
209  OUString aName = SC_LINEEND_NAME;
210 
211  aCaptionSet.Put( XLineStartItem( aName, basegfx::B2DPolyPolygon(aTriangle) ) );
212  aCaptionSet.Put( XLineStartWidthItem( 200 ) );
213  aCaptionSet.Put( XLineStartCenterItem( false ) );
214  aCaptionSet.Put( XFillStyleItem( drawing::FillStyle_SOLID ) );
216  aCaptionSet.Put( XFillColorItem( OUString(), aYellow ) );
217 
218  // shadow
219  // SdrShadowItem has sal_False, instead the shadow is set for the rectangle
220  // only with SetSpecialTextBoxShadow when the object is created
221  // (item must be set to adjust objects from older files)
222  aCaptionSet.Put( makeSdrShadowItem( false ) );
223  aCaptionSet.Put( makeSdrShadowXDistItem( 100 ) );
224  aCaptionSet.Put( makeSdrShadowYDistItem( 100 ) );
225 
226  // text attributes
227  aCaptionSet.Put( makeSdrTextLeftDistItem( 100 ) );
228  aCaptionSet.Put( makeSdrTextRightDistItem( 100 ) );
229  aCaptionSet.Put( makeSdrTextUpperDistItem( 100 ) );
230  aCaptionSet.Put( makeSdrTextLowerDistItem( 100 ) );
231 
232  aCaptionSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
233  aCaptionSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
234 
235  // do use the default cell style, so the user has a chance to
236  // modify the font for the annotations
237  rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN).FillEditItemSet( &aCaptionSet );
238 
239  // support the best position for the tail connector now that
240  // that notes can be resized and repositioned.
241  aCaptionSet.Put( SdrCaptionEscDirItem( SdrCaptionEscDir::BestFit) );
242 }
243 
244 void ScCommentData::UpdateCaptionSet( const SfxItemSet& rItemSet )
245 {
246  SfxWhichIter aWhichIter( rItemSet );
247  const SfxPoolItem* pPoolItem = nullptr;
248 
249  for( sal_uInt16 nWhich = aWhichIter.FirstWhich(); nWhich > 0; nWhich = aWhichIter.NextWhich() )
250  {
251  if(rItemSet.GetItemState(nWhich, false, &pPoolItem) == SfxItemState::SET)
252  {
253  switch(nWhich)
254  {
255  case SDRATTR_SHADOW:
256  // use existing Caption default - appears that setting this
257  // to true screws up the tail appearance. See also comment
258  // for default setting above.
259  break;
260  case SDRATTR_SHADOWXDIST:
261  // use existing Caption default - svx sets a value of 35
262  // but default 100 gives a better appearance.
263  break;
264  case SDRATTR_SHADOWYDIST:
265  // use existing Caption default - svx sets a value of 35
266  // but default 100 gives a better appearance.
267  break;
268 
269  default:
270  aCaptionSet.Put(*pPoolItem);
271  }
272  }
273  }
274 }
275 
277 {
278  rDoc.SetStreamValid(nTab, false);
279 }
280 
281 static bool Intersect( SCCOL nStartCol1, SCROW nStartRow1, SCCOL nEndCol1, SCROW nEndRow1,
282  SCCOL nStartCol2, SCROW nStartRow2, SCCOL nEndCol2, SCROW nEndRow2 )
283 {
284  return nEndCol1 >= nStartCol2 && nEndCol2 >= nStartCol1 &&
285  nEndRow1 >= nStartRow2 && nEndRow2 >= nStartRow1;
286 }
287 
288 bool ScDetectiveFunc::HasError( const ScRange& rRange, ScAddress& rErrPos )
289 {
290  rErrPos = rRange.aStart;
291  FormulaError nError = FormulaError::NONE;
292 
293  ScCellIterator aIter( rDoc, rRange);
294  for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
295  {
296  if (aIter.getType() != CELLTYPE_FORMULA)
297  continue;
298 
299  nError = aIter.getFormulaCell()->GetErrCode();
300  if (nError != FormulaError::NONE)
301  rErrPos = aIter.GetPos();
302  }
303 
304  return (nError != FormulaError::NONE);
305 }
306 
308 {
309  OSL_ENSURE( rDoc.ValidColRow( nCol, nRow ), "ScDetectiveFunc::GetDrawPos - invalid cell address" );
310  nCol = rDoc.SanitizeCol( nCol );
311  nRow = rDoc.SanitizeRow( nRow );
312 
313  Point aPos;
314 
315  switch( eMode )
316  {
318  break;
320  ++nCol;
321  ++nRow;
322  break;
324  aPos.AdjustX(rDoc.GetColWidth( nCol, nTab ) / 4 );
325  aPos.AdjustY(rDoc.GetRowHeight( nRow, nTab ) / 2 );
326  break;
327  }
328 
329  for ( SCCOL i = 0; i < nCol; ++i )
330  aPos.AdjustX(rDoc.GetColWidth( i, nTab ) );
331  aPos.AdjustY(rDoc.GetRowHeight( 0, nRow - 1, nTab ) );
332 
335 
336  if ( rDoc.IsNegativePage( nTab ) )
337  aPos.setX( aPos.X() * -1 );
338 
339  return aPos;
340 }
341 
343 {
344  tools::Rectangle aRect(
345  GetDrawPos( ::std::min( nCol1, nCol2 ), ::std::min( nRow1, nRow2 ), DrawPosMode::TopLeft ),
346  GetDrawPos( ::std::max( nCol1, nCol2 ), ::std::max( nRow1, nRow2 ), DrawPosMode::BottomRight ) );
347  aRect.Justify(); // reorder left/right in RTL sheets
348  return aRect;
349 }
350 
352 {
353  return GetDrawRect( nCol, nRow, nCol, nRow );
354 }
355 
356 static bool lcl_IsOtherTab( const basegfx::B2DPolyPolygon& rPolyPolygon )
357 {
358  // test if rPolygon is the line end for "other table" (rectangle)
359  if(1 == rPolyPolygon.count())
360  {
361  const basegfx::B2DPolygon& aSubPoly(rPolyPolygon.getB2DPolygon(0));
362 
363  // #i73305# circle consists of 4 segments, too, distinguishable from square by
364  // the use of control points
365  if(4 == aSubPoly.count() && aSubPoly.isClosed() && !aSubPoly.areControlPointsUsed())
366  {
367  return true;
368  }
369  }
370 
371  return false;
372 }
373 
375  SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab )
376 {
377  bool bStartAlien = ( rStart.Tab() != nTab );
378  bool bEndAlien = ( nEndTab != nTab );
379 
380  if (bStartAlien && bEndAlien)
381  {
382  OSL_FAIL("bStartAlien && bEndAlien");
383  return true;
384  }
385 
386  tools::Rectangle aStartRect;
387  tools::Rectangle aEndRect;
388  if (!bStartAlien)
389  aStartRect = GetDrawRect( rStart.Col(), rStart.Row() );
390  if (!bEndAlien)
391  aEndRect = GetDrawRect( nEndCol, nEndRow );
392 
393  ScDrawLayer* pModel = rDoc.GetDrawLayer();
394  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
395  OSL_ENSURE(pPage,"Page ?");
396 
397  bool bFound = false;
398  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
399  SdrObject* pObject = aIter.Next();
400  while (pObject && !bFound)
401  {
402  if ( pObject->GetLayer()==SC_LAYER_INTERN &&
403  pObject->IsPolyObj() && pObject->GetPointCount()==2 )
404  {
405  const SfxItemSet& rSet = pObject->GetMergedItemSet();
406 
407  bool bObjStartAlien =
408  lcl_IsOtherTab( rSet.Get(XATTR_LINESTART).GetLineStartValue() );
409  bool bObjEndAlien =
410  lcl_IsOtherTab( rSet.Get(XATTR_LINEEND).GetLineEndValue() );
411 
412  bool bStartHit = bStartAlien ? bObjStartAlien :
413  ( !bObjStartAlien && aStartRect.Contains(pObject->GetPoint(0)) );
414  bool bEndHit = bEndAlien ? bObjEndAlien :
415  ( !bObjEndAlien && aEndRect.Contains(pObject->GetPoint(1)) );
416 
417  if ( bStartHit && bEndHit )
418  bFound = true;
419  }
420  pObject = aIter.Next();
421  }
422 
423  return bFound;
424 }
425 
427 {
428  if ( pObject->GetLayer()==SC_LAYER_INTERN &&
429  pObject->IsPolyObj() && pObject->GetPointCount()==2 )
430  {
431  const SfxItemSet& rSet = pObject->GetMergedItemSet();
432 
433  bool bObjStartAlien =
434  lcl_IsOtherTab( rSet.Get(XATTR_LINESTART).GetLineStartValue() );
435  bool bObjEndAlien =
436  lcl_IsOtherTab( rSet.Get(XATTR_LINEEND).GetLineEndValue() );
437 
438  return !bObjStartAlien && !bObjEndAlien;
439  }
440 
441  return false;
442 }
443 
444 // InsertXXX: called from DrawEntry/DrawAlienEntry and InsertObject
445 
447  SCCOL nRefStartCol, SCROW nRefStartRow,
448  SCCOL nRefEndCol, SCROW nRefEndRow,
449  bool bFromOtherTab, bool bRed,
450  ScDetectiveData& rData )
451 {
452  ScDrawLayer* pModel = rDoc.GetDrawLayer();
453  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
454 
455  bool bArea = ( nRefStartCol != nRefEndCol || nRefStartRow != nRefEndRow );
456  if (bArea && !bFromOtherTab)
457  {
458  // insert the rectangle before the arrow - this is relied on in FindFrameForObject
459 
460  tools::Rectangle aRect = GetDrawRect( nRefStartCol, nRefStartRow, nRefEndCol, nRefEndRow );
461  SdrRectObj* pBox = new SdrRectObj(
462  *pModel,
463  aRect);
464 
466 
467  pBox->SetLayer( SC_LAYER_INTERN );
468  pPage->InsertObject( pBox );
469  pModel->AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pBox ) );
470 
472  pData->maStart.Set( nRefStartCol, nRefStartRow, nTab);
473  pData->maEnd.Set( nRefEndCol, nRefEndRow, nTab);
474  }
475 
476  Point aStartPos = GetDrawPos( nRefStartCol, nRefStartRow, DrawPosMode::DetectiveArrow );
477  Point aEndPos = GetDrawPos( nCol, nRow, DrawPosMode::DetectiveArrow );
478 
479  if (bFromOtherTab)
480  {
481  bool bNegativePage = rDoc.IsNegativePage( nTab );
482  tools::Long nPageSign = bNegativePage ? -1 : 1;
483 
484  aStartPos = Point( aEndPos.X() - 1000 * nPageSign, aEndPos.Y() - 1000 );
485  if (aStartPos.X() * nPageSign < 0)
486  aStartPos.AdjustX(2000 * nPageSign );
487  if (aStartPos.Y() < 0)
488  aStartPos.AdjustY(2000 );
489  }
490 
491  SfxItemSet& rAttrSet = bFromOtherTab ? rData.GetFromTabSet() : rData.GetArrowSet();
492 
493  if (bArea && !bFromOtherTab)
494  rAttrSet.Put( XLineWidthItem( 50 ) ); // range
495  else
496  rAttrSet.Put( XLineWidthItem( 0 ) ); // single reference
497 
498  Color nColor = ( bRed ? GetErrorColor() : GetArrowColor() );
499  rAttrSet.Put( XLineColorItem( OUString(), nColor ) );
500 
501  basegfx::B2DPolygon aTempPoly;
502  aTempPoly.append(basegfx::B2DPoint(aStartPos.X(), aStartPos.Y()));
503  aTempPoly.append(basegfx::B2DPoint(aEndPos.X(), aEndPos.Y()));
504  SdrPathObj* pArrow = new SdrPathObj(
505  *pModel,
506  OBJ_LINE,
507  basegfx::B2DPolyPolygon(aTempPoly));
508  pArrow->NbcSetLogicRect(tools::Rectangle::Justify(aStartPos,aEndPos)); //TODO: needed ???
509  pArrow->SetMergedItemSetAndBroadcast(rAttrSet);
510 
511  pArrow->SetLayer( SC_LAYER_INTERN );
512  pPage->InsertObject( pArrow );
513  pModel->AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pArrow ) );
514 
516  if (bFromOtherTab)
517  pData->maStart.SetInvalid();
518  else
519  pData->maStart.Set( nRefStartCol, nRefStartRow, nTab);
520 
521  pData->maEnd.Set( nCol, nRow, nTab);
523 
524  Modified();
525 }
526 
527 void ScDetectiveFunc::InsertToOtherTab( SCCOL nStartCol, SCROW nStartRow,
528  SCCOL nEndCol, SCROW nEndRow, bool bRed,
529  ScDetectiveData& rData )
530 {
531  ScDrawLayer* pModel = rDoc.GetDrawLayer();
532  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
533 
534  bool bArea = ( nStartCol != nEndCol || nStartRow != nEndRow );
535  if (bArea)
536  {
537  tools::Rectangle aRect = GetDrawRect( nStartCol, nStartRow, nEndCol, nEndRow );
538  SdrRectObj* pBox = new SdrRectObj(
539  *pModel,
540  aRect);
541 
543 
544  pBox->SetLayer( SC_LAYER_INTERN );
545  pPage->InsertObject( pBox );
546  pModel->AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pBox ) );
547 
549  pData->maStart.Set( nStartCol, nStartRow, nTab);
550  pData->maEnd.Set( nEndCol, nEndRow, nTab);
551  }
552 
553  bool bNegativePage = rDoc.IsNegativePage( nTab );
554  tools::Long nPageSign = bNegativePage ? -1 : 1;
555 
556  Point aStartPos = GetDrawPos( nStartCol, nStartRow, DrawPosMode::DetectiveArrow );
557  Point aEndPos( aStartPos.X() + 1000 * nPageSign, aStartPos.Y() - 1000 );
558  if (aEndPos.Y() < 0)
559  aEndPos.AdjustY(2000 );
560 
561  SfxItemSet& rAttrSet = rData.GetToTabSet();
562  if (bArea)
563  rAttrSet.Put( XLineWidthItem( 50 ) ); // range
564  else
565  rAttrSet.Put( XLineWidthItem( 0 ) ); // single reference
566 
567  Color nColor = ( bRed ? GetErrorColor() : GetArrowColor() );
568  rAttrSet.Put( XLineColorItem( OUString(), nColor ) );
569 
570  basegfx::B2DPolygon aTempPoly;
571  aTempPoly.append(basegfx::B2DPoint(aStartPos.X(), aStartPos.Y()));
572  aTempPoly.append(basegfx::B2DPoint(aEndPos.X(), aEndPos.Y()));
573  SdrPathObj* pArrow = new SdrPathObj(
574  *pModel,
575  OBJ_LINE,
576  basegfx::B2DPolyPolygon(aTempPoly));
577  pArrow->NbcSetLogicRect(tools::Rectangle::Justify(aStartPos,aEndPos)); //TODO: needed ???
578 
579  pArrow->SetMergedItemSetAndBroadcast(rAttrSet);
580 
581  pArrow->SetLayer( SC_LAYER_INTERN );
582  pPage->InsertObject( pArrow );
583  pModel->AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pArrow ) );
584 
585  ScDrawObjData* pData = ScDrawLayer::GetObjData( pArrow, true );
586  pData->maStart.Set( nStartCol, nStartRow, nTab);
587  pData->maEnd.SetInvalid();
588 
589  Modified();
590 }
591 
592 // DrawEntry: formula from this spreadsheet,
593 // reference on this or other
594 // DrawAlienEntry: formula from other spreadsheet,
595 // reference on this
596 
597 // return FALSE: there was already an arrow
598 
600  const ScRange& rRef,
601  ScDetectiveData& rData )
602 {
603  if ( HasArrow( rRef.aStart, nCol, nRow, nTab ) )
604  return false;
605 
606  ScAddress aErrorPos;
607  bool bError = HasError( rRef, aErrorPos );
608  bool bAlien = ( rRef.aEnd.Tab() < nTab || rRef.aStart.Tab() > nTab );
609 
610  InsertArrow( nCol, nRow,
611  rRef.aStart.Col(), rRef.aStart.Row(),
612  rRef.aEnd.Col(), rRef.aEnd.Row(),
613  bAlien, bError, rData );
614  return true;
615 }
616 
618  ScDetectiveData& rData )
619 {
620  if ( HasArrow( rRef.aStart, 0, 0, nTab+1 ) )
621  return false;
622 
623  ScAddress aErrorPos;
624  bool bError = HasError( rRef, aErrorPos );
625 
626  InsertToOtherTab( rRef.aStart.Col(), rRef.aStart.Row(),
627  rRef.aEnd.Col(), rRef.aEnd.Row(),
628  bError, rData );
629  return true;
630 }
631 
633 {
634  ScDrawLayer* pModel = rDoc.GetDrawLayer();
635  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
636 
637  tools::Rectangle aRect = ScDrawLayer::GetCellRect(rDoc, ScAddress(nCol, nRow, nTab), true);
638  aRect.AdjustLeft( -250 );
639  aRect.AdjustRight(250 );
640  aRect.AdjustTop( -70 );
641  aRect.AdjustBottom(70 );
642 
643  SdrCircObj* pCircle = new SdrCircObj(
644  *pModel,
645  SdrCircKind::Full,
646  aRect);
647  SfxItemSet& rAttrSet = rData.GetCircleSet();
648 
649  pCircle->SetMergedItemSetAndBroadcast(rAttrSet);
650 
651  pCircle->SetLayer( SC_LAYER_INTERN );
652  pPage->InsertObject( pCircle );
653  pModel->AddCalcUndo( std::make_unique<SdrUndoInsertObj>( *pCircle ) );
654 
655  ScDrawObjData* pData = ScDrawLayer::GetObjData( pCircle, true );
656  pData->maStart.Set( nCol, nRow, nTab);
657  pData->maEnd.SetInvalid();
659 
660  Modified();
661 }
662 
663 void ScDetectiveFunc::DeleteArrowsAt( SCCOL nCol, SCROW nRow, bool bDestPnt )
664 {
665  tools::Rectangle aRect = GetDrawRect( nCol, nRow );
666 
667  ScDrawLayer* pModel = rDoc.GetDrawLayer();
668  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
669  OSL_ENSURE(pPage,"Page ?");
670 
671  pPage->RecalcObjOrdNums();
672 
673  const size_t nObjCount = pPage->GetObjCount();
674  if (!nObjCount)
675  return;
676 
677  size_t nDelCount = 0;
678  std::unique_ptr<SdrObject*[]> ppObj(new SdrObject*[nObjCount]);
679 
680  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
681  SdrObject* pObject = aIter.Next();
682  while (pObject)
683  {
684  if ( pObject->GetLayer()==SC_LAYER_INTERN &&
685  pObject->IsPolyObj() && pObject->GetPointCount()==2 )
686  {
687  if (aRect.Contains(pObject->GetPoint(bDestPnt ? 1 : 0))) // start/destinationpoint
688  ppObj[nDelCount++] = pObject;
689  }
690 
691  pObject = aIter.Next();
692  }
693 
694  const bool bRecording = pModel->IsRecording();
695 
696  if (bRecording)
697  {
698  for (size_t i=1; i<=nDelCount; ++i)
699  pModel->AddCalcUndo(std::make_unique<SdrUndoDelObj>(*ppObj[nDelCount-i]));
700  }
701 
702  for (size_t i=1; i<=nDelCount; ++i)
703  {
704  // remove the object from the drawing page, delete if undo is disabled
705  SdrObject* pObj = pPage->RemoveObject(ppObj[nDelCount-i]->GetOrdNum());
706  if( !bRecording )
707  SdrObject::Free( pObj );
708  }
709 
710  ppObj.reset();
711 
712  Modified();
713 }
714 
715  // delete box around reference
716 
717 #define SC_DET_TOLERANCE 50
718 
719 static bool RectIsPoints( const tools::Rectangle& rRect, const Point& rStart, const Point& rEnd )
720 {
721  return rRect.Left() >= rStart.X() - SC_DET_TOLERANCE
722  && rRect.Left() <= rStart.X() + SC_DET_TOLERANCE
723  && rRect.Right() >= rEnd.X() - SC_DET_TOLERANCE
724  && rRect.Right() <= rEnd.X() + SC_DET_TOLERANCE
725  && rRect.Top() >= rStart.Y() - SC_DET_TOLERANCE
726  && rRect.Top() <= rStart.Y() + SC_DET_TOLERANCE
727  && rRect.Bottom() >= rEnd.Y() - SC_DET_TOLERANCE
728  && rRect.Bottom() <= rEnd.Y() + SC_DET_TOLERANCE;
729 }
730 
731 #undef SC_DET_TOLERANCE
732 
733 void ScDetectiveFunc::DeleteBox( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
734 {
735  tools::Rectangle aCornerRect = GetDrawRect( nCol1, nRow1, nCol2, nRow2 );
736  Point aStartCorner = aCornerRect.TopLeft();
737  Point aEndCorner = aCornerRect.BottomRight();
738  tools::Rectangle aObjRect;
739 
740  ScDrawLayer* pModel = rDoc.GetDrawLayer();
741  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
742  OSL_ENSURE(pPage,"Page ?");
743 
744  pPage->RecalcObjOrdNums();
745 
746  const size_t nObjCount = pPage->GetObjCount();
747  if (!nObjCount)
748  return;
749 
750  size_t nDelCount = 0;
751  std::unique_ptr<SdrObject*[]> ppObj(new SdrObject*[nObjCount]);
752 
753  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
754  SdrObject* pObject = aIter.Next();
755  while (pObject)
756  {
757  if ( pObject->GetLayer() == SC_LAYER_INTERN )
758  if ( auto pSdrRectObj = dynamic_cast< const SdrRectObj* >(pObject) )
759  {
760  aObjRect = pSdrRectObj->GetLogicRect();
761  aObjRect.Justify();
762  if ( RectIsPoints( aObjRect, aStartCorner, aEndCorner ) )
763  ppObj[nDelCount++] = pObject;
764  }
765 
766  pObject = aIter.Next();
767  }
768 
769  for (size_t i=1; i<=nDelCount; ++i)
770  pModel->AddCalcUndo( std::make_unique<SdrUndoRemoveObj>( *ppObj[nDelCount-i] ) );
771 
772  for (size_t i=1; i<=nDelCount; ++i)
773  pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
774 
775  ppObj.reset();
776 
777  Modified();
778 }
779 
781  ScDetectiveData& rData, sal_uInt16 nLevel )
782 {
783  sal_uInt16 nResult = DET_INS_EMPTY;
784 
785  ScCellIterator aIter( rDoc, rRef);
786  for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
787  {
788  if (aIter.getType() != CELLTYPE_FORMULA)
789  continue;
790 
791  const ScAddress& rPos = aIter.GetPos();
792  switch (InsertPredLevel(rPos.Col(), rPos.Row(), rData, nLevel))
793  {
794  case DET_INS_INSERTED:
795  nResult = DET_INS_INSERTED;
796  break;
797  case DET_INS_CONTINUE:
798  if (nResult != DET_INS_INSERTED)
799  nResult = DET_INS_CONTINUE;
800  break;
801  case DET_INS_CIRCULAR:
802  if (nResult == DET_INS_EMPTY)
803  nResult = DET_INS_CIRCULAR;
804  break;
805  default:
806  ;
807  }
808  }
809 
810  return nResult;
811 }
812 
814  sal_uInt16 nLevel )
815 {
816  ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, nTab));
817  if (aCell.meType != CELLTYPE_FORMULA)
818  return DET_INS_EMPTY;
819 
820  ScFormulaCell* pFCell = aCell.mpFormula;
821  if (pFCell->IsRunning())
822  return DET_INS_CIRCULAR;
823 
824  if (pFCell->GetDirty())
825  pFCell->Interpret(); // can't be called after SetRunning
826  pFCell->SetRunning(true);
827 
828  sal_uInt16 nResult = DET_INS_EMPTY;
829 
830  ScDetectiveRefIter aIter(rDoc, pFCell);
831  ScRange aRef;
832  while ( aIter.GetNextRef( aRef ) )
833  {
834  if (DrawEntry( nCol, nRow, aRef, rData ))
835  {
836  nResult = DET_INS_INSERTED; // insert new arrow
837  }
838  else
839  {
840  // continue
841 
842  if ( nLevel < rData.GetMaxLevel() )
843  {
844  sal_uInt16 nSubResult;
845  bool bArea = (aRef.aStart != aRef.aEnd);
846  if (bArea)
847  nSubResult = InsertPredLevelArea( aRef, rData, nLevel+1 );
848  else
849  nSubResult = InsertPredLevel( aRef.aStart.Col(), aRef.aStart.Row(),
850  rData, nLevel+1 );
851 
852  switch (nSubResult)
853  {
854  case DET_INS_INSERTED:
855  nResult = DET_INS_INSERTED;
856  break;
857  case DET_INS_CONTINUE:
858  if (nResult != DET_INS_INSERTED)
859  nResult = DET_INS_CONTINUE;
860  break;
861  case DET_INS_CIRCULAR:
862  if (nResult == DET_INS_EMPTY)
863  nResult = DET_INS_CIRCULAR;
864  break;
865  // DET_INS_EMPTY: no change
866  }
867  }
868  else // nMaxLevel reached
869  if (nResult != DET_INS_INSERTED)
870  nResult = DET_INS_CONTINUE;
871  }
872  }
873 
874  pFCell->SetRunning(false);
875 
876  return nResult;
877 }
878 
880  sal_uInt16 nLevel, sal_uInt16 nDeleteLevel )
881 {
882  sal_uInt16 nResult = nLevel;
883 
884  ScCellIterator aCellIter( rDoc, rRef);
885  for (bool bHasCell = aCellIter.first(); bHasCell; bHasCell = aCellIter.next())
886  {
887  if (aCellIter.getType() != CELLTYPE_FORMULA)
888  continue;
889 
890  sal_uInt16 nTemp = FindPredLevel(aCellIter.GetPos().Col(), aCellIter.GetPos().Row(), nLevel, nDeleteLevel);
891  if (nTemp > nResult)
892  nResult = nTemp;
893  }
894 
895  return nResult;
896 }
897 
898  // nDeleteLevel != 0 -> delete
899 
900 sal_uInt16 ScDetectiveFunc::FindPredLevel( SCCOL nCol, SCROW nRow, sal_uInt16 nLevel, sal_uInt16 nDeleteLevel )
901 {
902  OSL_ENSURE( nLevel<1000, "Level" );
903 
904  ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, nTab));
905  if (aCell.meType != CELLTYPE_FORMULA)
906  return nLevel;
907 
908  ScFormulaCell* pFCell = aCell.mpFormula;
909  if (pFCell->IsRunning())
910  return nLevel;
911 
912  if (pFCell->GetDirty())
913  pFCell->Interpret(); // can't be called after SetRunning
914  pFCell->SetRunning(true);
915 
916  sal_uInt16 nResult = nLevel;
917  bool bDelete = ( nDeleteLevel && nLevel == nDeleteLevel-1 );
918 
919  if ( bDelete )
920  {
921  DeleteArrowsAt( nCol, nRow, true ); // arrows, that are pointing here
922  }
923 
924  ScDetectiveRefIter aIter(rDoc, pFCell);
925  ScRange aRef;
926  while ( aIter.GetNextRef( aRef) )
927  {
928  bool bArea = ( aRef.aStart != aRef.aEnd );
929 
930  if ( bDelete ) // delete frame ?
931  {
932  if (bArea)
933  {
934  DeleteBox( aRef.aStart.Col(), aRef.aStart.Row(), aRef.aEnd.Col(), aRef.aEnd.Row() );
935  }
936  }
937  else // continue searching
938  {
939  if ( HasArrow( aRef.aStart, nCol,nRow,nTab ) )
940  {
941  sal_uInt16 nTemp;
942  if (bArea)
943  nTemp = FindPredLevelArea( aRef, nLevel+1, nDeleteLevel );
944  else
945  nTemp = FindPredLevel( aRef.aStart.Col(),aRef.aStart.Row(),
946  nLevel+1, nDeleteLevel );
947  if (nTemp > nResult)
948  nResult = nTemp;
949  }
950  }
951  }
952 
953  pFCell->SetRunning(false);
954 
955  return nResult;
956 }
957 
959  sal_uInt16 nLevel )
960 {
961  ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, nTab));
962  if (aCell.meType != CELLTYPE_FORMULA)
963  return DET_INS_EMPTY;
964 
965  ScFormulaCell* pFCell = aCell.mpFormula;
966  if (pFCell->IsRunning())
967  return DET_INS_CIRCULAR;
968 
969  if (pFCell->GetDirty())
970  pFCell->Interpret(); // can't be called after SetRunning
971  pFCell->SetRunning(true);
972 
973  sal_uInt16 nResult = DET_INS_EMPTY;
974 
975  ScDetectiveRefIter aIter(rDoc, pFCell);
976  ScRange aRef;
977  ScAddress aErrorPos;
978  bool bHasError = false;
979  while ( aIter.GetNextRef( aRef ) )
980  {
981  if (HasError( aRef, aErrorPos ))
982  {
983  bHasError = true;
984  if (DrawEntry( nCol, nRow, ScRange( aErrorPos), rData ))
985  nResult = DET_INS_INSERTED;
986 
987  if ( nLevel < rData.GetMaxLevel() ) // hits most of the time
988  {
989  if (InsertErrorLevel( aErrorPos.Col(), aErrorPos.Row(),
990  rData, nLevel+1 ) == DET_INS_INSERTED)
991  nResult = DET_INS_INSERTED;
992  }
993  }
994  }
995 
996  pFCell->SetRunning(false);
997 
998  // leaves ?
999  if (!bHasError)
1000  if (InsertPredLevel( nCol, nRow, rData, rData.GetMaxLevel() ) == DET_INS_INSERTED)
1001  nResult = DET_INS_INSERTED;
1002 
1003  return nResult;
1004 }
1005 
1006 sal_uInt16 ScDetectiveFunc::InsertSuccLevel( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1007  ScDetectiveData& rData, sal_uInt16 nLevel )
1008 {
1009  // over the entire document.
1010 
1011  sal_uInt16 nResult = DET_INS_EMPTY;
1012  ScCellIterator aCellIter(rDoc, ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB)); // all sheets
1013  for (bool bHas = aCellIter.first(); bHas; bHas = aCellIter.next())
1014  {
1015  if (aCellIter.getType() != CELLTYPE_FORMULA)
1016  continue;
1017 
1018  ScFormulaCell* pFCell = aCellIter.getFormulaCell();
1019  bool bRunning = pFCell->IsRunning();
1020 
1021  if (pFCell->GetDirty())
1022  pFCell->Interpret(); // can't be called after SetRunning
1023  pFCell->SetRunning(true);
1024 
1025  ScDetectiveRefIter aIter(rDoc, pFCell);
1026  ScRange aRef;
1027  while ( aIter.GetNextRef( aRef) )
1028  {
1029  if (aRef.aStart.Tab() <= nTab && aRef.aEnd.Tab() >= nTab)
1030  {
1031  if (Intersect( nCol1,nRow1,nCol2,nRow2,
1032  aRef.aStart.Col(),aRef.aStart.Row(),
1033  aRef.aEnd.Col(),aRef.aEnd.Row() ))
1034  {
1035  bool bAlien = ( aCellIter.GetPos().Tab() != nTab );
1036  bool bDrawRet;
1037  if (bAlien)
1038  bDrawRet = DrawAlienEntry( aRef, rData );
1039  else
1040  bDrawRet = DrawEntry( aCellIter.GetPos().Col(), aCellIter.GetPos().Row(),
1041  aRef, rData );
1042  if (bDrawRet)
1043  {
1044  nResult = DET_INS_INSERTED; // insert new arrow
1045  }
1046  else
1047  {
1048  if (bRunning)
1049  {
1050  if (nResult == DET_INS_EMPTY)
1051  nResult = DET_INS_CIRCULAR;
1052  }
1053  else
1054  {
1055 
1056  if ( nLevel < rData.GetMaxLevel() )
1057  {
1058  sal_uInt16 nSubResult = InsertSuccLevel(
1059  aCellIter.GetPos().Col(), aCellIter.GetPos().Row(),
1060  aCellIter.GetPos().Col(), aCellIter.GetPos().Row(),
1061  rData, nLevel+1 );
1062  switch (nSubResult)
1063  {
1064  case DET_INS_INSERTED:
1065  nResult = DET_INS_INSERTED;
1066  break;
1067  case DET_INS_CONTINUE:
1068  if (nResult != DET_INS_INSERTED)
1069  nResult = DET_INS_CONTINUE;
1070  break;
1071  case DET_INS_CIRCULAR:
1072  if (nResult == DET_INS_EMPTY)
1073  nResult = DET_INS_CIRCULAR;
1074  break;
1075  // DET_INS_EMPTY: leave unchanged
1076  }
1077  }
1078  else // nMaxLevel reached
1079  if (nResult != DET_INS_INSERTED)
1080  nResult = DET_INS_CONTINUE;
1081  }
1082  }
1083  }
1084  }
1085  }
1086  pFCell->SetRunning(bRunning);
1087  }
1088 
1089  return nResult;
1090 }
1091 
1092 sal_uInt16 ScDetectiveFunc::FindSuccLevel( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1093  sal_uInt16 nLevel, sal_uInt16 nDeleteLevel )
1094 {
1095  OSL_ENSURE( nLevel<1000, "Level" );
1096 
1097  sal_uInt16 nResult = nLevel;
1098  bool bDelete = ( nDeleteLevel && nLevel == nDeleteLevel-1 );
1099 
1100  ScCellIterator aCellIter( rDoc, ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab) );
1101  for (bool bHas = aCellIter.first(); bHas; bHas = aCellIter.next())
1102  {
1103  if (aCellIter.getType() != CELLTYPE_FORMULA)
1104  continue;
1105 
1106  ScFormulaCell* pFCell = aCellIter.getFormulaCell();
1107  bool bRunning = pFCell->IsRunning();
1108 
1109  if (pFCell->GetDirty())
1110  pFCell->Interpret(); // can't be called after SetRunning
1111  pFCell->SetRunning(true);
1112 
1113  ScDetectiveRefIter aIter(rDoc, pFCell);
1114  ScRange aRef;
1115  while ( aIter.GetNextRef( aRef) )
1116  {
1117  if (aRef.aStart.Tab() <= nTab && aRef.aEnd.Tab() >= nTab)
1118  {
1119  if (Intersect( nCol1,nRow1,nCol2,nRow2,
1120  aRef.aStart.Col(),aRef.aStart.Row(),
1121  aRef.aEnd.Col(),aRef.aEnd.Row() ))
1122  {
1123  if ( bDelete ) // arrows, that are starting here
1124  {
1125  if (aRef.aStart != aRef.aEnd)
1126  {
1127  DeleteBox( aRef.aStart.Col(), aRef.aStart.Row(),
1128  aRef.aEnd.Col(), aRef.aEnd.Row() );
1129  }
1130  DeleteArrowsAt( aRef.aStart.Col(), aRef.aStart.Row(), false );
1131  }
1132  else if ( !bRunning &&
1133  HasArrow( aRef.aStart,
1134  aCellIter.GetPos().Col(),aCellIter.GetPos().Row(),aCellIter.GetPos().Tab() ) )
1135  {
1136  sal_uInt16 nTemp = FindSuccLevel( aCellIter.GetPos().Col(), aCellIter.GetPos().Row(),
1137  aCellIter.GetPos().Col(), aCellIter.GetPos().Row(),
1138  nLevel+1, nDeleteLevel );
1139  if (nTemp > nResult)
1140  nResult = nTemp;
1141  }
1142  }
1143  }
1144  }
1145 
1146  pFCell->SetRunning(bRunning);
1147  }
1148 
1149  return nResult;
1150 }
1151 
1153 {
1154  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1155  if (!pModel)
1156  return false;
1157 
1158  ScDetectiveData aData( pModel );
1159 
1160  sal_uInt16 nMaxLevel = 0;
1161  sal_uInt16 nResult = DET_INS_CONTINUE;
1162  while (nResult == DET_INS_CONTINUE && nMaxLevel < 1000)
1163  {
1164  aData.SetMaxLevel( nMaxLevel );
1165  nResult = InsertPredLevel( nCol, nRow, aData, 0 );
1166  ++nMaxLevel;
1167  }
1168 
1169  return ( nResult == DET_INS_INSERTED );
1170 }
1171 
1173 {
1174  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1175  if (!pModel)
1176  return false;
1177 
1178  ScDetectiveData aData( pModel );
1179 
1180  sal_uInt16 nMaxLevel = 0;
1181  sal_uInt16 nResult = DET_INS_CONTINUE;
1182  while (nResult == DET_INS_CONTINUE && nMaxLevel < 1000)
1183  {
1184  aData.SetMaxLevel( nMaxLevel );
1185  nResult = InsertSuccLevel( nCol, nRow, nCol, nRow, aData, 0 );
1186  ++nMaxLevel;
1187  }
1188 
1189  return ( nResult == DET_INS_INSERTED );
1190 }
1191 
1193 {
1194  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1195  if (!pModel)
1196  return false;
1197 
1198  ScRange aRange( nCol, nRow, nTab );
1199  ScAddress aErrPos;
1200  if ( !HasError( aRange,aErrPos ) )
1201  return false;
1202 
1203  ScDetectiveData aData( pModel );
1204 
1205  aData.SetMaxLevel( 1000 );
1206  sal_uInt16 nResult = InsertErrorLevel( nCol, nRow, aData, 0 );
1207 
1208  return ( nResult == DET_INS_INSERTED );
1209 }
1210 
1212 {
1213  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1214  if (!pModel)
1215  return false;
1216 
1217  sal_uInt16 nLevelCount = FindSuccLevel( nCol, nRow, nCol, nRow, 0, 0 );
1218  if ( nLevelCount )
1219  FindSuccLevel( nCol, nRow, nCol, nRow, 0, nLevelCount ); // delete
1220 
1221  return ( nLevelCount != 0 );
1222 }
1223 
1225 {
1226  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1227  if (!pModel)
1228  return false;
1229 
1230  sal_uInt16 nLevelCount = FindPredLevel( nCol, nRow, 0, 0 );
1231  if ( nLevelCount )
1232  FindPredLevel( nCol, nRow, 0, nLevelCount ); // delete
1233 
1234  return ( nLevelCount != 0 );
1235 }
1236 
1238 {
1239  tools::Rectangle aRect = ScDrawLayer::GetCellRect(rDoc, ScAddress(nCol, nRow, nTab), true);
1240  aRect.AdjustLeft(-250);
1241  aRect.AdjustRight(250);
1242  aRect.AdjustTop(-70);
1243  aRect.AdjustBottom(70);
1244 
1245  Point aStartCorner = aRect.TopLeft();
1246  Point aEndCorner = aRect.BottomRight();
1247 
1248  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1249  if (!pModel)
1250  return false;
1251 
1252  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
1253  OSL_ENSURE(pPage, "Page ?");
1254 
1255  pPage->RecalcObjOrdNums();
1256 
1257  const size_t nObjCount = pPage->GetObjCount();
1258  size_t nDelCount = 0;
1259  if (nObjCount)
1260  {
1261  std::unique_ptr<SdrObject*[]> ppObj(new SdrObject*[nObjCount]);
1262 
1263  SdrObjListIter aIter(pPage, SdrIterMode::Flat);
1264  SdrObject* pObject = aIter.Next();
1265  while (pObject)
1266  {
1267  if (pObject->GetLayer() == SC_LAYER_INTERN)
1268  if (auto pSdrCircObj = dynamic_cast<const SdrCircObj*>(pObject) )
1269  {
1270  tools::Rectangle aObjRect = pSdrCircObj->GetLogicRect();
1271  if (RectIsPoints(aObjRect, aStartCorner, aEndCorner))
1272  ppObj[nDelCount++] = pObject;
1273  }
1274 
1275  pObject = aIter.Next();
1276  }
1277 
1278  for (size_t i = 1; i <= nDelCount; ++i)
1279  pModel->AddCalcUndo(std::make_unique<SdrUndoRemoveObj>(*ppObj[nDelCount - i]));
1280 
1281  for (size_t i = 1; i <= nDelCount; ++i)
1282  pPage->RemoveObject(ppObj[nDelCount - i]->GetOrdNum());
1283 
1284  ppObj.reset();
1285 
1286  Modified();
1287  }
1288 
1289  return (nDelCount != 0);
1290 }
1291 
1293 {
1294  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1295  if (!pModel)
1296  return false;
1297 
1298  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
1299  OSL_ENSURE(pPage,"Page ?");
1300 
1301  pPage->RecalcObjOrdNums();
1302 
1303  size_t nDelCount = 0;
1304  const size_t nObjCount = pPage->GetObjCount();
1305  if (nObjCount)
1306  {
1307  std::unique_ptr<SdrObject*[]> ppObj(new SdrObject*[nObjCount]);
1308 
1309  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
1310  SdrObject* pObject = aIter.Next();
1311  while (pObject)
1312  {
1313  if ( pObject->GetLayer() == SC_LAYER_INTERN )
1314  {
1315  bool bDoThis = true;
1316  bool bCircle = ( dynamic_cast<const SdrCircObj*>( pObject) != nullptr );
1317  bool bCaption = ScDrawLayer::IsNoteCaption( pObject );
1318  if ( eWhat == ScDetectiveDelete::Detective ) // detective, from menu
1319  bDoThis = !bCaption; // also circles
1320  else if ( eWhat == ScDetectiveDelete::Circles ) // circles, if new created
1321  bDoThis = bCircle;
1322  else if ( eWhat == ScDetectiveDelete::Arrows ) // DetectiveRefresh
1323  bDoThis = !bCaption && !bCircle; // don't include circles
1324  else
1325  {
1326  OSL_FAIL("what?");
1327  }
1328  if ( bDoThis )
1329  ppObj[nDelCount++] = pObject;
1330  }
1331 
1332  pObject = aIter.Next();
1333  }
1334 
1335  for (size_t i=1; i<=nDelCount; ++i)
1336  pModel->AddCalcUndo( std::make_unique<SdrUndoRemoveObj>( *ppObj[nDelCount-i] ) );
1337 
1338  for (size_t i=1; i<=nDelCount; ++i)
1339  pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
1340 
1341  ppObj.reset();
1342 
1343  Modified();
1344  }
1345 
1346  return ( nDelCount != 0 );
1347 }
1348 
1349 bool ScDetectiveFunc::MarkInvalid(bool& rOverflow)
1350 {
1351  rOverflow = false;
1352  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1353  if (!pModel)
1354  return false;
1355 
1356  bool bDeleted = DeleteAll( ScDetectiveDelete::Circles ); // just circles
1357 
1358  ScDetectiveData aData( pModel );
1359  tools::Long nInsCount = 0;
1360 
1361  // search for valid places
1362  ScDocAttrIterator aAttrIter( rDoc, nTab, 0,0,rDoc.MaxCol(),rDoc.MaxRow() );
1363  SCCOL nCol;
1364  SCROW nRow1;
1365  SCROW nRow2;
1366  const ScPatternAttr* pPattern = aAttrIter.GetNext( nCol, nRow1, nRow2 );
1367  while ( pPattern && nInsCount < SC_DET_MAXCIRCLE )
1368  {
1369  sal_uLong nIndex = pPattern->GetItem(ATTR_VALIDDATA).GetValue();
1370  if (nIndex)
1371  {
1372  const ScValidationData* pData = rDoc.GetValidationEntry( nIndex );
1373  if ( pData )
1374  {
1375  // pass cells in this area
1376 
1377  bool bMarkEmpty = !pData->IsIgnoreBlank();
1378  SCROW nNextRow = nRow1;
1379  SCROW nRow;
1380  ScCellIterator aCellIter( rDoc, ScRange(nCol, nRow1, nTab, nCol, nRow2, nTab) );
1381  for (bool bHas = aCellIter.first(); bHas && nInsCount < SC_DET_MAXCIRCLE; bHas = aCellIter.next())
1382  {
1383  SCROW nCellRow = aCellIter.GetPos().Row();
1384  if ( bMarkEmpty )
1385  for ( nRow = nNextRow; nRow < nCellRow && nInsCount < SC_DET_MAXCIRCLE; nRow++ )
1386  {
1387  if(!pPattern->GetItem(ATTR_MERGE_FLAG).IsOverlapped())
1388  DrawCircle( nCol, nRow, aData );
1389  ++nInsCount;
1390  }
1391  ScRefCellValue aCell = aCellIter.getRefCellValue();
1392  if (!pData->IsDataValid(aCell, aCellIter.GetPos()))
1393  {
1394  if(!pPattern->GetItem(ATTR_MERGE_FLAG).IsOverlapped())
1395  DrawCircle( nCol, nCellRow, aData );
1396  ++nInsCount;
1397  }
1398  nNextRow = nCellRow + 1;
1399  }
1400  if ( bMarkEmpty )
1401  for ( nRow = nNextRow; nRow <= nRow2 && nInsCount < SC_DET_MAXCIRCLE; nRow++ )
1402  {
1403  if(!pPattern->GetItem(ATTR_MERGE_FLAG).IsOverlapped())
1404  DrawCircle(nCol, nRow, aData);
1405  ++nInsCount;
1406  }
1407  }
1408  }
1409 
1410  pPattern = aAttrIter.GetNext( nCol, nRow1, nRow2 );
1411  }
1412 
1413  if ( nInsCount >= SC_DET_MAXCIRCLE )
1414  rOverflow = true;
1415 
1416  return ( bDeleted || nInsCount != 0 );
1417 }
1418 
1419 void ScDetectiveFunc::GetAllPreds(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1420  vector<ScTokenRef>& rRefTokens)
1421 {
1422  ScCellIterator aIter(rDoc, ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab));
1423  for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
1424  {
1425  if (aIter.getType() != CELLTYPE_FORMULA)
1426  continue;
1427 
1428  ScFormulaCell* pFCell = aIter.getFormulaCell();
1429  ScDetectiveRefIter aRefIter(rDoc, pFCell);
1430  for (formula::FormulaToken* p = aRefIter.GetNextRefToken(); p; p = aRefIter.GetNextRefToken())
1431  {
1432  ScTokenRef pRef(p->Clone());
1433  ScRefTokenHelper::join(&rDoc, rRefTokens, pRef, aIter.GetPos());
1434  }
1435  }
1436 }
1437 
1438 void ScDetectiveFunc::GetAllSuccs(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1439  vector<ScTokenRef>& rRefTokens)
1440 {
1441  vector<ScTokenRef> aSrcRange;
1442  aSrcRange.push_back(
1443  ScRefTokenHelper::createRefToken(rDoc, ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab)));
1444 
1445  ScCellIterator aIter(rDoc, ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab));
1446  for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
1447  {
1448  if (aIter.getType() != CELLTYPE_FORMULA)
1449  continue;
1450 
1451  ScFormulaCell* pFCell = aIter.getFormulaCell();
1452  ScDetectiveRefIter aRefIter(rDoc, pFCell);
1453  for (formula::FormulaToken* p = aRefIter.GetNextRefToken(); p; p = aRefIter.GetNextRefToken())
1454  {
1455  const ScAddress& aPos = aIter.GetPos();
1456  ScTokenRef pRef(p->Clone());
1457  if (ScRefTokenHelper::intersects(&rDoc, aSrcRange, pRef, aPos))
1458  {
1459  // This address is absolute.
1460  pRef = ScRefTokenHelper::createRefToken(rDoc, aPos);
1461  ScRefTokenHelper::join(&rDoc, rRefTokens, pRef, ScAddress());
1462  }
1463  }
1464  }
1465 }
1466 
1468 {
1469  // for all caption objects, update attributes and SpecialTextBoxShadow flag
1470  // (on all tables - nTab is ignored!)
1471 
1472  // no undo actions, this is refreshed after undo
1473 
1474  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1475  if (!pModel)
1476  return;
1477 
1478  for( SCTAB nObjTab = 0, nTabCount = rDoc.GetTableCount(); nObjTab < nTabCount; ++nObjTab )
1479  {
1480  SdrPage* pPage = pModel->GetPage( static_cast< sal_uInt16 >( nObjTab ) );
1481  OSL_ENSURE( pPage, "Page ?" );
1482  if( pPage )
1483  {
1484  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
1485  for( SdrObject* pObject = aIter.Next(); pObject; pObject = aIter.Next() )
1486  {
1488  {
1489  ScPostIt* pNote = rDoc.GetNote( pData->maStart );
1490  // caption should exist, we iterate over drawing objects...
1491  OSL_ENSURE( pNote && (pNote->GetCaption() == pObject), "ScDetectiveFunc::UpdateAllComments - invalid cell note" );
1492  if( pNote )
1493  {
1494  ScCommentData aData( rDoc, pModel );
1495  SfxItemSet aAttrColorSet = pObject->GetMergedItemSet();
1496  aAttrColorSet.Put( XFillColorItem( OUString(), GetCommentColor() ) );
1497  aData.UpdateCaptionSet( aAttrColorSet );
1498  pObject->SetMergedItemSetAndBroadcast( aData.GetCaptionSet() );
1499  if( SdrCaptionObj* pCaption = dynamic_cast< SdrCaptionObj* >( pObject ) )
1500  {
1501  pCaption->SetSpecialTextBoxShadow();
1502  pCaption->SetFixedTail();
1503  }
1504  }
1505  }
1506  }
1507  }
1508  }
1509 }
1510 
1512 {
1513  // no undo actions necessary
1514 
1515  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1516  if (!pModel)
1517  return;
1518 
1519  for( SCTAB nObjTab = 0, nTabCount = rDoc.GetTableCount(); nObjTab < nTabCount; ++nObjTab )
1520  {
1521  SdrPage* pPage = pModel->GetPage( static_cast< sal_uInt16 >( nObjTab ) );
1522  OSL_ENSURE( pPage, "Page ?" );
1523  if( pPage )
1524  {
1525  SdrObjListIter aIter( pPage, SdrIterMode::Flat );
1526  for( SdrObject* pObject = aIter.Next(); pObject; pObject = aIter.Next() )
1527  {
1528  if ( pObject->GetLayer() == SC_LAYER_INTERN )
1529  {
1530  bool bArrow = false;
1531  bool bError = false;
1532 
1533  ScAddress aPos;
1534  ScRange aSource;
1535  bool bDummy;
1536  ScDetectiveObjType eType = GetDetectiveObjectType( pObject, nObjTab, aPos, aSource, bDummy );
1537  if ( eType == SC_DETOBJ_ARROW || eType == SC_DETOBJ_TOOTHERTAB )
1538  {
1539  // source is valid, determine error flag from source range
1540 
1541  ScAddress aErrPos;
1542  if ( HasError( aSource, aErrPos ) )
1543  bError = true;
1544  else
1545  bArrow = true;
1546  }
1547  else if ( eType == SC_DETOBJ_FROMOTHERTAB )
1548  {
1549  // source range is no longer known, take error flag from formula itself
1550  // (this means, if the formula has an error, all references to other tables
1551  // are marked red)
1552 
1553  ScAddress aErrPos;
1554  if ( HasError( ScRange( aPos), aErrPos ) )
1555  bError = true;
1556  else
1557  bArrow = true;
1558  }
1559  else if ( eType == SC_DETOBJ_CIRCLE )
1560  {
1561  // circles (error marks) are always red
1562 
1563  bError = true;
1564  }
1565  else if ( eType == SC_DETOBJ_NONE )
1566  {
1567  // frame for area reference has no ObjType, always gets arrow color
1568 
1569  if ( dynamic_cast<const SdrRectObj*>( pObject) != nullptr && dynamic_cast<const SdrCaptionObj*>( pObject) == nullptr )
1570  {
1571  bArrow = true;
1572  }
1573  }
1574 
1575  if ( bArrow || bError )
1576  {
1577  Color nColor = ( bError ? GetErrorColor() : GetArrowColor() );
1578  pObject->SetMergedItem( XLineColorItem( OUString(), nColor ) );
1579 
1580  // repaint only
1581  pObject->ActionChanged();
1582  }
1583  }
1584  }
1585  }
1586  }
1587 }
1588 
1590 {
1591  // find the rectangle for an arrow (always the object directly before the arrow)
1592  // rRange must be initialized to the source cell of the arrow (start of area)
1593 
1594  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1595  if (!pModel) return;
1596 
1597  SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
1598  OSL_ENSURE(pPage,"Page ?");
1599  if (!pPage) return;
1600 
1601  // test if the object is a direct page member
1602  if( !(pObject && pObject->getSdrPageFromSdrObject() && (pObject->getSdrPageFromSdrObject() == pObject->getParentSdrObjListFromSdrObject()->getSdrPageFromSdrObjList())) )
1603  return;
1604 
1605  // Is there a previous object?
1606  const size_t nOrdNum = pObject->GetOrdNum();
1607 
1608  if(nOrdNum <= 0)
1609  return;
1610 
1611  SdrObject* pPrevObj = pPage->GetObj(nOrdNum - 1);
1612 
1613  if ( pPrevObj && pPrevObj->GetLayer() == SC_LAYER_INTERN && dynamic_cast<const SdrRectObj*>( pPrevObj) != nullptr )
1614  {
1615  ScDrawObjData* pPrevData = ScDrawLayer::GetObjDataTab( pPrevObj, rRange.aStart.Tab() );
1616  if ( pPrevData && pPrevData->maStart.IsValid() && pPrevData->maEnd.IsValid() && (pPrevData->maStart == rRange.aStart) )
1617  {
1618  rRange.aEnd = pPrevData->maEnd;
1619  return;
1620  }
1621  }
1622 }
1623 
1625  ScAddress& rPosition, ScRange& rSource, bool& rRedLine )
1626 {
1627  rRedLine = false;
1629 
1630  if ( pObject && pObject->GetLayer() == SC_LAYER_INTERN )
1631  {
1632  if ( ScDrawObjData* pData = ScDrawLayer::GetObjDataTab( pObject, nObjTab ) )
1633  {
1634  bool bValidStart = pData->maStart.IsValid();
1635  bool bValidEnd = pData->maEnd.IsValid();
1636 
1637  if ( pObject->IsPolyObj() && pObject->GetPointCount() == 2 )
1638  {
1639  // line object -> arrow
1640 
1641  if ( bValidStart )
1642  eType = bValidEnd ? SC_DETOBJ_ARROW : SC_DETOBJ_TOOTHERTAB;
1643  else if ( bValidEnd )
1644  eType = SC_DETOBJ_FROMOTHERTAB;
1645 
1646  if ( bValidStart )
1647  rSource = pData->maStart;
1648  if ( bValidEnd )
1649  rPosition = pData->maEnd;
1650 
1651  if ( bValidStart && lcl_HasThickLine( *pObject ) )
1652  {
1653  // thick line -> look for frame before this object
1654 
1655  FindFrameForObject( pObject, rSource ); // modifies rSource
1656  }
1657 
1658  Color nObjColor = pObject->GetMergedItem(XATTR_LINECOLOR).GetColorValue();
1659  if ( nObjColor == GetErrorColor() && nObjColor != GetArrowColor() )
1660  rRedLine = true;
1661  }
1662  else if (dynamic_cast<const SdrCircObj*>(pObject) != nullptr)
1663  {
1664  if (bValidStart)
1665  {
1666  // cell position is returned in rPosition
1667  rPosition = pData->maStart;
1668  eType = SC_DETOBJ_CIRCLE;
1669  }
1670  }
1671  else if (dynamic_cast<const SdrRectObj*>(pObject) != nullptr)
1672  {
1673  if (bValidStart)
1674  {
1675  // cell position is returned in rPosition
1676  rPosition = pData->maStart;
1677  eType = SC_DETOBJ_RECTANGLE;
1678  }
1679  }
1680  }
1681  }
1682 
1683  return eType;
1684 }
1685 
1687  const ScAddress& rPosition, const ScRange& rSource,
1688  bool bRedLine )
1689 {
1690  ScDrawLayer* pModel = rDoc.GetDrawLayer();
1691  if (!pModel) return;
1692  ScDetectiveData aData( pModel );
1693 
1694  switch (eType)
1695  {
1696  case SC_DETOBJ_ARROW:
1698  InsertArrow( rPosition.Col(), rPosition.Row(),
1699  rSource.aStart.Col(), rSource.aStart.Row(),
1700  rSource.aEnd.Col(), rSource.aEnd.Row(),
1701  (eType == SC_DETOBJ_FROMOTHERTAB), bRedLine, aData );
1702  break;
1703  case SC_DETOBJ_TOOTHERTAB:
1704  InsertToOtherTab( rSource.aStart.Col(), rSource.aStart.Row(),
1705  rSource.aEnd.Col(), rSource.aEnd.Row(),
1706  bRedLine, aData );
1707  break;
1708  case SC_DETOBJ_CIRCLE:
1709  DrawCircle( rPosition.Col(), rPosition.Row(), aData );
1710  break;
1711  default:
1712  {
1713  // added to avoid warnings
1714  }
1715  }
1716 }
1717 
1719 {
1720  if (!bColorsInitialized)
1721  InitializeColors();
1722  return nArrowColor;
1723 }
1724 
1726 {
1727  if (!bColorsInitialized)
1728  InitializeColors();
1729  return nErrorColor;
1730 }
1731 
1733 {
1734  if (!bColorsInitialized)
1735  InitializeColors();
1736  return nCommentColor;
1737 }
1738 
1740 {
1741  // may be called several times to update colors from configuration
1742 
1743  const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
1747 
1748  bColorsInitialized = true;
1749 }
1750 
1752 {
1753  return bColorsInitialized;
1754 }
1755 
1757 {
1758  rDisplay += "\n--------\n";
1759 }
1760 
1761 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
tools::Rectangle GetDrawRect(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: detfunc.cxx:342
bool ShowPred(SCCOL nCol, SCROW nRow)
Definition: detfunc.cxx:1152
static Color nArrowColor
Definition: detfunc.hxx:50
void DeleteBox(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: detfunc.cxx:733
SdrMetricItem makeSdrTextUpperDistItem(tools::Long mnHeight)
bool IsDataValid(const OUString &rTest, const ScPatternAttr &rPattern, const ScAddress &rPos) const
Definition: validat.cxx:527
void FindFrameForObject(const SdrObject *pObject, ScRange &rRange)
Definition: detfunc.cxx:1589
SfxItemSet aFromTabSet
Definition: detfunc.cxx:96
SCCOL SanitizeCol(SCCOL nCol) const
Definition: document.hxx:880
SdrMetricItem makeSdrShadowYDistItem(tools::Long nDist)
ScDetectiveData(SdrModel *pModel)
Definition: detfunc.cxx:141
sal_Int32 nIndex
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
ScAddress aStart
Definition: address.hxx:499
SfxItemSet & GetBoxSet()
Definition: detfunc.cxx:103
constexpr TypedWhichId< XLineEndItem > XATTR_LINEEND(XATTR_LINE_FIRST+5)
constexpr TypedWhichId< ScPatternAttr > ATTR_PATTERN(156)
#define EMPTY_OUSTRING
Definition: global.hxx:214
constexpr TypedWhichId< XLineStartItem > XATTR_LINESTART(XATTR_LINE_FIRST+4)
bool ShowSucc(SCCOL nCol, SCROW nRow)
Definition: detfunc.cxx:1172
SC_DLLPUBLIC bool IsNegativePage(SCTAB nTab) const
Definition: document.cxx:994
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
constexpr sal_uInt16 SDRATTR_END(SDRATTR_TEXTCOLUMNS_LAST)
SCROW Row() const
Definition: address.hxx:261
SfxItemSet & GetFromTabSet()
Definition: detfunc.cxx:106
DetInsertResult
Definition: detfunc.cxx:82
std::unique_ptr< ContentProperties > pData
sal_uInt16 InsertPredLevelArea(const ScRange &rRef, ScDetectiveData &rData, sal_uInt16 nLevel)
Definition: detfunc.cxx:780
#define SC_DET_MAXCIRCLE
Definition: detfunc.hxx:34
virtual bool IsPolyObj() const
constexpr tools::Long Left() const
sal_uInt16 FindPredLevel(SCCOL nCol, SCROW nRow, sal_uInt16 nLevel, sal_uInt16 nDeleteLevel)
Definition: detfunc.cxx:900
bool Contains(const Point &rPOINT) const
bool GetDirty() const
sal_uIntPtr sal_uLong
long Long
OBJ_LINE
static ScDrawObjData * GetObjData(SdrObject *pObj, bool bCreate=false)
Definition: drwlayer.cxx:2595
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
constexpr TypedWhichId< XLineWidthItem > XATTR_LINEWIDTH(XATTR_LINE_FIRST+2)
SdrObject * GetObj(size_t nNum) const
static bool IsNonAlienArrow(const SdrObject *pObject)
Definition: detfunc.cxx:426
void RecalcObjOrdNums()
CALCNOTESBACKGROUND
sal_uInt16 InsertErrorLevel(SCCOL nCol, SCROW nRow, ScDetectiveData &rData, sal_uInt16 nLevel)
Definition: detfunc.cxx:958
size_t GetObjCount() const
constexpr sal_uInt16 EE_ITEMS_END(EE_FEATURE_END)
static Color GetErrorColor()
Definition: detfunc.cxx:1725
void SC_DLLPUBLIC join(const ScDocument *pDoc,::std::vector< ScTokenRef > &rTokens, const ScTokenRef &pToken, const ScAddress &rPos)
void InsertObject(ScDetectiveObjType eType, const ScAddress &rPosition, const ScRange &rSource, bool bRedLine)
Definition: detfunc.cxx:1686
ScAddress aEnd
Definition: address.hxx:500
static tools::Rectangle GetCellRect(const ScDocument &rDoc, const ScAddress &rPos, bool bMergedCell)
Returns the rectangle for the passed cell address in 1/100 mm.
Definition: drwlayer.cxx:2098
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
SfxItemSet aArrowSet
Definition: detfunc.cxx:94
void UpdateAllArrowColors()
on all tables
Definition: detfunc.cxx:1511
SdrMetricItem makeSdrTextRightDistItem(tools::Long mnHeight)
void GetAllPreds(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,::std::vector< ScTokenRef > &rRefTokens)
Definition: detfunc.cxx:1419
static bool lcl_IsOtherTab(const basegfx::B2DPolyPolygon &rPolyPolygon)
Definition: detfunc.cxx:356
SdrMetricItem makeSdrTextLowerDistItem(tools::Long mnHeight)
virtual sal_uInt32 GetPointCount() const
static void Free(SdrObject *&_rpObject)
virtual void InsertObject(SdrObject *pObj, size_t nPos=SAL_MAX_SIZE)
CALCDETECTIVEERROR
EmbeddedObjectRef * pObject
ScAddress maStart
Definition: userdat.hxx:36
ScFormulaCell * getFormulaCell()
Definition: dociter.hxx:238
constexpr sal_uInt16 SDRATTR_START(XATTR_START)
SC_DLLPUBLIC sal_uInt16 GetRowHeight(SCROW nRow, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4192
SdrOnOffItem makeSdrTextAutoGrowHeightItem(bool bAuto)
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6087
CellType getType() const
Definition: dociter.hxx:235
SC_DLLPUBLIC const ScValidationData * GetValidationEntry(sal_uLong nIndex) const
Definition: documen4.cxx:882
SfxItemSet & GetToTabSet()
Definition: detfunc.cxx:105
bool ShowError(SCCOL nCol, SCROW nRow)
Definition: detfunc.cxx:1192
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
SC_DLLPUBLIC ScPostIt * GetNote(const ScAddress &rPos)
Notes.
Definition: document.cxx:6534
Point GetDrawPos(SCCOL nCol, SCROW nRow, DrawPosMode eMode) const
Definition: detfunc.cxx:307
static bool lcl_HasThickLine(const SdrObject &rObj)
Definition: detfunc.cxx:134
static Color nErrorColor
Definition: detfunc.hxx:51
SdrPage * getSdrPageFromSdrObject() const
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:872
static Color GetArrowColor()
Definition: detfunc.cxx:1718
sal_uInt16 InsertSuccLevel(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScDetectiveData &rData, sal_uInt16 nLevel)
Definition: detfunc.cxx:1006
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:314
Additional class containing cell annotation data.
Definition: postit.hxx:161
FormulaError GetErrCode()
Top-left edge of the cell.
bool DeletePred(SCCOL nCol, SCROW nRow)
Definition: detfunc.cxx:1224
const ScRefCellValue & getRefCellValue() const
Definition: dociter.hxx:241
void Modified()
Definition: detfunc.cxx:276
ScTokenRef createRefToken(const ScDocument &rDoc, const ScAddress &rAddr)
bool DrawEntry(SCCOL nCol, SCROW nRow, const ScRange &rRef, ScDetectiveData &rData)
DrawEntry / DrawAlienEntry check for existing arrows and errors.
Definition: detfunc.cxx:599
Walk through all cells in an area.
Definition: dociter.hxx:207
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:110
SCTAB Tab() const
Definition: address.hxx:270
SdrOnOffItem makeSdrTextAutoGrowWidthItem(bool bAuto)
void SetMaxLevel(sal_uInt16 nVal)
Definition: detfunc.cxx:109
sal_uInt16 nMaxLevel
Definition: detfunc.cxx:98
constexpr TypedWhichId< SdrOnOffItem > SDRATTR_SHADOW(SDRATTR_SHADOW_FIRST+0)
sal_uInt16 FindSuccLevel(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nLevel, sal_uInt16 nDeleteLevel)
Definition: detfunc.cxx:1092
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:70
constexpr OUStringLiteral aData
static bool IsColorsInitialized()
Definition: detfunc.cxx:1751
DocumentType eType
bool IsValid() const
Definition: address.hxx:292
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALIDDATA(153)
void DrawCircle(SCCOL nCol, SCROW nRow, ScDetectiveData &rData)
Definition: detfunc.cxx:632
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1058
virtual void SetLayer(SdrLayerID nLayer)
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:871
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
int i
Bottom-right edge of the cell.
ScDetectiveObjType
Definition: detfunc.hxx:38
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:405
sal_Int16 SCCOL
Definition: types.hxx:21
static ScDrawObjData * GetNoteCaptionData(SdrObject *pObj, SCTAB nTab)
Returns the object data, if the passed object is a cell note caption.
Definition: drwlayer.cxx:2628
Iterator for references in a formula cell.
Definition: formulaiter.hxx:31
static bool bColorsInitialized
Definition: detfunc.hxx:53
#define SC_MOD()
Definition: scmod.hxx:250
SfxItemSet aToTabSet
Definition: detfunc.cxx:95
bool MarkInvalid(bool &rOverflow)
Definition: detfunc.cxx:1349
static Color nCommentColor
Definition: detfunc.hxx:52
const SdrPage * GetPage(sal_uInt16 nPgNum) const
bool Interpret(SCROW nStartOffset=-1, SCROW nEndOffset=-1)
constexpr tools::Long Right() const
constexpr sal_uInt16 EE_ITEMS_START(OWN_ATTR_VALUE_END+1)
void SetMergedItemSetAndBroadcast(const SfxItemSet &rSet, bool bClearAllItems=false)
static void UpdateAllComments(ScDocument &rDoc)
on all tables
Definition: detfunc.cxx:1467
sal_uInt32 GetOrdNum() const
constexpr TypedWhichId< SdrMetricItem > SDRATTR_SHADOWYDIST(SDRATTR_SHADOW_FIRST+3)
constexpr tools::Long Top() const
void AddCalcUndo(std::unique_ptr< SdrUndoAction > pUndo)
Definition: drwlayer.cxx:1406
SfxItemSet aBoxSet
Definition: detfunc.cxx:93
bool IsRunning() const
const SfxPoolItem & GetMergedItem(const sal_uInt16 nWhich) const
const SCTAB MAXTAB
Definition: address.hxx:70
const SfxPoolItem & GetDefaultItem(sal_uInt16 nWhich) const
sal_uInt16 InsertPredLevel(SCCOL nCol, SCROW nRow, ScDetectiveData &rData, sal_uInt16 nLevel)
Definition: detfunc.cxx:813
sal_uInt16 GetMaxLevel() const
Definition: detfunc.cxx:110
static bool RectIsPoints(const tools::Rectangle &rRect, const Point &rStart, const Point &rEnd)
Definition: detfunc.cxx:719
virtual SdrObject * RemoveObject(size_t nObjNum)
sal_uInt16 FindPredLevelArea(const ScRange &rRef, sal_uInt16 nLevel, sal_uInt16 nDeleteLevel)
Definition: detfunc.cxx:879
FormulaError
SCCOL Col() const
Definition: address.hxx:266
bool DeleteCirclesAt(SCCOL nCol, SCROW nRow)
Definition: detfunc.cxx:1237
SdrMetricItem makeSdrTextLeftDistItem(tools::Long mnHeight)
constexpr Point TopLeft() const
bool DeleteAll(ScDetectiveDelete eWhat)
Definition: detfunc.cxx:1292
virtual SdrLayerID GetLayer() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
constexpr tools::Long Bottom() const
bool DeleteSucc(SCCOL nCol, SCROW nRow)
Definition: detfunc.cxx:1211
SCROW SanitizeRow(SCROW nRow) const
Definition: document.hxx:881
const ScAddress & GetPos() const
Definition: dociter.hxx:233
bool ValidColRow(SCCOL nCol, SCROW nRow) const
Definition: document.hxx:876
CellType meType
Definition: cellvalue.hxx:105
static Color GetCommentColor()
Definition: detfunc.cxx:1732
SdrObject * Next()
constexpr TypedWhichId< ScMergeFlagAttr > ATTR_MERGE_FLAG(145)
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
constexpr TypedWhichId< SdrMetricItem > SDRATTR_SHADOWXDIST(SDRATTR_SHADOW_FIRST+2)
void setClosed(bool bNew)
sal_Int32 SCROW
Definition: types.hxx:17
SfxItemSet aCircleSet
Definition: detfunc.cxx:97
ScDetectiveDelete
Definition: detfunc.hxx:36
SdrCaptionObj * GetCaption() const
Returns an existing note caption object.
Definition: postit.hxx:238
void GetAllSuccs(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,::std::vector< ScTokenRef > &rRefTokens)
Definition: detfunc.cxx:1438
sal_uInt32 count() const
void SetStreamValid(SCTAB nTab, bool bSet, bool bIgnoreLock=false)
Definition: document.cxx:925
static bool Intersect(SCCOL nStartCol1, SCROW nStartRow1, SCCOL nEndCol1, SCROW nEndRow1, SCCOL nStartCol2, SCROW nStartRow2, SCCOL nEndCol2, SCROW nEndRow2)
Definition: detfunc.cxx:281
bool GetNextRef(ScRange &rRange)
Definition: formulaiter.cxx:52
ColorConfigValue GetColorValue(ColorConfigEntry eEntry, bool bSmart=true) const
static void AppendChangTrackNoteSeparator(OUString &str)
Definition: detfunc.cxx:1756
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
bool HasError(const ScRange &rRange, ScAddress &rErrPos)
Definition: detfunc.cxx:288
SdrMetricItem makeSdrShadowXDistItem(tools::Long nDist)
static ScDrawObjData * GetObjDataTab(SdrObject *pObj, SCTAB nTab)
Definition: drwlayer.cxx:2609
static void InitializeColors()
Definition: detfunc.cxx:1739
bool HasArrow(const ScAddress &rStart, SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab)
Definition: detfunc.cxx:374
OUString aName
const SfxItemSet & GetMergedItemSet() const
Position inside cell for detective arrows.
constexpr SdrLayerID SC_LAYER_INTERN(2)
::boost::intrusive_ptr< formula::FormulaToken > ScTokenRef
Definition: types.hxx:29
virtual SdrPage * getSdrPageFromSdrObjList() const
SfxItemSet & GetArrowSet()
Definition: detfunc.cxx:104
void * p
These need to be in global namespace just like their respective types are.
bool DrawAlienEntry(const ScRange &rRef, ScDetectiveData &rData)
Definition: detfunc.cxx:617
SdrOnOffItem makeSdrShadowItem(bool bShadow)
void SetInvalid()
Definition: address.hxx:286
formula::FormulaToken * GetNextRefToken()
Definition: formulaiter.cxx:67
void DeleteArrowsAt(SCCOL nCol, SCROW nRow, bool bDestPnt)
Definition: detfunc.cxx:663
constexpr Point BottomRight() const
bool SC_DLLPUBLIC intersects(const ScDocument *pDoc, const ::std::vector< ScTokenRef > &rTokens, const ScTokenRef &pToken, const ScAddress &rPos)
static bool IsNoteCaption(SdrObject *pObj)
Returns true, if the passed object is the caption of a cell note.
Definition: drwlayer.cxx:2622
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
void InsertToOtherTab(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bRed, ScDetectiveData &rData)
Definition: detfunc.cxx:527
SdrObjList * getParentSdrObjListFromSdrObject() const
bool IsIgnoreBlank() const
Definition: conditio.hxx:371
void SetRunning(bool bVal)
#define SC_LINEEND_NAME
Definition: detfunc.cxx:78
virtual void NbcSetLogicRect(const tools::Rectangle &rRect) override
SC_DLLPUBLIC sal_uInt16 GetColWidth(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4151
ScAddress maEnd
Definition: userdat.hxx:37
#define SC_DET_TOLERANCE
Definition: detfunc.cxx:717
constexpr TypedWhichId< XLineColorItem > XATTR_LINECOLOR(XATTR_LINE_FIRST+3)
virtual Point GetPoint(sal_uInt32 i) const
B2DPolygon createPolygonFromEllipse(const B2DPoint &rCenter, double fRadiusX, double fRadiusY, sal_uInt32 nStartQuadrant=0)
void InsertArrow(SCCOL nCol, SCROW nRow, SCCOL nRefStartCol, SCROW nRefStartRow, SCCOL nRefEndCol, SCROW nRefEndRow, bool bFromOtherTab, bool bRed, ScDetectiveData &rData)
called from DrawEntry/DrawAlienEntry and InsertObject
Definition: detfunc.cxx:446
SfxItemSet & GetCircleSet()
Definition: detfunc.cxx:107
sal_Int16 SCTAB
Definition: types.hxx:22
ScDetectiveObjType GetDetectiveObjectType(SdrObject *pObject, SCTAB nObjTab, ScAddress &rPosition, ScRange &rSource, bool &rRedLine)
Definition: detfunc.cxx:1624
bool IsRecording() const
Definition: drwlayer.hxx:141