Kaydet (Commit) 9fc84406 authored tarafından Eike Rathke's avatar Eike Rathke Kaydeden (comit) Andras Timar

more adjustment of references in RPN

Similar to 47f002cb the RPN tokens have
to be adjusted to catch also references generated from named expressions
and the like. Quite likely this may fix some non-obvious cases of
reference update bugs and listener problems. If some cases worked so far
it means we're recompiling too much..

Change-Id: I29e8427f72afdd29aa45047cb52ba59161c18892
(cherry picked from commit bff9eddb)
üst 8bb59c85
...@@ -126,14 +126,17 @@ namespace ...@@ -126,14 +126,17 @@ namespace
struct TokenPointers struct TokenPointers
{ {
TokenPointerRange maPointerRange[2]; TokenPointerRange maPointerRange[2];
bool mbSkipRelName;
TokenPointers( FormulaToken** pCode, sal_uInt16 nLen, FormulaToken** pRPN, sal_uInt16 nRPN ) TokenPointers( FormulaToken** pCode, sal_uInt16 nLen, FormulaToken** pRPN, sal_uInt16 nRPN,
bool bSkipRelName = true ) :
mbSkipRelName(bSkipRelName)
{ {
maPointerRange[0] = TokenPointerRange( pCode, nLen); maPointerRange[0] = TokenPointerRange( pCode, nLen);
maPointerRange[1] = TokenPointerRange( pRPN, nRPN); maPointerRange[1] = TokenPointerRange( pRPN, nRPN);
} }
static bool skipToken( size_t i, const FormulaToken* const * pp ) bool skipToken( size_t i, const FormulaToken* const * pp )
{ {
// Handle all tokens in RPN, and code tokens only if they have a // Handle all tokens in RPN, and code tokens only if they have a
// reference count of 1, which means they are not referenced in // reference count of 1, which means they are not referenced in
...@@ -141,19 +144,22 @@ namespace ...@@ -141,19 +144,22 @@ namespace
if (i == 0) if (i == 0)
return (*pp)->GetRef() > 1; return (*pp)->GetRef() > 1;
// Skip (do not adjust) relative references resulting from named if (mbSkipRelName)
// expressions.
switch ((*pp)->GetType())
{ {
case svSingleRef: // Skip (do not adjust) relative references resulting from
return (*pp)->GetSingleRef()->IsRelName(); // named expressions.
case svDoubleRef: switch ((*pp)->GetType())
{ {
const ScComplexRefData& rRef = *(*pp)->GetDoubleRef(); case svSingleRef:
return rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName(); return (*pp)->GetSingleRef()->IsRelName();
} case svDoubleRef:
default: {
; // nothing const ScComplexRefData& rRef = *(*pp)->GetDoubleRef();
return rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName();
}
default:
; // nothing
}
} }
return false; return false;
...@@ -2208,48 +2214,57 @@ bool ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW& nExtend, ...@@ -2208,48 +2214,57 @@ bool ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW& nExtend,
void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos, void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos,
const ScAddress& rNewPos ) const ScAddress& rNewPos )
{ {
for ( sal_uInt16 j=0; j<nLen; ++j ) TokenPointers aPtrs( pCode, nLen, pRPN, nRPN, false);
for (size_t j=0; j<2; ++j)
{ {
switch ( pCode[j]->GetType() ) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svDoubleRef : if (aPtrs.skipToken(j,p))
{ continue;
ScSingleRefData& rRef2 = *pCode[j]->GetSingleRef2();
// Also adjust if the reference is of the form Sheet1.A2:A3 switch ( (*p)->GetType() )
if ( rRef2.IsFlag3D() || pCode[j]->GetSingleRef()->IsFlag3D() )
{
ScAddress aAbs = rRef2.toAbs(rOldPos);
rRef2.SetAddress(aAbs, rNewPos);
}
}
// fall through
case svSingleRef :
{
ScSingleRefData& rRef1 = *pCode[j]->GetSingleRef();
if ( rRef1.IsFlag3D() )
{
ScAddress aAbs = rRef1.toAbs(rOldPos);
rRef1.SetAddress(aAbs, rNewPos);
}
}
break;
case svExternalDoubleRef :
{
ScSingleRefData& rRef2 = *pCode[j]->GetSingleRef2();
ScAddress aAbs = rRef2.toAbs(rOldPos);
rRef2.SetAddress(aAbs, rNewPos);
}
// fall through
case svExternalSingleRef :
{
ScSingleRefData& rRef1 = *pCode[j]->GetSingleRef();
ScAddress aAbs = rRef1.toAbs(rOldPos);
rRef1.SetAddress(aAbs, rNewPos);
}
break;
default:
{ {
// added to avoid warnings case svDoubleRef :
{
ScSingleRefData& rRef2 = *(*p)->GetSingleRef2();
// Also adjust if the reference is of the form Sheet1.A2:A3
if ( rRef2.IsFlag3D() || (*p)->GetSingleRef()->IsFlag3D() )
{
ScAddress aAbs = rRef2.toAbs(rOldPos);
rRef2.SetAddress(aAbs, rNewPos);
}
}
// fall through
case svSingleRef :
{
ScSingleRefData& rRef1 = *(*p)->GetSingleRef();
if ( rRef1.IsFlag3D() )
{
ScAddress aAbs = rRef1.toAbs(rOldPos);
rRef1.SetAddress(aAbs, rNewPos);
}
}
break;
case svExternalDoubleRef :
{
ScSingleRefData& rRef2 = *(*p)->GetSingleRef2();
ScAddress aAbs = rRef2.toAbs(rOldPos);
rRef2.SetAddress(aAbs, rNewPos);
}
// fall through
case svExternalSingleRef :
{
ScSingleRefData& rRef1 = *(*p)->GetSingleRef();
ScAddress aAbs = rRef1.toAbs(rOldPos);
rRef1.SetAddress(aAbs, rNewPos);
}
break;
default:
{
// added to avoid warnings
}
} }
} }
} }
...@@ -2380,43 +2395,53 @@ void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument* pOldDoc, cons ...@@ -2380,43 +2395,53 @@ void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument* pOldDoc, cons
} }
} }
void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddress& rOldPos, const ScAddress& rNewPos, bool bRangeName, bool bCheckCopyRange) void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddress& rOldPos, const ScAddress& rNewPos,
bool bRangeName, bool bCheckCopyRange)
{ {
for ( sal_uInt16 j=0; j<nLen; ++j ) TokenPointers aPtrs( pCode, nLen, pRPN, nRPN, !bRangeName);
for (size_t j=0; j<2; ++j)
{ {
switch ( pCode[j]->GetType() ) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svDoubleRef : if (aPtrs.skipToken(j,p))
{ continue;
if (!SkipReference(pCode[j], rOldPos, pOldDoc, false, bCheckCopyRange))
continue;
ScComplexRefData& rRef = *pCode[j]->GetDoubleRef();
ScSingleRefData& rRef2 = rRef.Ref2;
ScSingleRefData& rRef1 = rRef.Ref1;
// for range names only adjust if all parts are absolute switch ( (*p)->GetType() )
if (!bRangeName || !(rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel()))
AdjustSingleRefData( rRef1, rOldPos, rNewPos );
if (!bRangeName || !(rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel()))
AdjustSingleRefData( rRef2, rOldPos, rNewPos );
}
break;
case svSingleRef :
{ {
if (!SkipReference(pCode[j], rOldPos, pOldDoc, false, bCheckCopyRange)) case svDoubleRef :
continue; {
if (!SkipReference((*p), rOldPos, pOldDoc, false, bCheckCopyRange))
continue;
ScComplexRefData& rRef = *(*p)->GetDoubleRef();
ScSingleRefData& rRef2 = rRef.Ref2;
ScSingleRefData& rRef1 = rRef.Ref1;
// for range names only adjust if all parts are absolute
if (!bRangeName || !(rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel()))
AdjustSingleRefData( rRef1, rOldPos, rNewPos );
if (!bRangeName || !(rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel()))
AdjustSingleRefData( rRef2, rOldPos, rNewPos );
}
break;
case svSingleRef :
{
if (!SkipReference((*p), rOldPos, pOldDoc, false, bCheckCopyRange))
continue;
ScSingleRefData& rRef = *pCode[j]->GetSingleRef(); ScSingleRefData& rRef = *(*p)->GetSingleRef();
// for range names only adjust if all parts are absolute // for range names only adjust if all parts are absolute
if (!bRangeName || !(rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel())) if (!bRangeName || !(rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel()))
AdjustSingleRefData( rRef, rOldPos, rNewPos ); AdjustSingleRefData( rRef, rOldPos, rNewPos );
} }
break; break;
default: default:
{ {
// added to avoid warnings // added to avoid warnings
}
} }
} }
} }
...@@ -2747,150 +2772,157 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon ...@@ -2747,150 +2772,157 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
if (bCellShifted) if (bCellShifted)
aNewPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); aNewPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
FormulaToken** p = pCode; TokenPointers aPtrs( pCode, nLen, pRPN, nRPN);
FormulaToken** pEnd = p + static_cast<size_t>(nLen); for (size_t j=0; j<2; ++j)
for (; p != pEnd; ++p)
{ {
switch ((*p)->GetType()) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svSingleRef: if (aPtrs.skipToken(j,p))
{ continue;
formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
if (rCxt.isDeleted() && aSelectedRange.In(aAbs))
{
// This reference is in the deleted region.
setRefDeleted(rRef, rCxt);
aRes.mbValueChanged = true;
break;
}
if (!rCxt.isDeleted() && rRef.IsDeleted()) switch ((*p)->GetType())
{ {
// Check if the token has reference to previously deleted region. case svSingleRef:
ScAddress aCheckPos = rRef.toAbs(aNewPos);
if (rCxt.maRange.In(aCheckPos))
{ {
restoreDeletedRef(rRef, rCxt); formula::FormulaToken* pToken = *p;
aRes.mbValueChanged = true; ScSingleRefData& rRef = *pToken->GetSingleRef();
break; ScAddress aAbs = rRef.toAbs(rOldPos);
}
}
if (rCxt.maRange.In(aAbs)) if (rCxt.isDeleted() && aSelectedRange.In(aAbs))
{ {
aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); // This reference is in the deleted region.
aRes.mbReferenceModified = true; setRefDeleted(rRef, rCxt);
} aRes.mbValueChanged = true;
break;
}
rRef.SetAddress(aAbs, aNewPos); if (!rCxt.isDeleted() && rRef.IsDeleted())
} {
break; // Check if the token has reference to previously deleted region.
case svDoubleRef: ScAddress aCheckPos = rRef.toAbs(aNewPos);
{ if (rCxt.maRange.In(aCheckPos))
formula::FormulaToken* pToken = *p; {
ScComplexRefData& rRef = *pToken->GetDoubleRef(); restoreDeletedRef(rRef, rCxt);
ScRange aAbs = rRef.toAbs(rOldPos); aRes.mbValueChanged = true;
break;
}
}
if (rCxt.isDeleted()) if (rCxt.maRange.In(aAbs))
{ {
if (aSelectedRange.In(aAbs)) aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
{ aRes.mbReferenceModified = true;
// This reference is in the deleted region. }
setRefDeleted(rRef, rCxt);
aRes.mbValueChanged = true; rRef.SetAddress(aAbs, aNewPos);
break;
} }
else if (aSelectedRange.Intersects(aAbs)) break;
case svDoubleRef:
{ {
if (shrinkRange(rCxt, aAbs, aSelectedRange)) formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
if (rCxt.isDeleted())
{ {
// The reference range has been shrunk. if (aSelectedRange.In(aAbs))
rRef.SetRange(aAbs, aNewPos); {
aRes.mbValueChanged = true; // This reference is in the deleted region.
setRefDeleted(rRef, rCxt);
aRes.mbValueChanged = true;
break;
}
else if (aSelectedRange.Intersects(aAbs))
{
if (shrinkRange(rCxt, aAbs, aSelectedRange))
{
// The reference range has been shrunk.
rRef.SetRange(aAbs, aNewPos);
aRes.mbValueChanged = true;
aRes.mbReferenceModified = true;
break;
}
}
}
if (rCxt.isInserted())
{
if (expandRange(rCxt, aAbs, aSelectedRange))
{
// The reference range has been expanded.
rRef.SetRange(aAbs, aNewPos);
aRes.mbValueChanged = true;
aRes.mbReferenceModified = true;
break;
}
if (expandRangeByEdge(rCxt, aAbs, aSelectedRange))
{
// The reference range has been expanded on the edge.
rRef.SetRange(aAbs, aNewPos);
aRes.mbValueChanged = true;
aRes.mbReferenceModified = true;
break;
}
}
if (rCxt.maRange.In(aAbs))
{
aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
aRes.mbReferenceModified = true; aRes.mbReferenceModified = true;
break;
} }
} else if (rCxt.maRange.Intersects(aAbs))
} {
// Part of the referenced range is being shifted. This
// will change the values of the range.
aRes.mbValueChanged = true;
}
if (rCxt.isInserted())
{
if (expandRange(rCxt, aAbs, aSelectedRange))
{
// The reference range has been expanded.
rRef.SetRange(aAbs, aNewPos); rRef.SetRange(aAbs, aNewPos);
aRes.mbValueChanged = true;
aRes.mbReferenceModified = true;
break;
} }
break;
if (expandRangeByEdge(rCxt, aAbs, aSelectedRange)) case svExternalSingleRef:
{
// For external reference, just reset the reference with
// respect to the new cell position.
formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
rRef.SetAddress(aAbs, aNewPos);
}
break;
case svExternalDoubleRef:
{ {
// The reference range has been expanded on the edge. // Same as above.
formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
rRef.SetRange(aAbs, aNewPos); rRef.SetRange(aAbs, aNewPos);
aRes.mbValueChanged = true;
aRes.mbReferenceModified = true;
break;
} }
} break;
case svIndex:
if (rCxt.maRange.In(aAbs)) {
{ switch ((*p)->GetOpCode())
aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); {
aRes.mbReferenceModified = true; case ocName:
} if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
else if (rCxt.maRange.Intersects(aAbs)) aRes.mbNameModified = true;
{ break;
// Part of the referenced range is being shifted. This case ocDBArea:
// will change the values of the range. case ocTableRef:
aRes.mbValueChanged = true; if (isDBDataModified(rCxt.mrDoc, **p))
} aRes.mbNameModified = true;
break;
rRef.SetRange(aAbs, aNewPos); default:
} ; // nothing
break; }
case svExternalSingleRef: }
{ break;
// For external reference, just reset the reference with default:
// respect to the new cell position. ;
formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
rRef.SetAddress(aAbs, aNewPos);
}
break;
case svExternalDoubleRef:
{
// Same as above.
formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
rRef.SetRange(aAbs, aNewPos);
}
break;
case svIndex:
{
switch ((*p)->GetOpCode())
{
case ocName:
if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
aRes.mbNameModified = true;
break;
case ocDBArea:
case ocTableRef:
if (isDBDataModified(rCxt.mrDoc, **p))
aRes.mbNameModified = true;
break;
default:
; // nothing
}
} }
break;
default:
;
} }
} }
...@@ -2920,7 +2952,7 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove( ...@@ -2920,7 +2952,7 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove(
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop; FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p) for (; p != pEnd; ++p)
{ {
if (TokenPointers::skipToken(j,p)) if (aPtrs.skipToken(j,p))
continue; continue;
switch ((*p)->GetType()) switch ((*p)->GetType())
...@@ -3269,111 +3301,118 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceInName( ...@@ -3269,111 +3301,118 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceInName(
sc::RefUpdateResult aRes; sc::RefUpdateResult aRes;
FormulaToken** p = pCode; TokenPointers aPtrs( pCode, nLen, pRPN, nRPN);
FormulaToken** pEnd = p + static_cast<size_t>(nLen); for (size_t j=0; j<2; ++j)
for (; p != pEnd; ++p)
{ {
switch ((*p)->GetType()) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svSingleRef: if (aPtrs.skipToken(j,p))
{ continue;
formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef(); switch ((*p)->GetType())
if (adjustSingleRefInName(rRef, rCxt, rPos))
aRes.mbReferenceModified = true;
}
break;
case svDoubleRef:
{ {
formula::FormulaToken* pToken = *p; case svSingleRef:
ScComplexRefData& rRef = *pToken->GetDoubleRef(); {
ScRange aAbs = rRef.toAbs(rPos); formula::FormulaToken* pToken = *p;
if (rCxt.maRange.In(aAbs)) ScSingleRefData& rRef = *pToken->GetSingleRef();
{ if (adjustSingleRefInName(rRef, rCxt, rPos))
// This range is entirely within the shifted region. aRes.mbReferenceModified = true;
if (adjustDoubleRefInName(rRef, rCxt, rPos)) }
aRes.mbReferenceModified = true; break;
} case svDoubleRef:
else if (rCxt.mnRowDelta < 0) {
{ formula::FormulaToken* pToken = *p;
// row(s) deleted. ScComplexRefData& rRef = *pToken->GetDoubleRef();
if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel()) ScRange aAbs = rRef.toAbs(rPos);
// Don't modify relative references in names. if (rCxt.maRange.In(aAbs))
break; {
// This range is entirely within the shifted region.
if (adjustDoubleRefInName(rRef, rCxt, rPos))
aRes.mbReferenceModified = true;
}
else if (rCxt.mnRowDelta < 0)
{
// row(s) deleted.
if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel())
// Don't modify relative references in names.
break;
if (aAbs.aStart.Col() < rCxt.maRange.aStart.Col() || rCxt.maRange.aEnd.Col() < aAbs.aEnd.Col()) if (aAbs.aStart.Col() < rCxt.maRange.aStart.Col() || rCxt.maRange.aEnd.Col() < aAbs.aEnd.Col())
// column range of the reference is not entirely in the deleted column range. // column range of the reference is not entirely in the deleted column range.
break; break;
if (aAbs.aStart.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.aEnd.Tab() < rCxt.maRange.aStart.Tab()) if (aAbs.aStart.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.aEnd.Tab() < rCxt.maRange.aStart.Tab())
// wrong tables // wrong tables
break; break;
ScRange aDeleted = rCxt.maRange; ScRange aDeleted = rCxt.maRange;
aDeleted.aStart.IncRow(rCxt.mnRowDelta); aDeleted.aStart.IncRow(rCxt.mnRowDelta);
aDeleted.aEnd.SetRow(aDeleted.aStart.Row()-rCxt.mnRowDelta-1); aDeleted.aEnd.SetRow(aDeleted.aStart.Row()-rCxt.mnRowDelta-1);
if (aAbs.aEnd.Row() < aDeleted.aStart.Row() || aDeleted.aEnd.Row() < aAbs.aStart.Row()) if (aAbs.aEnd.Row() < aDeleted.aStart.Row() || aDeleted.aEnd.Row() < aAbs.aStart.Row())
// reference range doesn't intersect with the deleted range. // reference range doesn't intersect with the deleted range.
break; break;
if (aDeleted.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= aDeleted.aEnd.Row()) if (aDeleted.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= aDeleted.aEnd.Row())
{ {
// This reference is entirely deleted. // This reference is entirely deleted.
rRef.Ref1.SetRowDeleted(true); rRef.Ref1.SetRowDeleted(true);
rRef.Ref2.SetRowDeleted(true); rRef.Ref2.SetRowDeleted(true);
aRes.mbReferenceModified = true; aRes.mbReferenceModified = true;
break; break;
} }
if (aAbs.aStart.Row() < aDeleted.aStart.Row()) if (aAbs.aStart.Row() < aDeleted.aStart.Row())
{ {
if (aDeleted.aEnd.Row() < aAbs.aEnd.Row()) if (aDeleted.aEnd.Row() < aAbs.aEnd.Row())
// Deleted in the middle. Make the reference shorter. // Deleted in the middle. Make the reference shorter.
rRef.Ref2.IncRow(rCxt.mnRowDelta); rRef.Ref2.IncRow(rCxt.mnRowDelta);
else else
// Deleted at tail end. Cut off the lower part. // Deleted at tail end. Cut off the lower part.
rRef.Ref2.SetAbsRow(aDeleted.aStart.Row()-1); rRef.Ref2.SetAbsRow(aDeleted.aStart.Row()-1);
} }
else else
{ {
// Deleted at the top. Cut the top off and shift up. // Deleted at the top. Cut the top off and shift up.
rRef.Ref1.SetAbsRow(aDeleted.aEnd.Row()+1); rRef.Ref1.SetAbsRow(aDeleted.aEnd.Row()+1);
rRef.Ref1.IncRow(rCxt.mnRowDelta); rRef.Ref1.IncRow(rCxt.mnRowDelta);
rRef.Ref2.IncRow(rCxt.mnRowDelta); rRef.Ref2.IncRow(rCxt.mnRowDelta);
} }
aRes.mbReferenceModified = true;
}
else if (rCxt.maRange.Intersects(aAbs))
{
if (rCxt.mnColDelta && rCxt.maRange.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= rCxt.maRange.aEnd.Row())
{
if (adjustDoubleRefInName(rRef, rCxt, rPos))
aRes.mbReferenceModified = true; aRes.mbReferenceModified = true;
}
else if (rCxt.maRange.Intersects(aAbs))
{
if (rCxt.mnColDelta && rCxt.maRange.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= rCxt.maRange.aEnd.Row())
{
if (adjustDoubleRefInName(rRef, rCxt, rPos))
aRes.mbReferenceModified = true;
}
if (rCxt.mnRowDelta && rCxt.maRange.aStart.Col() <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= rCxt.maRange.aEnd.Col())
{
if (adjustDoubleRefInName(rRef, rCxt, rPos))
aRes.mbReferenceModified = true;
}
}
else if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs())
{
// Check if we could expand range reference by the bottom
// edge. For named expressions, we only expand absolute
// references.
if (!rRef.Ref1.IsRowRel() && !rRef.Ref2.IsRowRel() && aAbs.aEnd.Row()+1 == rCxt.maRange.aStart.Row())
{
// Expand by the bottom edge.
rRef.Ref2.IncRow(rCxt.mnRowDelta);
aRes.mbReferenceModified = true;
}
}
} }
if (rCxt.mnRowDelta && rCxt.maRange.aStart.Col() <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= rCxt.maRange.aEnd.Col()) break;
{ default:
if (adjustDoubleRefInName(rRef, rCxt, rPos)) ;
aRes.mbReferenceModified = true;
}
}
else if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs())
{
// Check if we could expand range reference by the bottom
// edge. For named expressions, we only expand absolute
// references.
if (!rRef.Ref1.IsRowRel() && !rRef.Ref2.IsRowRel() && aAbs.aEnd.Row()+1 == rCxt.maRange.aStart.Row())
{
// Expand by the bottom edge.
rRef.Ref2.IncRow(rCxt.mnRowDelta);
aRes.mbReferenceModified = true;
}
}
} }
break;
default:
;
} }
} }
...@@ -3391,49 +3430,56 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceInMovedName( const sc::RefUpdat ...@@ -3391,49 +3430,56 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceInMovedName( const sc::RefUpdat
sc::RefUpdateResult aRes; sc::RefUpdateResult aRes;
FormulaToken** p = pCode; TokenPointers aPtrs( pCode, nLen, pRPN, nRPN);
FormulaToken** pEnd = p + static_cast<size_t>(nLen); for (size_t j=0; j<2; ++j)
for (; p != pEnd; ++p)
{ {
switch ((*p)->GetType()) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svSingleRef: if (aPtrs.skipToken(j,p))
continue;
switch ((*p)->GetType())
{ {
formula::FormulaToken* pToken = *p; case svSingleRef:
ScSingleRefData& rRef = *pToken->GetSingleRef(); {
if (rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel()) formula::FormulaToken* pToken = *p;
continue; ScSingleRefData& rRef = *pToken->GetSingleRef();
if (rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel())
continue;
ScAddress aAbs = rRef.toAbs(rPos); ScAddress aAbs = rRef.toAbs(rPos);
if (aOldRange.In(aAbs)) if (aOldRange.In(aAbs))
{ {
aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
aRes.mbReferenceModified = true; aRes.mbReferenceModified = true;
} }
rRef.SetAddress(aAbs, rPos); rRef.SetAddress(aAbs, rPos);
} }
break; break;
case svDoubleRef: case svDoubleRef:
{ {
formula::FormulaToken* pToken = *p; formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef(); ScComplexRefData& rRef = *pToken->GetDoubleRef();
if (rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() || rRef.Ref1.IsTabRel() || if (rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() || rRef.Ref1.IsTabRel() ||
rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() || rRef.Ref2.IsTabRel()) rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() || rRef.Ref2.IsTabRel())
continue; continue;
ScRange aAbs = rRef.toAbs(rPos); ScRange aAbs = rRef.toAbs(rPos);
if (aOldRange.In(aAbs)) if (aOldRange.In(aAbs))
{ {
aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta); aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
aRes.mbReferenceModified = true; aRes.mbReferenceModified = true;
} }
rRef.SetRange(aAbs, rPos); rRef.SetRange(aAbs, rPos);
}
break;
default:
;
} }
break;
default:
;
} }
} }
...@@ -3533,47 +3579,54 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnDeletedTab( sc::RefUpdateDele ...@@ -3533,47 +3579,54 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnDeletedTab( sc::RefUpdateDele
if (rCxt.mnDeletePos < rOldPos.Tab()) if (rCxt.mnDeletePos < rOldPos.Tab())
aNewPos.IncTab(-1*rCxt.mnSheets); aNewPos.IncTab(-1*rCxt.mnSheets);
FormulaToken** p = pCode; TokenPointers aPtrs( pCode, nLen, pRPN, nRPN);
FormulaToken** pEnd = p + static_cast<size_t>(nLen); for (size_t j=0; j<2; ++j)
for (; p != pEnd; ++p)
{ {
switch ((*p)->GetType()) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svSingleRef: if (aPtrs.skipToken(j,p))
{ continue;
formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef(); switch ((*p)->GetType())
if (adjustSingleRefOnDeletedTab(rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos))
aRes.mbReferenceModified = true;
}
break;
case svDoubleRef:
{
formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef();
aRes.mbReferenceModified |= adjustDoubleRefOnDeleteTab(rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos);
}
break;
case svIndex:
{ {
switch ((*p)->GetOpCode()) case svSingleRef:
{ {
case ocName: formula::FormulaToken* pToken = *p;
if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p)) ScSingleRefData& rRef = *pToken->GetSingleRef();
aRes.mbNameModified = true; if (adjustSingleRefOnDeletedTab(rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos))
break; aRes.mbReferenceModified = true;
case ocDBArea: }
case ocTableRef: break;
if (isDBDataModified(rCxt.mrDoc, **p)) case svDoubleRef:
aRes.mbNameModified = true; {
break; formula::FormulaToken* pToken = *p;
default: ScComplexRefData& rRef = *pToken->GetDoubleRef();
; // nothing aRes.mbReferenceModified |= adjustDoubleRefOnDeleteTab(rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos);
} }
break;
case svIndex:
{
switch ((*p)->GetOpCode())
{
case ocName:
if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
aRes.mbNameModified = true;
break;
case ocDBArea:
case ocTableRef:
if (isDBDataModified(rCxt.mrDoc, **p))
aRes.mbNameModified = true;
break;
default:
; // nothing
}
}
break;
default:
;
} }
break;
default:
;
} }
} }
return aRes; return aRes;
...@@ -3586,50 +3639,57 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnInsertedTab( sc::RefUpdateIns ...@@ -3586,50 +3639,57 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnInsertedTab( sc::RefUpdateIns
if (rCxt.mnInsertPos <= rOldPos.Tab()) if (rCxt.mnInsertPos <= rOldPos.Tab())
aNewPos.IncTab(rCxt.mnSheets); aNewPos.IncTab(rCxt.mnSheets);
FormulaToken** p = pCode; TokenPointers aPtrs( pCode, nLen, pRPN, nRPN);
FormulaToken** pEnd = p + static_cast<size_t>(nLen); for (size_t j=0; j<2; ++j)
for (; p != pEnd; ++p)
{ {
switch ((*p)->GetType()) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svSingleRef: if (aPtrs.skipToken(j,p))
{ continue;
formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef(); switch ((*p)->GetType())
if (adjustSingleRefOnInsertedTab(rRef, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
aRes.mbReferenceModified = true;
}
break;
case svDoubleRef:
{
formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef();
if (adjustSingleRefOnInsertedTab(rRef.Ref1, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
aRes.mbReferenceModified = true;
if (adjustSingleRefOnInsertedTab(rRef.Ref2, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
aRes.mbReferenceModified = true;
}
break;
case svIndex:
{ {
switch ((*p)->GetOpCode()) case svSingleRef:
{ {
case ocName: formula::FormulaToken* pToken = *p;
if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p)) ScSingleRefData& rRef = *pToken->GetSingleRef();
aRes.mbNameModified = true; if (adjustSingleRefOnInsertedTab(rRef, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
break; aRes.mbReferenceModified = true;
case ocDBArea: }
case ocTableRef: break;
if (isDBDataModified(rCxt.mrDoc, **p)) case svDoubleRef:
aRes.mbNameModified = true; {
break; formula::FormulaToken* pToken = *p;
default: ScComplexRefData& rRef = *pToken->GetDoubleRef();
; // nothing if (adjustSingleRefOnInsertedTab(rRef.Ref1, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
} aRes.mbReferenceModified = true;
if (adjustSingleRefOnInsertedTab(rRef.Ref2, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
aRes.mbReferenceModified = true;
}
break;
case svIndex:
{
switch ((*p)->GetOpCode())
{
case ocName:
if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
aRes.mbNameModified = true;
break;
case ocDBArea:
case ocTableRef:
if (isDBDataModified(rCxt.mrDoc, **p))
aRes.mbNameModified = true;
break;
default:
; // nothing
}
}
break;
default:
;
} }
break;
default:
;
} }
} }
return aRes; return aRes;
...@@ -3659,54 +3719,61 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa ...@@ -3659,54 +3719,61 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa
if (adjustTabOnMove(aNewPos, rCxt)) if (adjustTabOnMove(aNewPos, rCxt))
aRes.mbReferenceModified = true; aRes.mbReferenceModified = true;
FormulaToken** p = pCode; TokenPointers aPtrs( pCode, nLen, pRPN, nRPN);
FormulaToken** pEnd = p + static_cast<size_t>(nLen); for (size_t j=0; j<2; ++j)
for (; p != pEnd; ++p)
{ {
switch ((*p)->GetType()) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svSingleRef: if (aPtrs.skipToken(j,p))
{ continue;
formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef(); switch ((*p)->GetType())
ScAddress aAbs = rRef.toAbs(rOldPos);
if (adjustTabOnMove(aAbs, rCxt))
aRes.mbReferenceModified = true;
rRef.SetAddress(aAbs, aNewPos);
}
break;
case svDoubleRef:
{
formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
if (adjustTabOnMove(aAbs.aStart, rCxt))
aRes.mbReferenceModified = true;
if (adjustTabOnMove(aAbs.aEnd, rCxt))
aRes.mbReferenceModified = true;
rRef.SetRange(aAbs, aNewPos);
}
break;
case svIndex:
{ {
switch ((*p)->GetOpCode()) case svSingleRef:
{ {
case ocName: formula::FormulaToken* pToken = *p;
if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p)) ScSingleRefData& rRef = *pToken->GetSingleRef();
aRes.mbNameModified = true; ScAddress aAbs = rRef.toAbs(rOldPos);
break; if (adjustTabOnMove(aAbs, rCxt))
case ocDBArea: aRes.mbReferenceModified = true;
case ocTableRef: rRef.SetAddress(aAbs, aNewPos);
if (isDBDataModified(rCxt.mrDoc, **p)) }
aRes.mbNameModified = true; break;
break; case svDoubleRef:
default: {
; // nothing formula::FormulaToken* pToken = *p;
} ScComplexRefData& rRef = *pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
if (adjustTabOnMove(aAbs.aStart, rCxt))
aRes.mbReferenceModified = true;
if (adjustTabOnMove(aAbs.aEnd, rCxt))
aRes.mbReferenceModified = true;
rRef.SetRange(aAbs, aNewPos);
}
break;
case svIndex:
{
switch ((*p)->GetOpCode())
{
case ocName:
if (isNameModified(rCxt.maUpdatedNames, rOldPos.Tab(), **p))
aRes.mbNameModified = true;
break;
case ocDBArea:
case ocTableRef:
if (isDBDataModified(rCxt.mrDoc, **p))
aRes.mbNameModified = true;
break;
default:
; // nothing
}
}
break;
default:
;
} }
break;
default:
;
} }
} }
...@@ -3715,75 +3782,89 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa ...@@ -3715,75 +3782,89 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa
void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const ScAddress& rNewPos ) void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const ScAddress& rNewPos )
{ {
FormulaToken** p = pCode; TokenPointers aPtrs( pCode, nLen, pRPN, nRPN);
FormulaToken** pEnd = p + static_cast<size_t>(nLen); for (size_t j=0; j<2; ++j)
for (; p != pEnd; ++p)
{ {
switch ((*p)->GetType()) FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svSingleRef: if (aPtrs.skipToken(j,p))
case svExternalSingleRef: continue;
{
formula::FormulaToken* pToken = *p; switch ((*p)->GetType())
ScSingleRefData& rRef = *pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
rRef.SetAddress(aAbs, rNewPos);
}
break;
case svDoubleRef:
case svExternalDoubleRef:
{ {
formula::FormulaToken* pToken = *p; case svSingleRef:
ScComplexRefData& rRef = *pToken->GetDoubleRef(); case svExternalSingleRef:
ScRange aAbs = rRef.toAbs(rOldPos); {
rRef.SetRange(aAbs, rNewPos); formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
rRef.SetAddress(aAbs, rNewPos);
}
break;
case svDoubleRef:
case svExternalDoubleRef:
{
formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
rRef.SetRange(aAbs, rNewPos);
}
break;
default:
;
} }
break;
default:
;
} }
} }
} }
void ScTokenArray::AdjustReferenceOnMovedOriginIfOtherSheet( const ScAddress& rOldPos, const ScAddress& rNewPos ) void ScTokenArray::AdjustReferenceOnMovedOriginIfOtherSheet( const ScAddress& rOldPos, const ScAddress& rNewPos )
{ {
FormulaToken** p = pCode; TokenPointers aPtrs( pCode, nLen, pRPN, nRPN);
FormulaToken** pEnd = p + static_cast<size_t>(nLen); for (size_t j=0; j<2; ++j)
for (; p != pEnd; ++p)
{ {
bool bAdjust = false; FormulaToken** p = aPtrs.maPointerRange[j].mpStart;
switch ((*p)->GetType()) FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p)
{ {
case svExternalSingleRef: if (aPtrs.skipToken(j,p))
bAdjust = true; // always continue;
// fallthru
case svSingleRef: bool bAdjust = false;
{ switch ((*p)->GetType())
formula::FormulaToken* pToken = *p;
ScSingleRefData& rRef = *pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
if (!bAdjust)
bAdjust = (aAbs.Tab() != rOldPos.Tab());
if (bAdjust)
rRef.SetAddress(aAbs, rNewPos);
}
break;
case svExternalDoubleRef:
bAdjust = true; // always
// fallthru
case svDoubleRef:
{ {
formula::FormulaToken* pToken = *p; case svExternalSingleRef:
ScComplexRefData& rRef = *pToken->GetDoubleRef(); bAdjust = true; // always
ScRange aAbs = rRef.toAbs(rOldPos); // fallthru
if (!bAdjust) case svSingleRef:
bAdjust = (rOldPos.Tab() < aAbs.aStart.Tab() || aAbs.aEnd.Tab() < rOldPos.Tab()); {
if (bAdjust) formula::FormulaToken* pToken = *p;
rRef.SetRange(aAbs, rNewPos); ScSingleRefData& rRef = *pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
if (!bAdjust)
bAdjust = (aAbs.Tab() != rOldPos.Tab());
if (bAdjust)
rRef.SetAddress(aAbs, rNewPos);
}
break;
case svExternalDoubleRef:
bAdjust = true; // always
// fallthru
case svDoubleRef:
{
formula::FormulaToken* pToken = *p;
ScComplexRefData& rRef = *pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
if (!bAdjust)
bAdjust = (rOldPos.Tab() < aAbs.aStart.Tab() || aAbs.aEnd.Tab() < rOldPos.Tab());
if (bAdjust)
rRef.SetRange(aAbs, rNewPos);
}
break;
default:
;
} }
break;
default:
;
} }
} }
} }
...@@ -3911,7 +3992,7 @@ void ScTokenArray::CheckRelativeReferenceBounds( ...@@ -3911,7 +3992,7 @@ void ScTokenArray::CheckRelativeReferenceBounds(
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop; FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p) for (; p != pEnd; ++p)
{ {
if (TokenPointers::skipToken(j,p)) if (aPtrs.skipToken(j,p))
continue; continue;
switch ((*p)->GetType()) switch ((*p)->GetType())
...@@ -3947,7 +4028,7 @@ void ScTokenArray::CheckRelativeReferenceBounds( ...@@ -3947,7 +4028,7 @@ void ScTokenArray::CheckRelativeReferenceBounds(
FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop; FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p) for (; p != pEnd; ++p)
{ {
if (TokenPointers::skipToken(j,p)) if (aPtrs.skipToken(j,p))
continue; continue;
switch ((*p)->GetType()) switch ((*p)->GetType())
...@@ -3985,7 +4066,7 @@ void ScTokenArray::CheckExpandReferenceBounds( ...@@ -3985,7 +4066,7 @@ void ScTokenArray::CheckExpandReferenceBounds(
const FormulaToken* const * pEnd = aPtrs.maPointerRange[j].mpStop; const FormulaToken* const * pEnd = aPtrs.maPointerRange[j].mpStop;
for (; p != pEnd; ++p) for (; p != pEnd; ++p)
{ {
if (TokenPointers::skipToken(j,p)) if (aPtrs.skipToken(j,p))
continue; continue;
switch ((*p)->GetType()) switch ((*p)->GetType())
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment