LCOV - code coverage report
Current view: top level - libreoffice/sc/source/core/tool - detfunc.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 53 880 6.0 %
Date: 2012-12-27 Functions: 5 57 8.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10