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