| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| |
| |
| #include <IShellCursorSupplier.hxx> |
| #include <txtftn.hxx> |
| #include <fmtanchr.hxx> |
| #include <ftnidx.hxx> |
| #include <frmfmt.hxx> |
| #include <doc.hxx> |
| #include <UndoManager.hxx> |
| #include <docary.hxx> |
| #include <swundo.hxx> // fuer die UndoIds |
| #include <pam.hxx> |
| #include <ndtxt.hxx> |
| #include <UndoCore.hxx> |
| #include <rolbck.hxx> |
| #include <ndnotxt.hxx> |
| #include <IMark.hxx> |
| #include <mvsave.hxx> |
| #include <redline.hxx> |
| #include <crossrefbookmark.hxx> |
| #include <undo.hrc> |
| #include <comcore.hrc> |
| #include <docsh.hxx> |
| |
| class SwRedlineSaveData: public SwUndRng, public SwRedlineData, private SwUndoSaveSection |
| { |
| public: |
| SwRedlineSaveData( |
| SwComparePosition eCmpPos, |
| const SwPosition& rSttPos, |
| const SwPosition& rEndPos, |
| SwRedline& rRedl, |
| sal_Bool bCopyNext ); |
| |
| ~SwRedlineSaveData(); |
| |
| void RedlineToDoc( SwPaM& rPam ); |
| |
| SwNodeIndex* GetMvSttIdx() const |
| { |
| return SwUndoSaveSection::GetMvSttIdx(); |
| } |
| |
| #ifdef DBG_UTIL |
| sal_uInt16 nRedlineCount; |
| #endif |
| }; |
| |
| SV_IMPL_PTRARR( SwRedlineSaveDatas, SwRedlineSaveDataPtr ) |
| |
| |
| //------------------------------------------------------------ |
| |
| // Diese Klasse speichert den Pam als sal_uInt16's und kann diese wieder zu |
| |
| // einem PaM zusammensetzen |
| SwUndRng::SwUndRng() |
| : nSttNode( 0 ), nEndNode( 0 ), nSttCntnt( 0 ), nEndCntnt( 0 ) |
| { |
| } |
| |
| SwUndRng::SwUndRng( const SwPaM& rPam ) |
| { |
| SetValues( rPam ); |
| } |
| |
| void SwUndRng::SetValues( const SwPaM& rPam ) |
| { |
| const SwPosition *pStt = rPam.Start(); |
| if( rPam.HasMark() ) |
| { |
| const SwPosition *pEnd = rPam.GetPoint() == pStt |
| ? rPam.GetMark() |
| : rPam.GetPoint(); |
| nEndNode = pEnd->nNode.GetIndex(); |
| nEndCntnt = pEnd->nContent.GetIndex(); |
| } |
| else |
| // keine Selektion !! |
| nEndNode = 0, nEndCntnt = STRING_MAXLEN; |
| |
| nSttNode = pStt->nNode.GetIndex(); |
| nSttCntnt = pStt->nContent.GetIndex(); |
| } |
| |
| void SwUndRng::SetPaM( SwPaM & rPam, sal_Bool bCorrToCntnt ) const |
| { |
| rPam.DeleteMark(); |
| rPam.GetPoint()->nNode = nSttNode; |
| SwNode* pNd = rPam.GetNode(); |
| if( pNd->IsCntntNode() ) |
| rPam.GetPoint()->nContent.Assign( pNd->GetCntntNode(), nSttCntnt ); |
| else if( bCorrToCntnt ) |
| rPam.Move( fnMoveForward, fnGoCntnt ); |
| else |
| rPam.GetPoint()->nContent.Assign( 0, 0 ); |
| |
| if( !nEndNode && STRING_MAXLEN == nEndCntnt ) // keine Selection |
| return ; |
| |
| rPam.SetMark(); |
| if( nSttNode == nEndNode && nSttCntnt == nEndCntnt ) |
| return; // nichts mehr zu tun |
| |
| rPam.GetPoint()->nNode = nEndNode; |
| if( (pNd = rPam.GetNode())->IsCntntNode() ) |
| rPam.GetPoint()->nContent.Assign( pNd->GetCntntNode(), nEndCntnt ); |
| else if( bCorrToCntnt ) |
| rPam.Move( fnMoveBackward, fnGoCntnt ); |
| else |
| rPam.GetPoint()->nContent.Assign( 0, 0 ); |
| } |
| |
| SwPaM & SwUndRng::AddUndoRedoPaM( |
| ::sw::UndoRedoContext & rContext, bool const bCorrToCntnt) const |
| { |
| SwPaM & rPaM( rContext.GetCursorSupplier().CreateNewShellCursor() ); |
| SetPaM( rPaM, bCorrToCntnt ); |
| return rPaM; |
| } |
| |
| |
| //------------------------------------------------------------ |
| |
| |
| void SwUndo::RemoveIdxFromSection( SwDoc& rDoc, sal_uLong nSttIdx, |
| sal_uLong* pEndIdx ) |
| { |
| SwNodeIndex aIdx( rDoc.GetNodes(), nSttIdx ); |
| SwNodeIndex aEndIdx( rDoc.GetNodes(), pEndIdx ? *pEndIdx |
| : aIdx.GetNode().EndOfSectionIndex() ); |
| SwPosition aPos( rDoc.GetNodes().GetEndOfPostIts() ); |
| rDoc.CorrAbs( aIdx, aEndIdx, aPos, sal_True ); |
| } |
| |
| void SwUndo::RemoveIdxFromRange( SwPaM& rPam, sal_Bool bMoveNext ) |
| { |
| const SwPosition* pEnd = rPam.End(); |
| if( bMoveNext ) |
| { |
| if( pEnd != rPam.GetPoint() ) |
| rPam.Exchange(); |
| |
| SwNodeIndex aStt( rPam.GetMark()->nNode ); |
| SwNodeIndex aEnd( rPam.GetPoint()->nNode ); |
| |
| if( !rPam.Move( fnMoveForward ) ) |
| { |
| rPam.Exchange(); |
| if( !rPam.Move( fnMoveBackward ) ) |
| { |
| rPam.GetPoint()->nNode = rPam.GetDoc()->GetNodes().GetEndOfPostIts(); |
| rPam.GetPoint()->nContent.Assign( 0, 0 ); |
| } |
| } |
| |
| rPam.GetDoc()->CorrAbs( aStt, aEnd, *rPam.GetPoint(), sal_True ); |
| } |
| else |
| rPam.GetDoc()->CorrAbs( rPam, *pEnd, sal_True ); |
| } |
| |
| void SwUndo::RemoveIdxRel( sal_uLong nIdx, const SwPosition& rPos ) |
| { |
| // nur die Crsr verschieben; die Bookmarks/TOXMarks/.. werden vom |
| // entsp. JoinNext/JoinPrev erledigt! |
| SwNodeIndex aIdx( rPos.nNode.GetNode().GetNodes(), nIdx ); |
| ::PaMCorrRel( aIdx, rPos ); |
| } |
| |
| SwUndo::SwUndo(SwUndoId const nId) |
| : m_nId(nId), nOrigRedlineMode(nsRedlineMode_t::REDLINE_NONE), |
| bCacheComment(true), pComment(NULL) |
| { |
| } |
| |
| bool SwUndo::IsDelBox() const |
| { |
| return GetId() == UNDO_COL_DELETE || GetId() == UNDO_ROW_DELETE || |
| GetId() == UNDO_TABLE_DELBOX; |
| } |
| |
| SwUndo::~SwUndo() |
| { |
| delete pComment; |
| } |
| |
| |
| class UndoRedoRedlineGuard |
| { |
| public: |
| UndoRedoRedlineGuard(::sw::UndoRedoContext & rContext, SwUndo & rUndo) |
| : m_rRedlineAccess(rContext.GetDoc()) |
| , m_eMode(m_rRedlineAccess.GetRedlineMode()) |
| { |
| RedlineMode_t const eTmpMode = |
| static_cast<RedlineMode_t>(rUndo.GetRedlineMode()); |
| if ((nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != |
| (nsRedlineMode_t::REDLINE_SHOW_MASK & m_eMode)) |
| { |
| m_rRedlineAccess.SetRedlineMode( eTmpMode ); |
| } |
| m_rRedlineAccess.SetRedlineMode_intern( static_cast<RedlineMode_t>( |
| eTmpMode | nsRedlineMode_t::REDLINE_IGNORE) ); |
| } |
| ~UndoRedoRedlineGuard() |
| { |
| m_rRedlineAccess.SetRedlineMode(m_eMode); |
| } |
| private: |
| IDocumentRedlineAccess & m_rRedlineAccess; |
| RedlineMode_t const m_eMode; |
| }; |
| |
| void SwUndo::Undo() |
| { |
| OSL_ENSURE(false, "SwUndo::Undo(): ERROR: must call Undo(context) instead"); |
| } |
| |
| void SwUndo::Redo() |
| { |
| OSL_ENSURE(false, "SwUndo::Redo(): ERROR: must call Redo(context) instead"); |
| } |
| |
| void SwUndo::UndoWithContext(SfxUndoContext & rContext) |
| { |
| ::sw::UndoRedoContext *const pContext( |
| dynamic_cast< ::sw::UndoRedoContext * >(& rContext)); |
| OSL_ASSERT(pContext); |
| if (!pContext) { return; } |
| const UndoRedoRedlineGuard aUndoRedoRedlineGuard(*pContext, *this); |
| UndoImpl(*pContext); |
| } |
| |
| void SwUndo::RedoWithContext(SfxUndoContext & rContext) |
| { |
| ::sw::UndoRedoContext *const pContext( |
| dynamic_cast< ::sw::UndoRedoContext * >(& rContext)); |
| OSL_ASSERT(pContext); |
| if (!pContext) { return; } |
| const UndoRedoRedlineGuard aUndoRedoRedlineGuard(*pContext, *this); |
| RedoImpl(*pContext); |
| } |
| |
| void SwUndo::Repeat(SfxRepeatTarget & rContext) |
| { |
| ::sw::RepeatContext *const pRepeatContext( |
| dynamic_cast< ::sw::RepeatContext * >(& rContext)); |
| OSL_ASSERT(pRepeatContext); |
| if (!pRepeatContext) { return; } |
| RepeatImpl(*pRepeatContext); |
| } |
| |
| sal_Bool SwUndo::CanRepeat(SfxRepeatTarget & rContext) const |
| { |
| ::sw::RepeatContext *const pRepeatContext( |
| dynamic_cast< ::sw::RepeatContext * >(& rContext)); |
| OSL_ASSERT(pRepeatContext); |
| if (!pRepeatContext) { return false; } |
| return CanRepeatImpl(*pRepeatContext); |
| } |
| |
| void SwUndo::RepeatImpl( ::sw::RepeatContext & ) |
| { |
| } |
| |
| bool SwUndo::CanRepeatImpl( ::sw::RepeatContext & ) const |
| { |
| // return false; |
| return ((REPEAT_START <= GetId()) && (GetId() < REPEAT_END)); |
| } |
| |
| String SwUndo::GetComment() const |
| { |
| String aResult; |
| |
| if (bCacheComment) |
| { |
| if (! pComment) |
| { |
| pComment = new String(SW_RES(UNDO_BASE + GetId())); |
| |
| SwRewriter aRewriter = GetRewriter(); |
| |
| *pComment = aRewriter.Apply(*pComment); |
| } |
| |
| aResult = *pComment; |
| } |
| else |
| { |
| aResult = String(SW_RES(UNDO_BASE + GetId())); |
| |
| SwRewriter aRewriter = GetRewriter(); |
| |
| aResult = aRewriter.Apply(aResult); |
| } |
| |
| return aResult; |
| } |
| |
| SwRewriter SwUndo::GetRewriter() const |
| { |
| SwRewriter aResult; |
| |
| return aResult; |
| } |
| |
| |
| //------------------------------------------------------------ |
| |
| SwUndoSaveCntnt::SwUndoSaveCntnt() |
| : pHistory( 0 ) |
| {} |
| |
| SwUndoSaveCntnt::~SwUndoSaveCntnt() |
| { |
| delete pHistory; |
| } |
| |
| // wird fuer das Loeschen von Inhalt benoetigt. Fuer das ReDo werden |
| // Inhalte in das UndoNodesArray verschoben. Diese Methoden fuegen |
| // am Ende eines TextNodes fuer die Attribute einen Trenner ein. |
| // Dadurch werden die Attribute nicht expandiert. |
| // MoveTo.. verschiebt aus dem NodesArray in das UndoNodesArray |
| // MoveFrom.. verschiebt aus dem UndoNodesArray in das NodesArray |
| |
| // 2.8.93: ist pEndNdIdx angebenen, wird vom Undo/Redo -Ins/DelFly |
| // aufgerufen. Dann soll die gesamte Section verschoben werden. |
| |
| void SwUndoSaveCntnt::MoveToUndoNds( SwPaM& rPaM, SwNodeIndex* pNodeIdx, |
| SwIndex* pCntIdx, sal_uLong* pEndNdIdx, xub_StrLen* pEndCntIdx ) |
| { |
| SwDoc& rDoc = *rPaM.GetDoc(); |
| ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); |
| |
| SwNoTxtNode* pCpyNd = rPaM.GetNode()->GetNoTxtNode(); |
| |
| // jetzt kommt das eigentliche Loeschen(Verschieben) |
| SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes(); |
| SwPosition aPos( pEndNdIdx ? rNds.GetEndOfPostIts() |
| : rNds.GetEndOfExtras() ); |
| aPos.nNode--; |
| |
| const SwPosition* pStt = rPaM.Start(), *pEnd = rPaM.End(); |
| |
| if( pCpyNd || pEndNdIdx || !aPos.nNode.GetNode().GetCntntNode() || |
| (!pStt->nContent.GetIndex() && (pStt->nNode != pEnd->nNode || |
| (!pStt->nNode.GetNode().GetCntntNode() || |
| pStt->nNode.GetNode().GetCntntNode()->Len() == |
| pEnd->nContent.GetIndex() ) ) ) ) |
| { |
| aPos.nNode++; |
| aPos.nContent = 0; |
| } |
| else |
| aPos.nNode.GetNode().GetCntntNode()->MakeEndIndex( &aPos.nContent ); |
| |
| // als sal_uInt16 merken; die Indizies verschieben sich !! |
| sal_uLong nTmpMvNode = aPos.nNode.GetIndex(); |
| xub_StrLen nTmpMvCntnt = aPos.nContent.GetIndex(); |
| |
| if( pCpyNd || pEndNdIdx ) |
| { |
| SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 ); |
| rDoc.GetNodes()._MoveNodes( aRg, rNds, aPos.nNode, sal_False ); |
| aPos.nContent = 0; |
| aPos.nNode--; |
| } |
| else |
| { |
| rDoc.GetNodes().MoveRange( rPaM, aPos, rNds ); |
| |
| SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode(); |
| if( pTxtNd ) // fuege einen Trenner fuer die Attribute ein ! |
| { |
| // weil aber beim Insert die Attribute angefasst/sprich |
| // aus dem Array geloescht und wieder eingefuegt werden, koennen |
| // dadurch Attribute verschwinden (z.B "Fett aus" von 10-20, |
| // "Fett an" von 12-15, dann wird durchs Insert/Delete das |
| // "Fett an" geloescht !! Ist hier aber nicht erwuenscht !!) |
| // DARUM: nicht die Hints anfassen, direct den String manipulieren |
| |
| String& rStr = (String&)pTxtNd->GetTxt(); |
| // Zur Sicherheit lieber nur wenn wirklich am Ende steht |
| if( rStr.Len() == aPos.nContent.GetIndex() ) |
| { |
| rStr.Insert( ' ' ); |
| ++aPos.nContent; |
| } |
| else |
| { |
| pTxtNd->InsertText( sal_Unicode(' '), aPos.nContent, |
| IDocumentContentOperations::INS_NOHINTEXPAND ); |
| } |
| } |
| } |
| if( pEndNdIdx ) |
| *pEndNdIdx = aPos.nNode.GetIndex(); |
| if( pEndCntIdx ) |
| *pEndCntIdx = aPos.nContent.GetIndex(); |
| |
| // alte Position |
| aPos.nNode = nTmpMvNode; |
| if( pNodeIdx ) |
| *pNodeIdx = aPos.nNode; |
| |
| if( pCntIdx ) |
| { |
| SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode(); |
| if( pCNd ) |
| pCntIdx->Assign( pCNd, nTmpMvCntnt ); |
| else |
| pCntIdx->Assign( 0, 0 ); |
| } |
| } |
| |
| void SwUndoSaveCntnt::MoveFromUndoNds( SwDoc& rDoc, sal_uLong nNodeIdx, |
| xub_StrLen nCntIdx, SwPosition& rInsPos, |
| sal_uLong* pEndNdIdx, xub_StrLen* pEndCntIdx ) |
| { |
| // jetzt kommt das wiederherstellen |
| SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes(); |
| if( nNodeIdx == rNds.GetEndOfPostIts().GetIndex() ) |
| return; // nichts gespeichert |
| |
| ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); |
| |
| SwPaM aPaM( rInsPos ); |
| if( pEndNdIdx ) // dann hole aus diesem den Bereich |
| aPaM.GetPoint()->nNode.Assign( rNds, *pEndNdIdx ); |
| else |
| { |
| aPaM.GetPoint()->nNode = rNds.GetEndOfExtras(); |
| GoInCntnt( aPaM, fnMoveBackward ); |
| } |
| |
| SwTxtNode* pTxtNd = aPaM.GetNode()->GetTxtNode(); |
| if( !pEndNdIdx && pTxtNd ) // loesche den Trenner wieder |
| { |
| if( pEndCntIdx ) |
| aPaM.GetPoint()->nContent.Assign( pTxtNd, *pEndCntIdx ); |
| if( pTxtNd->GetTxt().Len() ) |
| { |
| GoInCntnt( aPaM, fnMoveBackward ); |
| pTxtNd->EraseText( aPaM.GetPoint()->nContent, 1 ); |
| } |
| |
| aPaM.SetMark(); |
| aPaM.GetPoint()->nNode = nNodeIdx; |
| aPaM.GetPoint()->nContent.Assign( aPaM.GetCntntNode(), nCntIdx ); |
| |
| _SaveRedlEndPosForRestore aRedlRest( rInsPos.nNode, rInsPos.nContent.GetIndex() ); |
| |
| rNds.MoveRange( aPaM, rInsPos, rDoc.GetNodes() ); |
| |
| // noch den letzen Node loeschen. |
| if( !aPaM.GetPoint()->nContent.GetIndex() || |
| ( aPaM.GetPoint()->nNode++ && // noch leere Nodes am Ende ?? |
| &rNds.GetEndOfExtras() != &aPaM.GetPoint()->nNode.GetNode() )) |
| { |
| aPaM.GetPoint()->nContent.Assign( 0, 0 ); |
| aPaM.SetMark(); |
| rNds.Delete( aPaM.GetPoint()->nNode, |
| rNds.GetEndOfExtras().GetIndex() - |
| aPaM.GetPoint()->nNode.GetIndex() ); |
| } |
| |
| aRedlRest.Restore(); |
| } |
| else if( pEndNdIdx || !pTxtNd ) |
| { |
| SwNodeRange aRg( rNds, nNodeIdx, rNds, (pEndNdIdx |
| ? ((*pEndNdIdx) + 1) |
| : rNds.GetEndOfExtras().GetIndex() ) ); |
| rNds._MoveNodes( aRg, rDoc.GetNodes(), rInsPos.nNode, 0 == pEndNdIdx ); |
| |
| } |
| else { |
| ASSERT( sal_False, "was ist es denn nun?" ); |
| } |
| } |
| |
| // diese beiden Methoden bewegen den Point vom Pam zurueck/vor. Damit |
| // kann fuer ein Undo/Redo ein Bereich aufgespannt werden. (Der |
| // Point liegt dann vor dem manipuliertem Bereich !!) |
| // Das Flag gibt an, ob noch vorm Point Inhalt steht. |
| |
| sal_Bool SwUndoSaveCntnt::MovePtBackward( SwPaM& rPam ) |
| { |
| rPam.SetMark(); |
| if( rPam.Move( fnMoveBackward )) |
| return sal_True; |
| |
| // gibt es nach vorne keinen Inhalt mehr, so setze den Point einfach |
| // auf die vorherige Position (Node und Content, damit der Content |
| // abgemeldet wird !!) |
| rPam.GetPoint()->nNode--; |
| rPam.GetPoint()->nContent.Assign( 0, 0 ); |
| return sal_False; |
| } |
| |
| void SwUndoSaveCntnt::MovePtForward( SwPaM& rPam, sal_Bool bMvBkwrd ) |
| { |
| // gab es noch Inhalt vor der Position ? |
| if( bMvBkwrd ) |
| rPam.Move( fnMoveForward ); |
| else |
| { // setzen Point auf die naechste Position |
| rPam.GetPoint()->nNode++; |
| SwCntntNode* pCNd = rPam.GetCntntNode(); |
| if( pCNd ) |
| pCNd->MakeStartIndex( &rPam.GetPoint()->nContent ); |
| else |
| rPam.Move( fnMoveForward ); |
| } |
| } |
| |
| |
| /* |
| JP 21.03.94: loesche alle Objecte, die ContentIndizies auf den ang. |
| Bereich besitzen. |
| Zur Zeit gibts folgende Objecte |
| - Fussnoten |
| - Flys |
| - Bookmarks |
| - Verzeichnisse |
| */ |
| // --> OD 2007-10-17 #i81002# - extending method: |
| // delete certain (not all) cross-reference bookmarks at text node of <rMark> |
| // and at text node of <rPoint>, if these text nodes aren't the same. |
| void SwUndoSaveCntnt::DelCntntIndex( const SwPosition& rMark, |
| const SwPosition& rPoint, |
| DelCntntType nDelCntntType ) |
| { |
| const SwPosition *pStt = rMark < rPoint ? &rMark : &rPoint, |
| *pEnd = &rMark == pStt ? &rPoint : &rMark; |
| |
| SwDoc* pDoc = rMark.nNode.GetNode().GetDoc(); |
| |
| ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); |
| |
| // 1. Fussnoten |
| if( nsDelCntntType::DELCNT_FTN & nDelCntntType ) |
| { |
| SwFtnIdxs& rFtnArr = pDoc->GetFtnIdxs(); |
| if( rFtnArr.Count() ) |
| { |
| const SwNode* pFtnNd; |
| sal_uInt16 nPos; |
| rFtnArr.SeekEntry( pStt->nNode, &nPos ); |
| SwTxtFtn* pSrch; |
| |
| // loesche erstmal alle, die dahinter stehen |
| while( nPos < rFtnArr.Count() && ( pFtnNd = |
| &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex() |
| <= pEnd->nNode.GetIndex() ) |
| { |
| xub_StrLen nFtnSttIdx = *pSrch->GetStart(); |
| if( (nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) |
| ? (&pEnd->nNode.GetNode() == pFtnNd ) |
| : (( &pStt->nNode.GetNode() == pFtnNd && |
| pStt->nContent.GetIndex() > nFtnSttIdx) || |
| ( &pEnd->nNode.GetNode() == pFtnNd && |
| nFtnSttIdx >= pEnd->nContent.GetIndex() )) ) |
| { |
| ++nPos; // weiter suchen |
| continue; |
| } |
| |
| // es muss leider ein Index angelegt werden. Sonst knallts im |
| // TextNode, weil im DTOR der SwFtn dieser geloescht wird !! |
| SwTxtNode* pTxtNd = (SwTxtNode*)pFtnNd; |
| if( !pHistory ) |
| pHistory = new SwHistory; |
| SwTxtAttr* const pFtnHnt = |
| pTxtNd->GetTxtAttrForCharAt( nFtnSttIdx ); |
| ASSERT( pFtnHnt, "kein FtnAttribut" ); |
| SwIndex aIdx( pTxtNd, nFtnSttIdx ); |
| pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false ); |
| pTxtNd->EraseText( aIdx, 1 ); |
| } |
| |
| while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )-> |
| GetTxtNode())->GetIndex() >= pStt->nNode.GetIndex() ) |
| { |
| xub_StrLen nFtnSttIdx = *pSrch->GetStart(); |
| if( !(nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType) && ( |
| ( &pStt->nNode.GetNode() == pFtnNd && |
| pStt->nContent.GetIndex() > nFtnSttIdx ) || |
| ( &pEnd->nNode.GetNode() == pFtnNd && |
| nFtnSttIdx >= pEnd->nContent.GetIndex() ))) |
| continue; // weiter suchen |
| |
| // es muss leider ein Index angelegt werden. Sonst knallts im |
| // TextNode, weil im DTOR der SwFtn dieser geloescht wird !! |
| SwTxtNode* pTxtNd = (SwTxtNode*)pFtnNd; |
| if( !pHistory ) |
| pHistory = new SwHistory; |
| SwTxtAttr* const pFtnHnt = |
| pTxtNd->GetTxtAttrForCharAt( nFtnSttIdx ); |
| ASSERT( pFtnHnt, "kein FtnAttribut" ); |
| SwIndex aIdx( pTxtNd, nFtnSttIdx ); |
| pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false ); |
| pTxtNd->EraseText( aIdx, 1 ); |
| } |
| } |
| } |
| |
| // 2. Flys |
| if( nsDelCntntType::DELCNT_FLY & nDelCntntType ) |
| { |
| sal_uInt16 nChainInsPos = pHistory ? pHistory->Count() : 0; |
| const SwSpzFrmFmts& rSpzArr = *pDoc->GetSpzFrmFmts(); |
| if( rSpzArr.Count() ) |
| { |
| const sal_Bool bDelFwrd = rMark.nNode.GetIndex() <= rPoint.nNode.GetIndex(); |
| SwFlyFrmFmt* pFmt; |
| const SwFmtAnchor* pAnchor; |
| sal_uInt16 n = rSpzArr.Count(); |
| const SwPosition* pAPos; |
| |
| while( n && rSpzArr.Count() ) |
| { |
| pFmt = (SwFlyFrmFmt*)rSpzArr[--n]; |
| pAnchor = &pFmt->GetAnchor(); |
| switch( pAnchor->GetAnchorId() ) |
| { |
| case FLY_AS_CHAR: |
| if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && |
| (( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) |
| ? ( pStt->nNode <= pAPos->nNode && |
| pAPos->nNode < pEnd->nNode ) |
| : ( *pStt <= *pAPos && *pAPos < *pEnd )) ) |
| { |
| if( !pHistory ) |
| pHistory = new SwHistory; |
| SwTxtNode *const pTxtNd = |
| pAPos->nNode.GetNode().GetTxtNode(); |
| SwTxtAttr* const pFlyHnt = pTxtNd->GetTxtAttrForCharAt( |
| pAPos->nContent.GetIndex()); |
| ASSERT( pFlyHnt, "kein FlyAttribut" ); |
| pHistory->Add( pFlyHnt, 0, false ); |
| // n wieder zurueck, damit nicht ein Format uebesprungen wird ! |
| n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; |
| } |
| break; |
| case FLY_AT_PARA: |
| { |
| pAPos = pAnchor->GetCntntAnchor(); |
| if( pAPos ) |
| { |
| bool bTmp; |
| if( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) |
| bTmp = pStt->nNode <= pAPos->nNode && pAPos->nNode < pEnd->nNode; |
| else |
| { |
| if (bDelFwrd) |
| bTmp = rMark.nNode < pAPos->nNode && |
| pAPos->nNode <= rPoint.nNode; |
| else |
| bTmp = rPoint.nNode <= pAPos->nNode && |
| pAPos->nNode < rMark.nNode; |
| } |
| |
| if (bTmp) |
| { |
| if( !pHistory ) |
| pHistory = new SwHistory; |
| |
| // Moving the anchor? |
| if( !( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) && |
| ( rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex() ) ) |
| { |
| // Do not try to move the anchor to a table! |
| if( rMark.nNode.GetNode().GetTxtNode() ) |
| { |
| pHistory->Add( *pFmt ); |
| SwFmtAnchor aAnch( *pAnchor ); |
| SwPosition aPos( rMark.nNode ); |
| aAnch.SetAnchor( &aPos ); |
| pFmt->SetFmtAttr( aAnch ); |
| } |
| } |
| else |
| { |
| pHistory->Add( *pFmt, nChainInsPos ); |
| // n wieder zurueck, damit nicht ein |
| // Format uebesprungen wird ! |
| n = n >= rSpzArr.Count() ? |
| rSpzArr.Count() : n+1; |
| } |
| } |
| } |
| } |
| break; |
| case FLY_AT_CHAR: |
| if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && |
| ( pStt->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) ) |
| { |
| if( !pHistory ) |
| pHistory = new SwHistory; |
| if (IsDestroyFrameAnchoredAtChar( |
| *pAPos, *pStt, *pEnd, nDelCntntType)) |
| { |
| pHistory->Add( *pFmt, nChainInsPos ); |
| n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; |
| } |
| else if( !( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) ) |
| { |
| if( *pStt <= *pAPos && *pAPos < *pEnd ) |
| { |
| // These are the objects anchored |
| // between section start and end position |
| // Do not try to move the anchor to a table! |
| if( rMark.nNode.GetNode().GetTxtNode() ) |
| { |
| pHistory->Add( *pFmt ); |
| SwFmtAnchor aAnch( *pAnchor ); |
| aAnch.SetAnchor( &rMark ); |
| pFmt->SetFmtAttr( aAnch ); |
| } |
| } |
| } |
| } |
| break; |
| case FLY_AT_FLY: |
| |
| if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) && |
| pStt->nNode == pAPos->nNode ) |
| { |
| if( !pHistory ) |
| pHistory = new SwHistory; |
| |
| pHistory->Add( *pFmt, nChainInsPos ); |
| |
| // n wieder zurueck, damit nicht ein Format uebesprungen wird ! |
| n = n >= rSpzArr.Count() ? rSpzArr.Count() : n+1; |
| } |
| break; |
| default: break; |
| } |
| } |
| } |
| } |
| |
| // 3. Bookmarks |
| if( nsDelCntntType::DELCNT_BKM & nDelCntntType ) |
| { |
| IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); |
| if( pMarkAccess->getAllMarksCount() ) |
| { |
| |
| for( sal_uInt16 n = 0; n < pMarkAccess->getAllMarksCount(); ++n ) |
| { |
| bool bSavePos = false; |
| bool bSaveOtherPos = false; |
| const ::sw::mark::IMark* pBkmk = (pMarkAccess->getAllMarksBegin() + n)->get(); |
| |
| if( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) |
| { |
| if ( pStt->nNode <= pBkmk->GetMarkPos().nNode |
| && pBkmk->GetMarkPos().nNode < pEnd->nNode ) |
| { |
| bSavePos = true; |
| } |
| if ( pBkmk->IsExpanded() |
| && pStt->nNode <= pBkmk->GetOtherMarkPos().nNode |
| && pBkmk->GetOtherMarkPos().nNode < pEnd->nNode ) |
| { |
| bSaveOtherPos = true; |
| } |
| } |
| else |
| { |
| // keep cross-reference bookmarks, if content inside one paragraph is deleted. |
| if ( rMark.nNode == rPoint.nNode |
| && ( IDocumentMarkAccess::GetType(*pBkmk) == IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK |
| || IDocumentMarkAccess::GetType(*pBkmk) == IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK ) ) |
| { |
| continue; |
| } |
| |
| bool bMaybe = false; |
| if ( *pStt <= pBkmk->GetMarkPos() && pBkmk->GetMarkPos() <= *pEnd ) |
| { |
| if ( pBkmk->GetMarkPos() == *pEnd |
| || ( *pStt == pBkmk->GetMarkPos() && pBkmk->IsExpanded() ) ) |
| bMaybe = true; |
| else |
| bSavePos = true; |
| } |
| if( pBkmk->IsExpanded() && |
| *pStt <= pBkmk->GetOtherMarkPos() && pBkmk->GetOtherMarkPos() <= *pEnd ) |
| { |
| if ( bSavePos || bSaveOtherPos |
| || ( pBkmk->GetOtherMarkPos() < *pEnd && pBkmk->GetOtherMarkPos() > *pStt ) ) |
| { |
| if( bMaybe ) |
| bSavePos = true; |
| bSaveOtherPos = true; |
| } |
| } |
| |
| if ( !bSavePos && !bSaveOtherPos |
| && dynamic_cast< const ::sw::mark::CrossRefBookmark* >(pBkmk) ) |
| { |
| // certain special handling for cross-reference bookmarks |
| const bool bDifferentTxtNodesAtMarkAndPoint = |
| rMark.nNode != rPoint.nNode |
| && rMark.nNode.GetNode().GetTxtNode() |
| && rPoint.nNode.GetNode().GetTxtNode(); |
| if ( bDifferentTxtNodesAtMarkAndPoint ) |
| { |
| // delete cross-reference bookmark at <pStt>, if only part of |
| // <pEnd> text node content is deleted. |
| if( pStt->nNode == pBkmk->GetMarkPos().nNode |
| && pEnd->nContent.GetIndex() != pEnd->nNode.GetNode().GetTxtNode()->Len() ) |
| { |
| bSavePos = true; |
| bSaveOtherPos = false; // cross-reference bookmarks are not expanded |
| } |
| // delete cross-reference bookmark at <pEnd>, if only part of |
| // <pStt> text node content is deleted. |
| else if( pEnd->nNode == pBkmk->GetMarkPos().nNode && |
| pStt->nContent.GetIndex() != 0 ) |
| { |
| bSavePos = true; |
| bSaveOtherPos = false; // cross-reference bookmarks are not expanded |
| } |
| } |
| } |
| else if ( IDocumentMarkAccess::GetType(*pBkmk) == IDocumentMarkAccess::ANNOTATIONMARK ) |
| { |
| // delete annotation marks, if its end position is covered by the deletion |
| const SwPosition& rAnnotationEndPos = pBkmk->GetMarkEnd(); |
| if ( *pStt < rAnnotationEndPos && rAnnotationEndPos <= *pEnd ) |
| { |
| bSavePos = true; |
| bSaveOtherPos = true; |
| } |
| } |
| } |
| |
| if ( bSavePos || bSaveOtherPos ) |
| { |
| if( !pHistory ) |
| pHistory = new SwHistory; |
| |
| pHistory->Add( *pBkmk, bSavePos, bSaveOtherPos ); |
| if ( bSavePos |
| && ( bSaveOtherPos |
| || !pBkmk->IsExpanded() ) ) |
| { |
| pMarkAccess->deleteMark(pMarkAccess->getAllMarksBegin()+n); |
| n--; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| // sicher eine vollstaendige Section im Undo-Nodes-Array |
| |
| SwUndoSaveSection::SwUndoSaveSection() |
| : pMvStt( 0 ), pRedlSaveData( 0 ), nMvLen( 0 ), nStartPos( ULONG_MAX ) |
| { |
| } |
| |
| SwUndoSaveSection::~SwUndoSaveSection() |
| { |
| if( pMvStt ) // loesche noch den Bereich aus dem UndoNodes Array |
| { |
| // SaveSection speichert den Inhalt in der PostIt-Section |
| SwNodes& rUNds = pMvStt->GetNode().GetNodes(); |
| rUNds.Delete( *pMvStt, nMvLen ); |
| |
| delete pMvStt; |
| } |
| delete pRedlSaveData; |
| } |
| |
| void SwUndoSaveSection::SaveSection( SwDoc* pDoc, const SwNodeIndex& rSttIdx ) |
| { |
| SwNodeRange aRg( rSttIdx.GetNode(), *rSttIdx.GetNode().EndOfSectionNode() ); |
| SaveSection( pDoc, aRg ); |
| } |
| |
| |
| void SwUndoSaveSection::SaveSection( |
| SwDoc* pDoc, |
| const SwNodeRange& rRange ) |
| { |
| SwPaM aPam( rRange.aStart, rRange.aEnd ); |
| |
| // delete all footnotes, fly frames, bookmarks and indexes |
| DelCntntIndex( *aPam.GetMark(), *aPam.GetPoint() ); |
| { |
| // move certain indexes out of deleted range |
| SwNodeIndex aSttIdx( aPam.Start()->nNode.GetNode() ); |
| SwNodeIndex aEndIdx( aPam.End()->nNode.GetNode() ); |
| SwNodeIndex aMvStt( aEndIdx, 1 ); |
| pDoc->CorrAbs( aSttIdx, aEndIdx, SwPosition( aMvStt ), sal_True ); |
| } |
| |
| pRedlSaveData = new SwRedlineSaveDatas; |
| if( !SwUndo::FillSaveData( aPam, *pRedlSaveData, sal_True, sal_True )) |
| delete pRedlSaveData, pRedlSaveData = 0; |
| |
| nStartPos = rRange.aStart.GetIndex(); |
| |
| aPam.GetPoint()->nNode--; |
| aPam.GetMark()->nNode++; |
| |
| SwCntntNode* pCNd = aPam.GetCntntNode( sal_False ); |
| if( pCNd ) |
| aPam.GetMark()->nContent.Assign( pCNd, 0 ); |
| if( 0 != ( pCNd = aPam.GetCntntNode( sal_True )) ) |
| aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); |
| |
| // Positionen als SwIndex merken, damit im DTOR dieser Bereich |
| // entfernt werden kann !! |
| sal_uLong nEnd; |
| pMvStt = new SwNodeIndex( rRange.aStart ); |
| MoveToUndoNds( aPam, pMvStt, 0, &nEnd, 0 ); |
| nMvLen = nEnd - pMvStt->GetIndex() + 1; |
| } |
| |
| void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, SwNodeIndex* pIdx, |
| sal_uInt16 nSectType ) |
| { |
| if( ULONG_MAX != nStartPos ) // gab es ueberhaupt Inhalt ? |
| { |
| // ueberpruefe, ob der Inhalt an der alten Position steht |
| SwNodeIndex aSttIdx( pDoc->GetNodes(), nStartPos ); |
| OSL_ENSURE(!aSttIdx.GetNode().GetCntntNode(), |
| "RestoreSection(): Position on content node"); |
| |
| // move den Inhalt aus dem UndoNodes-Array in den Fly |
| SwStartNode* pSttNd = pDoc->GetNodes().MakeEmptySection( aSttIdx, |
| (SwStartNodeType)nSectType ); |
| |
| RestoreSection( pDoc, SwNodeIndex( *pSttNd->EndOfSectionNode() )); |
| |
| if( pIdx ) |
| *pIdx = *pSttNd; |
| } |
| } |
| |
| void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, const SwNodeIndex& rInsPos ) |
| { |
| if( ULONG_MAX != nStartPos ) // gab es ueberhaupt Inhalt ? |
| { |
| SwPosition aInsPos( rInsPos ); |
| sal_uLong nEnd = pMvStt->GetIndex() + nMvLen - 1; |
| MoveFromUndoNds( *pDoc, pMvStt->GetIndex(), 0, aInsPos, &nEnd, 0 ); |
| |
| // Indizies wieder zerstoren, Inhalt ist aus dem UndoNodes-Array |
| // entfernt worden. |
| DELETEZ( pMvStt ); |
| nMvLen = 0; |
| |
| if( pRedlSaveData ) |
| { |
| SwUndo::SetSaveData( *pDoc, *pRedlSaveData ); |
| delete pRedlSaveData, pRedlSaveData = 0; |
| } |
| } |
| } |
| |
| // sicher und setze die RedlineDaten |
| |
| SwRedlineSaveData::SwRedlineSaveData( |
| SwComparePosition eCmpPos, |
| const SwPosition& rSttPos, |
| const SwPosition& rEndPos, |
| SwRedline& rRedl, |
| sal_Bool bCopyNext ) |
| : SwUndRng( rRedl ) |
| , SwRedlineData( rRedl.GetRedlineData(), bCopyNext ) |
| { |
| ASSERT( POS_OUTSIDE == eCmpPos || !rRedl.GetContentIdx(), "Redline mit Content" ); |
| |
| switch (eCmpPos) |
| { |
| case POS_OVERLAP_BEFORE: // Pos1 ueberlappt Pos2 am Anfang |
| nEndNode = rEndPos.nNode.GetIndex(); |
| nEndCntnt = rEndPos.nContent.GetIndex(); |
| break; |
| |
| case POS_OVERLAP_BEHIND: // Pos1 ueberlappt Pos2 am Ende |
| nSttNode = rSttPos.nNode.GetIndex(); |
| nSttCntnt = rSttPos.nContent.GetIndex(); |
| break; |
| |
| case POS_INSIDE: // Pos1 liegt vollstaendig in Pos2 |
| nSttNode = rSttPos.nNode.GetIndex(); |
| nSttCntnt = rSttPos.nContent.GetIndex(); |
| nEndNode = rEndPos.nNode.GetIndex(); |
| nEndCntnt = rEndPos.nContent.GetIndex(); |
| break; |
| |
| case POS_OUTSIDE: // Pos2 liegt vollstaendig in Pos1 |
| if ( rRedl.GetContentIdx() ) |
| { |
| // dann den Bereich ins UndoArray verschieben und merken |
| SaveSection( rRedl.GetDoc(), *rRedl.GetContentIdx() ); |
| rRedl.SetContentIdx( 0 ); |
| } |
| break; |
| |
| case POS_EQUAL: // Pos1 ist genauso gross wie Pos2 |
| break; |
| |
| default: |
| ASSERT( !this, "keine gueltigen Daten!" ) |
| } |
| |
| #ifdef DBG_UTIL |
| nRedlineCount = rSttPos.nNode.GetNode().GetDoc()->GetRedlineTbl().Count(); |
| #endif |
| } |
| |
| SwRedlineSaveData::~SwRedlineSaveData() |
| { |
| } |
| |
| void SwRedlineSaveData::RedlineToDoc( SwPaM& rPam ) |
| { |
| SwDoc& rDoc = *rPam.GetDoc(); |
| SwRedline* pRedl = new SwRedline( *this, rPam ); |
| |
| if( GetMvSttIdx() ) |
| { |
| SwNodeIndex aIdx( rDoc.GetNodes() ); |
| RestoreSection( &rDoc, &aIdx, SwNormalStartNode ); |
| if( GetHistory() ) |
| GetHistory()->Rollback( &rDoc ); |
| pRedl->SetContentIdx( &aIdx ); |
| } |
| SetPaM( *pRedl ); |
| // erstmal die "alten" entfernen, damit im Append keine unerwarteten |
| // Dinge passieren, wie z.B. eine Delete in eigenen Insert. Dann wird |
| // naehmlich das gerade restaurierte wieder geloescht - nicht das gewollte |
| rDoc.DeleteRedline( *pRedl, false, USHRT_MAX ); |
| |
| RedlineMode_t eOld = rDoc.GetRedlineMode(); |
| rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES)); |
| //#i92154# let UI know about a new redline with comment |
| if (rDoc.GetDocShell() && (pRedl->GetComment() != String(::rtl::OUString::createFromAscii(""))) ) |
| rDoc.GetDocShell()->Broadcast(SwRedlineHint(pRedl,SWREDLINE_INSERTED)); |
| // |
| #if OSL_DEBUG_LEVEL > 0 |
| bool const bSuccess = |
| #endif |
| rDoc.AppendRedline( pRedl, true ); |
| OSL_ENSURE(bSuccess, |
| "SwRedlineSaveData::RedlineToDoc: insert redline failed"); |
| rDoc.SetRedlineMode_intern( eOld ); |
| } |
| |
| |
| sal_Bool SwUndo::FillSaveData( |
| const SwPaM& rRange, |
| SwRedlineSaveDatas& rSData, |
| sal_Bool bDelRange, |
| sal_Bool bCopyNext ) |
| { |
| if ( rSData.Count() ) |
| { |
| rSData.DeleteAndDestroy( 0, rSData.Count() ); |
| } |
| |
| SwRedlineSaveData* pNewData; |
| const SwPosition* pStt = rRange.Start(); |
| const SwPosition* pEnd = rRange.End(); |
| const SwRedlineTbl& rTbl = rRange.GetDoc()->GetRedlineTbl(); |
| sal_uInt16 n = 0; |
| rRange.GetDoc()->GetRedline( *pStt, &n ); |
| for ( ; n < rTbl.Count(); ++n ) |
| { |
| SwRedline* pRedl = rTbl[n]; |
| |
| const SwComparePosition eCmpPos = |
| ComparePosition( *pStt, *pEnd, *pRedl->Start(), *pRedl->End() ); |
| if ( eCmpPos != POS_BEFORE |
| && eCmpPos != POS_BEHIND |
| && eCmpPos != POS_COLLIDE_END |
| && eCmpPos != POS_COLLIDE_START ) |
| { |
| pNewData = new SwRedlineSaveData( eCmpPos, *pStt, *pEnd, *pRedl, bCopyNext ); |
| rSData.Insert( pNewData, rSData.Count() ); |
| } |
| } |
| if ( rSData.Count() && bDelRange ) |
| { |
| rRange.GetDoc()->DeleteRedline( rRange, false, USHRT_MAX ); |
| } |
| return 0 != rSData.Count(); |
| } |
| |
| |
| sal_Bool SwUndo::FillSaveDataForFmt( |
| const SwPaM& rRange, |
| SwRedlineSaveDatas& rSData ) |
| { |
| if ( rSData.Count() ) |
| { |
| rSData.DeleteAndDestroy( 0, rSData.Count() ); |
| } |
| |
| SwRedlineSaveData* pNewData; |
| const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End(); |
| const SwRedlineTbl& rTbl = rRange.GetDoc()->GetRedlineTbl(); |
| sal_uInt16 n = 0; |
| rRange.GetDoc()->GetRedline( *pStt, &n ); |
| for ( ; n < rTbl.Count(); ++n ) |
| { |
| SwRedline* pRedl = rTbl[n]; |
| if ( nsRedlineType_t::REDLINE_FORMAT == pRedl->GetType() ) |
| { |
| const SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRedl->Start(), *pRedl->End() ); |
| if ( eCmpPos != POS_BEFORE |
| && eCmpPos != POS_BEHIND |
| && eCmpPos != POS_COLLIDE_END |
| && eCmpPos != POS_COLLIDE_START ) |
| { |
| pNewData = new SwRedlineSaveData( eCmpPos, *pStt, *pEnd, *pRedl, sal_True ); |
| rSData.Insert( pNewData, rSData.Count() ); |
| } |
| |
| } |
| } |
| return 0 != rSData.Count(); |
| } |
| |
| |
| void SwUndo::SetSaveData( SwDoc& rDoc, const SwRedlineSaveDatas& rSData ) |
| { |
| RedlineMode_t eOld = rDoc.GetRedlineMode(); |
| rDoc.SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON )); |
| SwPaM aPam( rDoc.GetNodes().GetEndOfContent() ); |
| |
| for( sal_uInt16 n = rSData.Count(); n; ) |
| rSData[ --n ]->RedlineToDoc( aPam ); |
| |
| // check redline count against count saved in RedlineSaveData object |
| DBG_ASSERT( (rSData.Count() == 0) || |
| (rSData[0]->nRedlineCount == rDoc.GetRedlineTbl().Count()), |
| "redline count not restored properly" ); |
| |
| rDoc.SetRedlineMode_intern( eOld ); |
| } |
| |
| sal_Bool SwUndo::HasHiddenRedlines( const SwRedlineSaveDatas& rSData ) |
| { |
| for( sal_uInt16 n = rSData.Count(); n; ) |
| if( rSData[ --n ]->GetMvSttIdx() ) |
| return sal_True; |
| return sal_False; |
| } |
| |
| sal_Bool SwUndo::CanRedlineGroup( SwRedlineSaveDatas& rCurr, |
| const SwRedlineSaveDatas& rCheck, sal_Bool bCurrIsEnd ) |
| { |
| sal_Bool bRet = sal_False; |
| sal_uInt16 n; |
| |
| if( rCurr.Count() == rCheck.Count() ) |
| { |
| bRet = sal_True; |
| for( n = 0; n < rCurr.Count(); ++n ) |
| { |
| const SwRedlineSaveData& rSet = *rCurr[ n ]; |
| const SwRedlineSaveData& rGet = *rCheck[ n ]; |
| if( rSet.nSttNode != rGet.nSttNode || |
| rSet.GetMvSttIdx() || rGet.GetMvSttIdx() || |
| ( bCurrIsEnd ? rSet.nSttCntnt != rGet.nEndCntnt |
| : rSet.nEndCntnt != rGet.nSttCntnt ) || |
| !rGet.CanCombine( rSet ) ) |
| { |
| bRet = sal_False; |
| break; |
| } |
| } |
| |
| if( bRet ) |
| for( n = 0; n < rCurr.Count(); ++n ) |
| { |
| SwRedlineSaveData& rSet = *rCurr[ n ]; |
| const SwRedlineSaveData& rGet = *rCheck[ n ]; |
| if( bCurrIsEnd ) |
| rSet.nSttCntnt = rGet.nSttCntnt; |
| else |
| rSet.nEndCntnt = rGet.nEndCntnt; |
| } |
| } |
| return bRet; |
| } |
| |
| // #111827# |
| String ShortenString(const String & rStr, xub_StrLen nLength, const String & rFillStr) |
| { |
| ASSERT( nLength - rFillStr.Len() >= 2, "improper arguments") |
| |
| String aResult; |
| |
| if (rStr.Len() <= nLength) |
| aResult = rStr; |
| else |
| { |
| long nTmpLength = nLength - rFillStr.Len(); |
| if ( nTmpLength < 2 ) |
| nTmpLength = 2; |
| |
| nLength = static_cast<xub_StrLen>(nTmpLength); |
| |
| const xub_StrLen nFrontLen = nLength - nLength / 2; |
| const xub_StrLen nBackLen = nLength - nFrontLen; |
| |
| aResult += rStr.Copy(0, nFrontLen); |
| aResult += rFillStr; |
| aResult += rStr.Copy(rStr.Len() - nBackLen, nBackLen); |
| } |
| |
| return aResult; |
| } |
| |
| static bool lcl_IsSpecialCharacter(sal_Unicode nChar) |
| { |
| switch (nChar) |
| { |
| case CH_TXTATR_BREAKWORD: |
| case CH_TXTATR_INWORD: |
| case CH_TXTATR_TAB: |
| case CH_TXTATR_NEWLINE: |
| return true; |
| |
| default: |
| break; |
| } |
| |
| return false; |
| } |
| |
| static String lcl_DenotedPortion(String rStr, xub_StrLen nStart, |
| xub_StrLen nEnd) |
| { |
| String aResult; |
| |
| if (nEnd - nStart > 0) |
| { |
| sal_Unicode cLast = rStr.GetChar(nEnd - 1); |
| if (lcl_IsSpecialCharacter(cLast)) |
| { |
| switch(cLast) |
| { |
| case CH_TXTATR_TAB: |
| aResult += String(SW_RES(STR_UNDO_TABS)); |
| |
| break; |
| case CH_TXTATR_NEWLINE: |
| aResult += String(SW_RES(STR_UNDO_NLS)); |
| |
| break; |
| |
| case CH_TXTATR_INWORD: |
| case CH_TXTATR_BREAKWORD: |
| aResult += UNDO_ARG2; |
| |
| break; |
| |
| } |
| SwRewriter aRewriter; |
| aRewriter.AddRule(UNDO_ARG1, |
| String::CreateFromInt32(nEnd - nStart)); |
| aResult = aRewriter.Apply(aResult); |
| } |
| else |
| { |
| aResult = String(SW_RES(STR_START_QUOTE)); |
| aResult += rStr.Copy(nStart, nEnd - nStart); |
| aResult += String(SW_RES(STR_END_QUOTE)); |
| } |
| } |
| |
| return aResult; |
| } |
| |
| String DenoteSpecialCharacters(const String & rStr) |
| { |
| String aResult; |
| |
| if (rStr.Len() > 0) |
| { |
| bool bStart = false; |
| xub_StrLen nStart = 0; |
| sal_Unicode cLast = 0; |
| |
| for (xub_StrLen i = 0; i < rStr.Len(); i++) |
| { |
| if (lcl_IsSpecialCharacter(rStr.GetChar(i))) |
| { |
| if (cLast != rStr.GetChar(i)) |
| bStart = true; |
| |
| } |
| else |
| { |
| if (lcl_IsSpecialCharacter(cLast)) |
| bStart = true; |
| } |
| |
| if (bStart) |
| { |
| aResult += lcl_DenotedPortion(rStr, nStart, i); |
| |
| nStart = i; |
| bStart = false; |
| } |
| |
| cLast = rStr.GetChar(i); |
| } |
| |
| aResult += lcl_DenotedPortion(rStr, nStart, rStr.Len()); |
| } |
| else |
| aResult = UNDO_ARG2; |
| |
| return aResult; |
| } |
| |
| bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos, |
| SwPosition const & rStart, SwPosition const & rEnd, |
| DelCntntType const nDelCntntType) |
| { |
| |
| // Here we identified the objects to destroy: |
| // - anchored between start and end of the selection |
| // - anchored in start of the selection with "CheckNoContent" |
| // - anchored in start of sel. and the selection start at pos 0 |
| return (rAnchorPos.nNode < rEnd.nNode) |
| && ( (nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType) |
| || (rStart.nNode < rAnchorPos.nNode) |
| || !rStart.nContent.GetIndex() |
| ); |
| } |
| |