diff options
-rw-r--r-- | sc/inc/formulacell.hxx | 12 | ||||
-rw-r--r-- | sc/inc/listenercontext.hxx | 11 | ||||
-rw-r--r-- | sc/inc/refupdatecontext.hxx | 18 | ||||
-rw-r--r-- | sc/source/core/data/column.cxx | 234 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 17 | ||||
-rw-r--r-- | sc/source/core/data/listenercontext.cxx | 24 | ||||
-rw-r--r-- | sc/source/core/tool/token.cxx | 17 | ||||
-rw-r--r-- | sc/source/ui/inc/undoblk.hxx | 5 | ||||
-rw-r--r-- | sc/source/ui/undo/undoblk.cxx | 19 |
9 files changed, 293 insertions, 64 deletions
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index e901c6e2b10e..7e40ddd33bc2 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -141,12 +141,6 @@ private: const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos ); /** - * Update reference in response to cell move. - */ - bool UpdateReferenceOnMove( - const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos ); - - /** * Update reference in response to cell copy-n-paste. */ bool UpdateReferenceOnCopy( @@ -252,6 +246,12 @@ public: bool UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, const ScAddress* pUndoCellPos = NULL ); + /** + * Update reference in response to cell move. + */ + bool UpdateReferenceOnMove( + const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos ); + void TransposeReference(); void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc ); diff --git a/sc/inc/listenercontext.hxx b/sc/inc/listenercontext.hxx index 1e7d067f6f9f..c0260ef8be1a 100644 --- a/sc/inc/listenercontext.hxx +++ b/sc/inc/listenercontext.hxx @@ -17,6 +17,7 @@ #include <boost/scoped_ptr.hpp> class ScDocument; +class ScTokenArray; namespace sc { @@ -39,9 +40,17 @@ class EndListeningContext : boost::noncopyable ScDocument& mrDoc; ColumnSpanSet maSet; boost::scoped_ptr<ColumnBlockPositionSet> mpPosSet; + ScTokenArray* mpOldCode; + ScAddress maPosDelta; // Add this to get the old position prior to the move. + public: - EndListeningContext(ScDocument& rDoc); + EndListeningContext(ScDocument& rDoc, ScTokenArray* pOldCode = NULL); + + void setPositionDelta( const ScAddress& rDelta ); + ScDocument& getDoc(); + ScTokenArray* getOldCode(); + ScAddress getOldPosition( const ScAddress& rPos ) const; ColumnBlockPosition* getBlockPosition(SCTAB nTab, SCCOL nCol); diff --git a/sc/inc/refupdatecontext.hxx b/sc/inc/refupdatecontext.hxx index ba0beedbc161..c8e52d8acdf0 100644 --- a/sc/inc/refupdatecontext.hxx +++ b/sc/inc/refupdatecontext.hxx @@ -55,7 +55,8 @@ struct RefUpdateContext /** * Range of cells that are about to be moved for insert/delete/move modes. * For copy mode, it's the destination range of cells that are about to be - * pasted. + * pasted. When moving a range of cells, it's the destination range, not + * the source range. */ ScRange maRange; @@ -77,8 +78,23 @@ struct RefUpdateContext struct RefUpdateResult { + /** + * When this flag is true, the result of the formula needs to be + * re-calculated either because it contains a reference that's been + * deleted, or the size of a range reference has changed. + */ bool mbValueChanged; + + /** + * This flag indicates whether any reference in the token array has been + * modified. + */ bool mbReferenceModified; + + /** + * When this flag is true, it indicates that the token array contains a + * range name that's been updated. + */ bool mbNameModified; RefUpdateResult(); diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 47ef9cbdde62..db8cf962eac0 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -41,6 +41,7 @@ #include "scopetools.hxx" #include "sharedformula.hxx" #include "refupdatecontext.hxx" +#include <listenercontext.hxx> #include <svl/poolcach.hxx> #include <svl/zforlist.hxx> @@ -2328,6 +2329,67 @@ void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nR namespace { +struct FormulaGroup +{ + struct { + ScFormulaCell* mpCell; // non-shared formula cell + ScFormulaCell** mpCells; // pointer to the top formula cell in a shared group. + }; + size_t mnRow; + size_t mnLength; + bool mbShared; + + FormulaGroup( ScFormulaCell** pCells, size_t nRow, size_t nLength ) : + mpCells(pCells), mnRow(nRow), mnLength(nLength), mbShared(true) {} + + FormulaGroup( ScFormulaCell* pCell, size_t nRow ) : + mpCell(pCell), mnRow(nRow), mnLength(0), mbShared(false) {} +}; + +class SharedTopFormulaCellPicker : std::unary_function<sc::CellStoreType::value_type, void> +{ +public: + virtual ~SharedTopFormulaCellPicker() {} + + void operator() ( sc::CellStoreType::value_type& node ) + { + if (node.type != sc::element_type_formula) + return; + + size_t nTopRow = node.position; + + sc::formula_block::iterator itBeg = sc::formula_block::begin(*node.data); + sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data); + + // Only pick shared formula cells that are the top cells of their + // respective shared ranges. + for (sc::formula_block::iterator it = itBeg; it != itEnd; ++it) + { + ScFormulaCell* pCell = *it; + size_t nRow = nTopRow + std::distance(itBeg, it); + if (!pCell->IsShared()) + { + processNonShared(pCell, nRow); + continue; + } + + if (pCell->IsSharedTop()) + { + ScFormulaCell** pp = &(*it); + processSharedTop(pp, nRow, pCell->GetSharedLength()); + + // Move to the last cell in the group, to get incremented to + // the next cell in the next iteration. + size_t nOffsetToLast = pCell->GetSharedLength() - 1; + std::advance(it, nOffsetToLast); + } + } + } + + virtual void processNonShared( ScFormulaCell* /*pCell*/, size_t /*nRow*/ ) {} + virtual void processSharedTop( ScFormulaCell** /*ppCells*/, size_t /*nRow*/, size_t /*nLength*/ ) {} +}; + class UpdateRefOnCopy { const sc::RefUpdateContext& mrCxt; @@ -2358,67 +2420,162 @@ public: } }; -class UpdateRefOnNonCopy +class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void> { SCCOL mnCol; SCROW mnTab; - const sc::RefUpdateContext& mrCxt; + const sc::RefUpdateContext* mpCxt; ScDocument* mpUndoDoc; bool mbUpdated; + void updateRefOnMove( FormulaGroup& rGroup ) + { + if (!rGroup.mbShared) + { + ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab); + mbUpdated |= rGroup.mpCell->UpdateReferenceOnMove(*mpCxt, mpUndoDoc, &aUndoPos); + return; + } + + // Update references of a formula group. + ScFormulaCell** pp = rGroup.mpCells; + ScFormulaCell** ppEnd = pp + rGroup.mnLength; + ScFormulaCell* pTop = *pp; + ScTokenArray* pCode = pTop->GetCode(); + boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone()); + + ScAddress aPos = pTop->aPos; + ScAddress aOldPos = aPos; + + if (mpCxt->maRange.In(aPos)) + { + // The cell is being moved or copied to a new position. The + // position has already been updated prior to this call. + // Determine its original position before the move which will be + // used to adjust relative references later. + + aOldPos.Set( + aPos.Col() - mpCxt->mnColDelta, + aPos.Row() - mpCxt->mnRowDelta, + aPos.Tab() - mpCxt->mnTabDelta); + } + + bool bRecalcOnMove = pCode->IsRecalcModeOnRefMove(); + if (bRecalcOnMove) + bRecalcOnMove = aPos != aOldPos; + + sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(*mpCxt, aOldPos, aPos); + if (aRes.mbReferenceModified || bRecalcOnMove) + { + // Perform end-listening, start-listening, and dirtying on all + // formula cells in the group. + + sc::StartListeningContext aStartCxt(mpCxt->mrDoc); + + sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get()); + aEndCxt.setPositionDelta( + ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta)); + + for (; pp != ppEnd; ++pp) + { + ScFormulaCell* p = *pp; + p->EndListeningTo(aEndCxt); + p->StartListeningTo(aStartCxt); + p->SetDirty(); + } + + if (mpUndoDoc) + { + // Insert the old formula group into the undo document. + ScAddress aUndoPos = aOldPos; + ScFormulaCell* pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, pOldCode->Clone()); + ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(rGroup.mnLength, false); + + mpUndoDoc->SetFormulaCell(aUndoPos, pFC); + aUndoPos.IncRow(); + for (size_t i = 1; i < rGroup.mnLength; ++i, aUndoPos.IncRow()) + { + pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, xGroup); + mpUndoDoc->SetFormulaCell(aUndoPos, pFC); + } + } + } + } + public: UpdateRefOnNonCopy( - SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext& rCxt, + SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext* pCxt, ScDocument* pUndoDoc) : - mnCol(nCol), mnTab(nTab), mrCxt(rCxt), + mnCol(nCol), mnTab(nTab), mpCxt(pCxt), mpUndoDoc(pUndoDoc), mbUpdated(false) {} - void operator() (size_t nRow, ScFormulaCell* pCell) + void operator() ( FormulaGroup& rGroup ) { - ScAddress aUndoPos(mnCol, nRow, mnTab); - mbUpdated |= pCell->UpdateReference(mrCxt, mpUndoDoc, &aUndoPos); + if (mpCxt->meMode == URM_MOVE) + { + updateRefOnMove(rGroup); + return; + } + + if (rGroup.mbShared) + { + ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab); + ScFormulaCell** pp = rGroup.mpCells; + ScFormulaCell** ppEnd = pp + rGroup.mnLength; + for (; pp != ppEnd; ++pp, aUndoPos.IncRow()) + { + ScFormulaCell* p = *pp; + mbUpdated |= p->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos); + } + } + else + { + ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab); + mbUpdated |= rGroup.mpCell->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos); + } } bool isUpdated() const { return mbUpdated; } }; -class UpdateRefGroupBoundChecker : std::unary_function<sc::CellStoreType::value_type, void> +class UpdateRefGroupBoundChecker : public SharedTopFormulaCellPicker { const sc::RefUpdateContext& mrCxt; std::vector<SCROW>& mrBounds; + public: UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) : mrCxt(rCxt), mrBounds(rBounds) {} - void operator() (const sc::CellStoreType::value_type& node) + virtual ~UpdateRefGroupBoundChecker() {} + + virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) { - if (node.type != sc::element_type_formula) - return; + // Check its tokens and record its reference boundaries. + ScFormulaCell& rCell = **ppCells; + const ScTokenArray& rCode = *rCell.GetCode(); + rCode.CheckRelativeReferenceBounds( + mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds); + } +}; - sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data); - sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data); +class FormulaGroupPicker : public SharedTopFormulaCellPicker +{ + std::vector<FormulaGroup>& mrGroups; - // Only pick shared formula cells that are the top cells of their - // respective shared ranges. - for (; it != itEnd; ++it) - { - const ScFormulaCell& rCell = **it; - if (!rCell.IsShared()) - continue; +public: + FormulaGroupPicker( std::vector<FormulaGroup>& rGroups ) : mrGroups(rGroups) {} - if (rCell.IsSharedTop()) - { - // Check its tokens and record its reference boundaries. - const ScTokenArray& rCode = *rCell.GetCode(); - rCode.CheckRelativeReferenceBounds( - mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds); + virtual ~FormulaGroupPicker() {} - // Move to the last cell in the group, to get incremented to - // the next cell in the next iteration. - size_t nOffsetToLast = rCell.GetSharedLength() - 1; - std::advance(it, nOffsetToLast); - } - } + virtual void processNonShared( ScFormulaCell* pCell, size_t nRow ) + { + mrGroups.push_back(FormulaGroup(pCell, nRow)); + } + + virtual void processSharedTop( ScFormulaCell** ppCells, size_t nRow, size_t nLength ) + { + mrGroups.push_back(FormulaGroup(ppCells, nRow, nLength)); } }; @@ -2451,8 +2608,8 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc if (rCxt.meMode == URM_COPY) return UpdateReferenceOnCopy(rCxt, pUndoDoc); - if (IsEmptyData()) - // Cells in this column are all empty. + if (IsEmptyData() || pDocument->IsClipOrUndo()) + // Cells in this column are all empty, or clip or undo doc. No update needed. return false; std::vector<SCROW> aBounds; @@ -2490,8 +2647,13 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc // Do the actual splitting. sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds); - UpdateRefOnNonCopy aHandler(nCol, nTab, rCxt, pUndoDoc); - sc::ProcessFormula(maCells, aHandler); + // Collect all formula groups. + std::vector<FormulaGroup> aGroups; + std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups)); + + // Process all collected formula groups. + UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc); + aHandler = std::for_each(aGroups.begin(), aGroups.end(), aHandler); if (aHandler.isUpdated()) rCxt.maRegroupCols.set(nTab, nCol); diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 0de5c8729506..6da276a7f6f9 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -3944,7 +3944,7 @@ void ScFormulaCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr, { case svSingleRef: { - ScAddress aCell = t->GetSingleRef().toAbs(aPos); + ScAddress aCell = t->GetSingleRef().toAbs(aCellPos); if (aCell.IsValid()) pDoc->EndListeningCell(aCell, this); } @@ -3966,27 +3966,32 @@ void ScFormulaCell::EndListeningTo( sc::EndListeningContext& rCxt ) ScDocument& rDoc = rCxt.getDoc(); rDoc.SetDetectiveDirty(true); // It has changed something - if (pCode->IsRecalcModeAlways()) + ScTokenArray* pArr = rCxt.getOldCode(); + ScAddress aCellPos = rCxt.getOldPosition(aPos); + if (!pArr) + pArr = pCode; + + if (pArr->IsRecalcModeAlways()) { rDoc.EndListeningArea(BCA_LISTEN_ALWAYS, this); return; } - pCode->Reset(); + pArr->Reset(); ScToken* t; - while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL ) + while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL ) { switch (t->GetType()) { case svSingleRef: { - ScAddress aCell = t->GetSingleRef().toAbs(aPos); + ScAddress aCell = t->GetSingleRef().toAbs(aCellPos); if (aCell.IsValid()) rDoc.EndListeningCell(rCxt, aCell, *this); } break; case svDoubleRef: - endListeningArea(this, rDoc, aPos, *t); + endListeningArea(this, rDoc, aCellPos, *t); break; default: ; // nothing diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx index dc9234681acb..3dfe5edb0b37 100644 --- a/sc/source/core/data/listenercontext.cxx +++ b/sc/source/core/data/listenercontext.cxx @@ -52,14 +52,34 @@ ColumnBlockPosition* StartListeningContext::getBlockPosition(SCTAB nTab, SCCOL n return mpSet->getBlockPosition(nTab, nCol); } -EndListeningContext::EndListeningContext(ScDocument& rDoc) : - mrDoc(rDoc), maSet(false), mpPosSet(new ColumnBlockPositionSet(rDoc)) {} +EndListeningContext::EndListeningContext(ScDocument& rDoc, ScTokenArray* pOldCode) : + mrDoc(rDoc), maSet(false), mpPosSet(new ColumnBlockPositionSet(rDoc)), + mpOldCode(pOldCode), maPosDelta(0,0,0) {} + +void EndListeningContext::setPositionDelta( const ScAddress& rDelta ) +{ + maPosDelta = rDelta; +} ScDocument& EndListeningContext::getDoc() { return mrDoc; } +ScTokenArray* EndListeningContext::getOldCode() +{ + return mpOldCode; +} + +ScAddress EndListeningContext::getOldPosition( const ScAddress& rPos ) const +{ + ScAddress aOldPos = rPos; + aOldPos.IncCol(maPosDelta.Col()); + aOldPos.IncRow(maPosDelta.Row()); + aOldPos.IncTab(maPosDelta.Tab()); + return aOldPos; +} + ColumnBlockPosition* EndListeningContext::getBlockPosition(SCTAB nTab, SCCOL nCol) { return mpPosSet->getBlockPosition(nTab, nCol); diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index fc9ad75e476d..92a9c77be623 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -3155,17 +3155,22 @@ void checkBounds( if (!rRef.IsRowRel()) return; + ScRange aCheckRange = rCxt.maRange; + if (rCxt.meMode == URM_MOVE) + // Check bounds against the old range prior to the move. + aCheckRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta); + ScRange aAbs(rRef.toAbs(rPos)); aAbs.aEnd.IncRow(nGroupLen-1); - if (!rCxt.maRange.Intersects(aAbs)) + if (!aCheckRange.Intersects(aAbs)) return; // Get the boundary row positions. - if (aAbs.aEnd.Row() < rCxt.maRange.aStart.Row()) + if (aAbs.aEnd.Row() < aCheckRange.aStart.Row()) // No intersections. return; - if (aAbs.aStart.Row() <= rCxt.maRange.aStart.Row()) + if (aAbs.aStart.Row() <= aCheckRange.aStart.Row()) { // +-+ <---- top // | | @@ -3175,11 +3180,11 @@ void checkBounds( // +-------+ // Add offset from the reference top to the cell position. - SCROW nOffset = rCxt.maRange.aStart.Row() - aAbs.aStart.Row(); + SCROW nOffset = aCheckRange.aStart.Row() - aAbs.aStart.Row(); rBounds.push_back(rPos.Row()+nOffset); } - if (aAbs.aEnd.Row() >= rCxt.maRange.aEnd.Row()) + if (aAbs.aEnd.Row() >= aCheckRange.aEnd.Row()) { // only check for end range @@ -3191,7 +3196,7 @@ void checkBounds( // +-+ // Ditto. - SCROW nOffset = rCxt.maRange.aEnd.Row() + 1 - aAbs.aStart.Row(); + SCROW nOffset = aCheckRange.aEnd.Row() + 1 - aAbs.aStart.Row(); rBounds.push_back(rPos.Row()+nOffset); } } diff --git a/sc/source/ui/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx index 1b10216b3ebd..758e5bb91357 100644 --- a/sc/source/ui/inc/undoblk.hxx +++ b/sc/source/ui/inc/undoblk.hxx @@ -239,6 +239,9 @@ public: virtual OUString GetComment() const; private: + sal_uInt16 mnPaintExtFlags; + ScRangeList maPaintRanges; + ScRange aSrcRange; ScRange aDestRange; sal_uLong nStartChangeAction; @@ -247,7 +250,7 @@ private: sal_Bool bKeepScenarioFlags; void PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const; - void DoUndo( ScRange aRange ) const; + void DoUndo( ScRange aRange ); void SetChangeTrack(); }; diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx index 6497f0e17849..aebdb3ee9afc 100644 --- a/sc/source/ui/undo/undoblk.cxx +++ b/sc/source/ui/undo/undoblk.cxx @@ -1218,7 +1218,7 @@ void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const pDocShell->PostPaint( aRange, nPaint, nExtFlags ); } -void ScUndoDragDrop::DoUndo( ScRange aRange ) const +void ScUndoDragDrop::DoUndo( ScRange aRange ) { ScDocument* pDoc = pDocShell->GetDocument(); @@ -1231,8 +1231,7 @@ void ScUndoDragDrop::DoUndo( ScRange aRange ) const ScRange aPaintRange = aRange; pDoc->ExtendMerge( aPaintRange ); // before deleting - sal_uInt16 nExtFlags = 0; - pDocShell->UpdatePaintExt( nExtFlags, aPaintRange ); + pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange); // do not undo objects and note captions, they are handled via drawing undo sal_uInt16 nUndoFlags = (IDF_ALL & ~IDF_OBJECTS) | IDF_NOCAPTIONS; @@ -1245,16 +1244,26 @@ void ScUndoDragDrop::DoUndo( ScRange aRange ) const aPaintRange.aEnd.SetCol( std::max( aPaintRange.aEnd.Col(), aRange.aEnd.Col() ) ); aPaintRange.aEnd.SetRow( std::max( aPaintRange.aEnd.Row(), aRange.aEnd.Row() ) ); - pDocShell->UpdatePaintExt( nExtFlags, aPaintRange ); - PaintArea( aPaintRange, nExtFlags ); + pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange); + maPaintRanges.Join(aPaintRange); } void ScUndoDragDrop::Undo() { + mnPaintExtFlags = 0; + maPaintRanges.RemoveAll(); + BeginUndo(); DoUndo(aDestRange); if (bCut) DoUndo(aSrcRange); + + for (size_t i = 0; i < maPaintRanges.size(); ++i) + { + const ScRange* p = maPaintRanges[i]; + PaintArea(*p, mnPaintExtFlags); + } + EndUndo(); SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); } |