1 diff --git sc/inc/cell.hxx sc/inc/cell.hxx
2 index 5ec1281..4c1afdb 100644
5 @@ -662,6 +662,7 @@ private:
7 ScDetectiveRefIter( ScFormulaCell* pCell );
8 BOOL GetNextRef( ScRange& rRange );
9 + ScToken* GetNextRefToken();
12 // ============================================================================
13 diff --git sc/inc/detfunc.hxx sc/inc/detfunc.hxx
14 index 49a7938..c38150d 100644
15 --- sc/inc/detfunc.hxx
16 +++ sc/inc/detfunc.hxx
18 #include <tools/gen.hxx>
19 #include <tools/color.hxx>
27 @@ -46,6 +49,7 @@ class ScDetectiveData;
33 #define SC_DET_MAXCIRCLE 1000
35 @@ -146,6 +150,9 @@ public:
37 BOOL MarkInvalid(BOOL& rOverflow);
39 + void GetAllPreds(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ::std::vector<ScSharedTokenRef>& rRefTokens);
40 + void GetAllSuccs(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ::std::vector<ScSharedTokenRef>& rRefTokens);
42 static void UpdateAllComments( ScDocument& rDoc ); // on all tables
43 void UpdateAllArrowColors(); // on all tables
45 diff --git sc/inc/reftokenhelper.hxx sc/inc/reftokenhelper.hxx
46 index d7b335f..44619ab 100644
47 --- sc/inc/reftokenhelper.hxx
48 +++ sc/inc/reftokenhelper.hxx
49 @@ -78,6 +78,9 @@ public:
50 static void join(::std::vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken);
52 static bool getDoubleRefDataFromToken(ScComplexRefData& rData, const ScSharedTokenRef& pToken);
54 + static ScSharedTokenRef createRefToken(const ScAddress& rAddr);
55 + static ScSharedTokenRef createRefToken(const ScRange& rRange);
59 diff --git sc/inc/sc.hrc sc/inc/sc.hrc
60 index bd688c8..340416b 100644
64 #define SID_DETECTIVE_REFRESH (DETECTIVE_START+14)
65 #define SID_DETECTIVE_AUTO (DETECTIVE_START+15)
67 +#define SID_DETECTIVE_MARK_PRED (DETECTIVE_START+16)
68 +#define SID_DETECTIVE_MARK_SUCC (DETECTIVE_START+17)
70 #define DETECTIVE_END (DETECTIVE_START+20)
72 #define SID_API_SLOTS (DETECTIVE_END)
73 diff --git sc/sdi/cellsh.sdi sc/sdi/cellsh.sdi
74 index 05ab23c..b22589b 100644
77 @@ -113,6 +113,8 @@ interface CellSelection
78 SID_DETECTIVE_ADD_ERR [ ExecMethod = ExecuteEdit; StateMethod = GetState; ]
79 SID_DETECTIVE_INVALID [ ExecMethod = ExecuteEdit; StateMethod = GetState; ]
80 SID_DETECTIVE_REFRESH [ ExecMethod = ExecuteEdit; StateMethod = GetState; ]
81 + SID_DETECTIVE_MARK_PRED [ ExecMethod = ExecuteEdit; StateMethod = GetState; ]
82 + SID_DETECTIVE_MARK_SUCC [ ExecMethod = ExecuteEdit; StateMethod = GetState; ]
83 FID_INS_ROW [ ExecMethod = ExecuteEdit; StateMethod = GetBlockState; ]
84 FID_INS_COLUMN [ ExecMethod = ExecuteEdit; StateMethod = GetBlockState; ]
85 FID_INS_CELLSDOWN [ ExecMethod = ExecuteEdit; StateMethod = GetBlockState; ]
86 diff --git sc/sdi/scalc.sdi sc/sdi/scalc.sdi
87 index 66c0a09..f8eddc2 100644
90 @@ -7899,4 +7899,53 @@ SfxBoolItem ToggleSheetGrid FID_TAB_TOGGLE_GRID
94 +//--------------------------------------------------------------------------
95 +SfxVoidItem MarkPrecedents SID_DETECTIVE_MARK_PRED
100 + Cachable = Cachable,
104 + ReadOnlyDoc = TRUE,
107 + RecordAbsolute = FALSE,
112 + AccelConfig = TRUE,
114 + StatusBarConfig = FALSE,
115 + ToolBoxConfig = FALSE,
116 + GroupId = GID_OPTIONS;
119 +//--------------------------------------------------------------------------
120 +SfxVoidItem MarkDependents SID_DETECTIVE_MARK_SUCC
124 + AutoUpdate = FALSE,
125 + Cachable = Cachable,
129 + ReadOnlyDoc = TRUE,
132 + RecordAbsolute = FALSE,
137 + AccelConfig = TRUE,
139 + StatusBarConfig = FALSE,
140 + ToolBoxConfig = FALSE,
141 + GroupId = GID_OPTIONS;
144 diff --git sc/source/core/data/cell.cxx sc/source/core/data/cell.cxx
145 index 1c3035c..4d5773d 100644
146 --- sc/source/core/data/cell.cxx
147 +++ sc/source/core/data/cell.cxx
148 @@ -1954,7 +1954,7 @@ BOOL lcl_ScDetectiveRefIter_SkipRef( ScToken* p )
149 if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted()
152 - if ( p->GetType() == svDoubleRef )
153 + if ( p->GetType() == svDoubleRef || p->GetType() == svExternalDoubleRef )
155 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
156 if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted()
157 @@ -1967,7 +1967,20 @@ BOOL lcl_ScDetectiveRefIter_SkipRef( ScToken* p )
158 BOOL ScDetectiveRefIter::GetNextRef( ScRange& rRange )
161 + ScToken* p = GetNextRefToken();
164 + SingleDoubleRefProvider aProv( *p );
165 + rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab );
166 + rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab );
173 +ScToken* ScDetectiveRefIter::GetNextRefToken()
175 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
177 p->CalcAbsIfRel( aPos );
178 @@ -1978,16 +1991,7 @@ BOOL ScDetectiveRefIter::GetNextRef( ScRange& rRange )
180 p->CalcAbsIfRel( aPos );
185 - SingleDoubleRefProvider aProv( *p );
186 - rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab );
187 - rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab );
195 // ============================================================================
196 diff --git sc/source/core/tool/detfunc.cxx sc/source/core/tool/detfunc.cxx
197 index 7680bda..99e0e71 100644
198 --- sc/source/core/tool/detfunc.cxx
199 +++ sc/source/core/tool/detfunc.cxx
201 #include "attrib.hxx"
203 #include "postit.hxx"
204 +#include "rangelst.hxx"
205 +#include "reftokenhelper.hxx"
209 +using ::std::vector;
211 //------------------------------------------------------------------------
213 @@ -1407,6 +1413,52 @@ BOOL ScDetectiveFunc::MarkInvalid(BOOL& rOverflow)
214 return ( bDeleted || nInsCount != 0 );
217 +void ScDetectiveFunc::GetAllPreds(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
218 + vector<ScSharedTokenRef>& rRefTokens)
220 + ScCellIterator aCellIter(pDoc, nCol1, nRow1, nTab, nCol2, nRow2, nTab);
221 + for (ScBaseCell* pCell = aCellIter.GetFirst(); pCell; pCell = aCellIter.GetNext())
223 + if (pCell->GetCellType() != CELLTYPE_FORMULA)
226 + ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
227 + ScDetectiveRefIter aRefIter(pFCell);
228 + for (ScToken* p = aRefIter.GetNextRefToken(); p; p = aRefIter.GetNextRefToken())
230 + ScSharedTokenRef pRef(static_cast<ScToken*>(p->Clone()));
231 + ScRefTokenHelper::join(rRefTokens, pRef);
236 +void ScDetectiveFunc::GetAllSuccs(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
237 + vector<ScSharedTokenRef>& rRefTokens)
239 + vector<ScSharedTokenRef> aSrcRange;
240 + aSrcRange.push_back(
241 + ScRefTokenHelper::createRefToken(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab)));
243 + ScCellIterator aCellIter(pDoc, 0, 0, nTab, MAXCOL, MAXROW, nTab);
244 + for (ScBaseCell* pCell = aCellIter.GetFirst(); pCell; pCell = aCellIter.GetNext())
246 + if (pCell->GetCellType() != CELLTYPE_FORMULA)
249 + ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
250 + ScDetectiveRefIter aRefIter(pFCell);
251 + for (ScToken* p = aRefIter.GetNextRefToken(); p; p = aRefIter.GetNextRefToken())
253 + ScSharedTokenRef pRef(static_cast<ScToken*>(p->Clone()));
254 + if (ScRefTokenHelper::intersects(aSrcRange, pRef))
256 + pRef = ScRefTokenHelper::createRefToken(aCellIter.GetPos());
257 + ScRefTokenHelper::join(rRefTokens, pRef);
263 void ScDetectiveFunc::UpdateAllComments( ScDocument& rDoc )
265 // for all caption objects, update attributes and SpecialTextBoxShadow flag
266 --- sc/source/core/tool/makefile.mk
267 +++ sc/source/core/tool/makefile.mk
269 $(SLO)$/chartlock.obj \
270 $(SLO)$/chgtrack.obj \
271 $(SLO)$/compiler.obj \
272 + $(SLO)$/detfunc.obj \
273 $(SLO)$/doubleref.obj \
274 $(SLO)$/formulaparserpool.obj \
275 $(SLO)$/interpr1.obj \
276 diff --git sc/source/core/tool/reftokenhelper.cxx sc/source/core/tool/reftokenhelper.cxx
277 index ed196e0..635df6e 100644
278 --- sc/source/core/tool/reftokenhelper.cxx
279 +++ sc/source/core/tool/reftokenhelper.cxx
280 @@ -475,3 +475,19 @@ bool ScRefTokenHelper::getDoubleRefDataFromToken(ScComplexRefData& rData, const
285 +ScSharedTokenRef ScRefTokenHelper::createRefToken(const ScAddress& rAddr)
287 + ScSingleRefData aRefData;
288 + aRefData.InitAddress(rAddr);
289 + ScSharedTokenRef pRef(new ScSingleRefToken(aRefData));
293 +ScSharedTokenRef ScRefTokenHelper::createRefToken(const ScRange& rRange)
295 + ScComplexRefData aRefData;
296 + aRefData.InitRange(rRange);
297 + ScSharedTokenRef pRef(new ScDoubleRefToken(aRefData));
300 diff --git sc/source/ui/docshell/docfunc.cxx sc/source/ui/docshell/docfunc.cxx
301 index f55b697..a289649 100644
302 --- sc/source/ui/docshell/docfunc.cxx
303 +++ sc/source/ui/docshell/docfunc.cxx
306 using namespace com::sun::star;
307 using ::com::sun::star::uno::Sequence;
308 +using ::std::vector;
310 // STATIC DATA -----------------------------------------------------------
312 @@ -524,6 +525,44 @@ BOOL ScDocFunc::DetectiveRefresh( BOOL bAutomatic )
316 +static void lcl_collectAllPredOrSuccRanges(
317 + const ScRangeList& rSrcRanges, vector<ScSharedTokenRef>& rRefTokens, ScDocShell& rDocShell,
320 + ScDocument* pDoc = rDocShell.GetDocument();
321 + vector<ScSharedTokenRef> aRefTokens;
322 + ScRangeList aSrcRanges(rSrcRanges);
323 + ScRange* p = aSrcRanges.First();
326 + ScDetectiveFunc aDetFunc(pDoc, p->aStart.Tab());
327 + ScRangeList aDestRanges;
328 + for (; p; p = aSrcRanges.Next())
332 + aDetFunc.GetAllPreds(
333 + p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), aRefTokens);
337 + aDetFunc.GetAllSuccs(
338 + p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), aRefTokens);
341 + rRefTokens.swap(aRefTokens);
344 +void ScDocFunc::DetectiveCollectAllPreds(const ScRangeList& rSrcRanges, vector<ScSharedTokenRef>& rRefTokens)
346 + lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, true);
349 +void ScDocFunc::DetectiveCollectAllSuccs(const ScRangeList& rSrcRanges, vector<ScSharedTokenRef>& rRefTokens)
351 + lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, false);
354 //------------------------------------------------------------------------
356 BOOL ScDocFunc::DeleteContents( const ScMarkData& rMark, USHORT nFlags,
357 diff --git sc/source/ui/inc/docfunc.hxx sc/source/ui/inc/docfunc.hxx
358 index 6a1bf00..302b07d 100644
359 --- sc/source/ui/inc/docfunc.hxx
360 +++ sc/source/ui/inc/docfunc.hxx
362 #include <tools/link.hxx>
363 #include "global.hxx"
364 #include "formula/grammar.hxx"
365 #include "tabbgcolor.hxx"
366 +#include "token.hxx"
370 class ScEditEngineDefaulter;
372 @@ -42,6 +45,7 @@ class ScDocShell;
380 @@ -77,6 +81,8 @@ public:
381 BOOL DetectiveMarkInvalid(SCTAB nTab);
382 BOOL DetectiveDelAll(SCTAB nTab);
383 BOOL DetectiveRefresh(BOOL bAutomatic = FALSE);
384 + void DetectiveCollectAllPreds(const ScRangeList& rSrcRanges, ::std::vector<ScSharedTokenRef>& rRefTokens);
385 + void DetectiveCollectAllSuccs(const ScRangeList& rSrcRanges, ::std::vector<ScSharedTokenRef>& rRefTokens);
387 BOOL DeleteContents( const ScMarkData& rMark, USHORT nFlags,
388 BOOL bRecord, BOOL bApi );
389 diff --git sc/source/ui/inc/viewfunc.hxx sc/source/ui/inc/viewfunc.hxx
390 index 7bf556d..7bd9a26 100644
391 --- sc/source/ui/inc/viewfunc.hxx
392 +++ sc/source/ui/inc/viewfunc.hxx
393 @@ -326,6 +326,8 @@ public:
394 void DetectiveMarkInvalid();
395 void DetectiveDelAll();
396 void DetectiveRefresh();
397 + void DetectiveMarkPred();
398 + void DetectiveMarkSucc();
400 void ShowNote( bool bShow = true );
401 inline void HideNote() { ShowNote( false ); }
402 @@ -366,6 +368,8 @@ private:
403 BOOL TestFormatArea( SCCOL nCol, SCROW nRow, SCTAB nTab, BOOL bAttrChanged );
404 void DoAutoAttributes( SCCOL nCol, SCROW nRow, SCTAB nTab,
405 BOOL bAttrChanged, BOOL bAddUndo );
407 + void MarkAndJumpToRanges(const ScRangeList& rRanges);
411 diff --git sc/source/ui/view/cellsh1.cxx sc/source/ui/view/cellsh1.cxx
412 index 0cd4007..d6fdb75 100644
413 --- sc/source/ui/view/cellsh1.cxx
414 +++ sc/source/ui/view/cellsh1.cxx
415 @@ -1584,6 +1584,13 @@ void ScCellShell::ExecuteEdit( SfxRequest& rReq )
419 + case SID_DETECTIVE_MARK_PRED:
420 + pTabViewShell->DetectiveMarkPred();
422 + case SID_DETECTIVE_MARK_SUCC:
423 + pTabViewShell->DetectiveMarkSucc();
426 case SID_SPELL_DIALOG:
427 // pTabViewShell->DoSpellingChecker();
429 diff --git sc/source/ui/view/gridwin.cxx sc/source/ui/view/gridwin.cxx
430 index 57f1996..2b2ec31 100644
431 --- sc/source/ui/view/gridwin.cxx
432 +++ sc/source/ui/view/gridwin.cxx
433 @@ -3078,6 +3078,17 @@ void __EXPORT ScGridWindow::KeyInput(const KeyEvent& rKEvt)
434 ShowNoteMarker( pViewData->GetCurX(), pViewData->GetCurY(), TRUE );
437 + if (aCode.GetCode() == KEY_BRACKETLEFT && aCode.GetModifier() == KEY_MOD1)
439 + pViewSh->DetectiveMarkPred();
442 + if (aCode.GetCode() == KEY_BRACKETRIGHT && aCode.GetModifier() == KEY_MOD1)
444 + pViewSh->DetectiveMarkSucc();
450 Window::KeyInput(rKEvt);
451 diff --git sc/source/ui/view/tabvwsh3.cxx sc/source/ui/view/tabvwsh3.cxx
452 index e106539..eb4c908 100644
453 --- sc/source/ui/view/tabvwsh3.cxx
454 +++ sc/source/ui/view/tabvwsh3.cxx
455 @@ -407,13 +407,15 @@ void ScTabViewShell::Execute( SfxRequest& rReq )
457 pViewData->ResetOldCursor();
458 SetCursor( nCol, nRow );
459 - AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP );
460 rBindings.Invalidate( SID_CURRENTCELL );
461 rBindings.Update( nSlot );
466 + // align to cursor even if the cursor position hasn't changed,
467 + // because the cursor may be set outside the visible area.
468 + AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP );
470 rReq.SetReturnValue( SfxStringItem( SID_CURRENTCELL, aAddress ) );
472 diff --git sc/source/ui/view/viewfun6.cxx sc/source/ui/view/viewfun6.cxx
473 index 43b3db1..e686cfc 100644
474 --- sc/source/ui/view/viewfun6.cxx
475 +++ sc/source/ui/view/viewfun6.cxx
477 #include "globstr.hrc"
480 +#include "reftokenhelper.hxx"
481 +#include "externalrefmgr.hxx"
485 +using ::rtl::OUStringBuffer;
486 +using ::std::vector;
488 //==================================================================
490 @@ -140,6 +147,136 @@ void ScViewFunc::DetectiveRefresh()
494 +static void lcl_jumpToRange(const ScRange& rRange, ScViewData* pView, ScDocument* pDoc)
497 + rRange.Format(aAddrText, SCR_ABS_3D, pDoc);
498 + SfxStringItem aPosItem(SID_CURRENTCELL, aAddrText);
499 + SfxBoolItem aUnmarkItem(FN_PARAM_1, TRUE); // remove existing selection
500 + pView->GetDispatcher().Execute(
501 + SID_CURRENTCELL, SFX_CALLMODE_SYNCHRON | SFX_CALLMODE_RECORD,
502 + &aPosItem, &aUnmarkItem, 0L);
505 +void ScViewFunc::MarkAndJumpToRanges(const ScRangeList& rRanges)
507 + ScViewData* pView = GetViewData();
508 + ScDocShell* pDocSh = pView->GetDocShell();
510 + ScRangeList aRanges(rRanges);
511 + ScRange* p = aRanges.First();
512 + ScRangeList aRangesToMark;
513 + ScAddress aCurPos = pView->GetCurPos();
514 + for (; p; p = aRanges.Next())
516 + // Collect only those ranges that are on the same sheet as the current
519 + if (p->aStart.Tab() == aCurPos.Tab())
520 + aRangesToMark.Append(*p);
523 + if (!aRangesToMark.Count())
526 + // Jump to the first range of all precedent ranges.
527 + p = aRangesToMark.First();
528 + lcl_jumpToRange(*p, pView, pDocSh->GetDocument());
530 + for (; p; p = aRangesToMark.Next())
531 + MarkRange(*p, false, true);
534 +void ScViewFunc::DetectiveMarkPred()
536 + ScViewData* pView = GetViewData();
537 + ScDocShell* pDocSh = pView->GetDocShell();
538 + ScDocument* pDoc = pDocSh->GetDocument();
539 + ScMarkData& rMarkData = pView->GetMarkData();
540 + ScAddress aCurPos = pView->GetCurPos();
541 + ScRangeList aRanges;
542 + if (rMarkData.IsMarked() || rMarkData.IsMultiMarked())
543 + rMarkData.FillRangeListWithMarks(&aRanges, false);
545 + aRanges.Append(aCurPos);
547 + vector<ScSharedTokenRef> aRefTokens;
548 + pDocSh->GetDocFunc().DetectiveCollectAllPreds(aRanges, aRefTokens);
550 + if (aRefTokens.empty())
551 + // No precedents found. Nothing to do.
554 + ScSharedTokenRef p = aRefTokens.front();
555 + if (ScRefTokenHelper::isExternalRef(p))
557 + // This is external. Open the external document if available, and
558 + // jump to the destination.
560 + sal_uInt16 nFileId = p->GetIndex();
561 + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
562 + const String* pPath = pRefMgr->getExternalFileName(nFileId);
565 + if (pPath && ScRefTokenHelper::getRangeFromToken(aRange, p, true))
567 + const String& rTabName = p->GetString();
568 + OUStringBuffer aBuf;
569 + aBuf.append(*pPath);
570 + aBuf.append(sal_Unicode('#'));
571 + aBuf.append(rTabName);
572 + aBuf.append(sal_Unicode('.'));
575 + aRange.Format(aRangeStr, SCA_VALID);
576 + aBuf.append(aRangeStr);
578 + ScGlobal::OpenURL(aBuf.makeStringAndClear(), String());
585 + ScRefTokenHelper::getRangeFromToken(aRange, p, false);
586 + if (aRange.aStart.Tab() != aCurPos.Tab())
588 + // The first precedent range is on a different sheet. Jump to it
589 + // immediately and forget the rest.
590 + lcl_jumpToRange(aRange, pView, pDoc);
595 + ScRangeList aDestRanges;
596 + ScRefTokenHelper::getRangeListFromTokens(aDestRanges, aRefTokens);
597 + MarkAndJumpToRanges(aDestRanges);
600 +void ScViewFunc::DetectiveMarkSucc()
602 + ScViewData* pView = GetViewData();
603 + ScDocShell* pDocSh = pView->GetDocShell();
604 + ScMarkData& rMarkData = pView->GetMarkData();
605 + ScAddress aCurPos = pView->GetCurPos();
606 + ScRangeList aRanges;
607 + if (rMarkData.IsMarked() || rMarkData.IsMultiMarked())
608 + rMarkData.FillRangeListWithMarks(&aRanges, false);
610 + aRanges.Append(aCurPos);
612 + vector<ScSharedTokenRef> aRefTokens;
613 + pDocSh->GetDocFunc().DetectiveCollectAllSuccs(aRanges, aRefTokens);
615 + if (aRefTokens.empty())
616 + // No dependants found. Nothing to do.
619 + ScRangeList aDestRanges;
620 + ScRefTokenHelper::getRangeListFromTokens(aDestRanges, aRefTokens);
621 + MarkAndJumpToRanges(aDestRanges);
624 //---------------------------------------------------------------------------
626 void ScViewFunc::ShowNote( bool bShow )