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