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