From c808802e94eba48dc23d7fca133ed35c17feb163 Mon Sep 17 00:00:00 2001 From: Jan-Marek Glogowski Date: Sat, 28 Jun 2014 01:41:17 +0200 Subject: MM: introduce SwDoc::Append helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This drops all the specialized, workaround code from MM, introduced to use the SwFEShell::Paste function and additionally merges and renames SwDoc::Paste into SwDoc::Append. There is still a little common codepath, therefore this adds comments to always update both functions. Change-Id: I704b3ef3257dd977dac95e16e25049ff8ade97ed Reviewed-on: https://gerrit.libreoffice.org/10967 Reviewed-by: Björn Michaelsen Tested-by: Björn Michaelsen --- sw/inc/doc.hxx | 4 +- .../core/doc/DocumentContentOperationsManager.cxx | 4 +- sw/source/core/doc/docnew.cxx | 162 ++++++++++++++++----- sw/source/core/frmedt/fecopy.cxx | 4 + sw/source/uibase/dbui/dbmgr.cxx | 114 +++------------ 5 files changed, 158 insertions(+), 130 deletions(-) diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index a1d6236cc9b5..f91432649da9 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -460,7 +460,6 @@ private: OUString msDocAccTitle; void InitTOXTypes(); - void Paste( const SwDoc& ); public: enum DocumentType { @@ -1646,7 +1645,10 @@ public: ::sw::MetaFieldManager & GetMetaFieldManager(); ::sw::UndoManager & GetUndoManager(); ::sw::UndoManager const& GetUndoManager() const; + SfxObjectShell* CreateCopy(bool bCallInitNew) const; + void Append( const SwDoc& rSource, sal_uInt16 nStartPageNumber, + SwPageDesc* pTargetPageDesc, bool bDeletePrevious = false ); /** * Dumps the entire nodes structure to the given destination (file nodes.xml in the current directory by default) diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx index 4bbe194c6de6..f60fc5e445f0 100644 --- a/sw/source/core/doc/DocumentContentOperationsManager.cxx +++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx @@ -3138,8 +3138,10 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( !rRg.aStart.GetNode().IsSectionNode() && !aTmpI.GetNode().IsEndNode() ) { + // If the range starts with a SwStartNode, it isn't copied + sal_uInt16 offset = (rRg.aStart.GetNode().GetNodeType() != ND_STARTNODE) ? 1 : 0; OSL_ENSURE( rInsPos.GetIndex() - aSavePos.GetIndex() == - rRg.aEnd.GetIndex() - rRg.aStart.GetIndex(), + rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset, "An insufficient number of nodes were copied!" ); } } diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx index 1a7e76e41c4d..ea9b136325c7 100644 --- a/sw/source/core/doc/docnew.cxx +++ b/sw/source/core/doc/docnew.cxx @@ -106,6 +106,7 @@ #include #include #include +#include #include @@ -900,7 +901,8 @@ SfxObjectShell* SwDoc::CreateCopy(bool bCallInitNew ) const SfxObjectShell* pRetShell = new SwDocShell( pRet, SFX_CREATE_MODE_STANDARD ); if( bCallInitNew ) { - // it could happen that DoInitNew creates model, that increases the refcount of the object + // it could happen that DoInitNew creates model, + // that increases the refcount of the object pRetShell->DoInitNew(); } @@ -912,14 +914,7 @@ SfxObjectShell* SwDoc::CreateCopy(bool bCallInitNew ) const pRet->ReplaceStyles(*this); - // copy content - pRet->Paste( *this ); - - if ( bCallInitNew ) { - // delete leading page / initial content from target document - SwNodeIndex aDeleteIdx( pRet->GetNodes().GetEndOfExtras(), 2 ); - pRet->GetNodes().Delete( aDeleteIdx, 1 ); - } + pRet->Append(*this, 0, NULL, bCallInitNew); // remove the temporary shell if it is there as it was done before pRet->SetTmpDocShell( (SfxObjectShell*)NULL ); @@ -929,29 +924,64 @@ SfxObjectShell* SwDoc::CreateCopy(bool bCallInitNew ) const return pRetShell; } -// copy document content - code from SwFEShell::Paste( SwDoc* ) -void SwDoc::Paste( const SwDoc& rSource ) +// appends all pages of source SwDoc - based on SwFEShell::Paste( SwDoc* ) +void SwDoc::Append( const SwDoc& rSource, sal_uInt16 nStartPageNumber, + SwPageDesc* pTargetPageDesc, bool bDeletePrevious ) { // GetEndOfExtras + 1 = StartOfContent == no content node! // this ensures, that we have at least two nodes in the SwPaM. // @see IDocumentContentOperations::CopyRange SwNodeIndex aSourceIdx( rSource.GetNodes().GetEndOfExtras(), 1 ); + SwNodeIndex aSourceEndIdx( rSource.GetNodes().GetEndOfContent(), -1 ); SwPaM aCpyPam( aSourceIdx ); + if ( aSourceEndIdx.GetNode().IsTxtNode() ) { + aCpyPam.SetMark(); + // moves to the last content node before EOC; for single paragraph + // documents this would result in [n, n], which is considered empty + aCpyPam.Move( fnMoveForward, fnGoDoc ); + } + else + aCpyPam = SwPaM( aSourceIdx, aSourceEndIdx ); + + SwWrtShell* pTargetShell = GetDocShell()->GetWrtShell(); + sal_uInt16 nPhysPageNumber = 0; + if ( pTargetShell ) { + pTargetShell->StartAllAction(); + + // Otherwise we have to handle SwDummySectionNodes as first node + if ( pTargetPageDesc ) { + OUString name = pTargetPageDesc->GetName(); + pTargetShell->InsertPageBreak( &name, nStartPageNumber ); + } + + // -1 for the page break + -1, becauce it's an offset + nPhysPageNumber = pTargetShell->GetPhyPageNum() - 2; + if (bDeletePrevious) + nPhysPageNumber--; + + // We always start on an odd physical page number + if (1 == nPhysPageNumber % 2) + nPhysPageNumber++; + } + + // -1, otherwise aFixupIdx would move to new EOC + SwNodeIndex aFixupIdx( GetNodes().GetEndOfContent(), -1 ); + + // append at the end of document / content SwNodeIndex aTargetIdx( GetNodes().GetEndOfContent() ); SwPaM aInsertPam( aTargetIdx ); - aCpyPam.SetMark(); - aCpyPam.Move( fnMoveForward, fnGoDoc ); this->GetIDocumentUndoRedo().StartUndo( UNDO_INSGLOSSARY, NULL ); this->getIDocumentFieldsAccess().LockExpFlds(); { + // ** + // ** refer to SwFEShell::Paste, if you change the following code ** + // ** + SwPosition& rInsPos = *aInsertPam.GetPoint(); - //find out if the clipboard document starts with a table - bool bStartWithTable = 0 != aCpyPam.Start()->nNode.GetNode().FindTableNode(); - SwPosition aInsertPosition( rInsPos ); { SwNodeIndex aIndexBefore(rInsPos.nNode); @@ -967,31 +997,88 @@ void SwDoc::Paste( const SwDoc& rSource ) aPaM.GetDoc()->MakeUniqueNumRules(aPaM); - // No need to update the rsid, as this is an empty doc - } + // Update the rsid of each pasted text node + SwNodes &rDestNodes = GetNodes(); + sal_uLong const nEndIdx = aPaM.End()->nNode.GetIndex(); - //TODO: Is this necessary here? SaveTblBoxCntnt( &rInsPos ); - if(/*bIncludingPageFrames && */bStartWithTable) - { - //remove the paragraph in front of the table - SwPaM aPara(aInsertPosition); - this->getIDocumentContentOperations().DelFullPara(aPara); + for (sal_uLong nIdx = aPaM.Start()->nNode.GetIndex(); + nIdx <= nEndIdx; ++nIdx) + { + SwTxtNode *const pTxtNode = rDestNodes[nIdx]->GetTxtNode(); + if ( pTxtNode ) + UpdateParRsid( pTxtNode ); + } } - //additionally copy page bound frames - if( /*bIncludingPageFrames && */rSource.GetSpzFrmFmts()->size() ) + { - for ( sal_uInt16 i = 0; i < rSource.GetSpzFrmFmts()->size(); ++i ) - { - const SwFrmFmt& rCpyFmt = *(*rSource.GetSpzFrmFmts())[i]; - SwFmtAnchor aAnchor( rCpyFmt.GetAnchor() ); - if (FLY_AT_PAGE == aAnchor.GetAnchorId()) - { - aAnchor.SetPageNum( aAnchor.GetPageNum() /*+ nStartPageNumber - */); + sal_uInt16 iDelNodes = 0; + SwNodeIndex aDelIdx( aFixupIdx ); + + // we just need to set the new page description and reset numbering + // this keeps all other settings as in the pasted document + if ( nStartPageNumber || pTargetPageDesc ) { + SfxPoolItem *pNewItem; + SwTxtNode *aTxtNd = 0; + SwFmt *pFmt = 0; + + // find the first node allowed to contain a RES_PAGEDESC + while (1) { + aFixupIdx++; + + SwNode &node = aFixupIdx.GetNode(); + if ( node.IsTxtNode() ) { + // every document contains at least one text node! + aTxtNd = node.GetTxtNode(); + pNewItem = aTxtNd->GetAttr( RES_PAGEDESC ).Clone(); + break; + } + else if ( node.IsTableNode() ) { + pFmt = node.GetTableNode()->GetTable().GetFrmFmt(); + pNewItem = pFmt->GetFmtAttr( RES_PAGEDESC ).Clone(); + break; } - else - continue; - this->getIDocumentLayoutAccess().CopyLayoutFmt( rCpyFmt, aAnchor, true, true ); + } + + // just update the original instead of overwriting + SwFmtPageDesc *aDesc = static_cast< SwFmtPageDesc* >( pNewItem ); + if ( nStartPageNumber ) + aDesc->SetNumOffset( nStartPageNumber ); + if ( pTargetPageDesc ) + aDesc->RegisterToPageDesc( *pTargetPageDesc ); + if ( aTxtNd ) + aTxtNd->SetAttr( *aDesc ); + else + pFmt->SetFmtAttr( *aDesc ); + delete pNewItem; + + iDelNodes++; } + + if ( bDeletePrevious ) + iDelNodes++; + + if ( iDelNodes ) { + // delete leading empty page(s), e.g. from InsertPageBreak or + // new SwDoc. this has to be done before copying the page bound + // frames, otherwise the drawing layer gets confused. + if ( pTargetShell ) + pTargetShell->SttEndDoc( false ); + aDelIdx -= (iDelNodes - 1); + GetNodes().Delete( aDelIdx, iDelNodes ); + } + } + + // finally copy page bound frames + const SwFrmFmts *pSpzFrmFmts = rSource.GetSpzFrmFmts(); + for ( sal_uInt16 i = 0; i < pSpzFrmFmts->size(); ++i ) + { + const SwFrmFmt& rCpyFmt = *(*pSpzFrmFmts)[i]; + SwFmtAnchor aAnchor( rCpyFmt.GetAnchor() ); + if (FLY_AT_PAGE != aAnchor.GetAnchorId()) + continue; + if ( nPhysPageNumber ) + aAnchor.SetPageNum( aAnchor.GetPageNum() + nPhysPageNumber ); + this->getIDocumentLayoutAccess().CopyLayoutFmt( rCpyFmt, aAnchor, true, true ); } } @@ -999,6 +1086,9 @@ void SwDoc::Paste( const SwDoc& rSource ) getIDocumentFieldsAccess().UnlockExpFlds(); getIDocumentFieldsAccess().UpdateFlds(NULL, false); + + if ( pTargetShell ) + pTargetShell->EndAllAction(); } sal_uInt16 SwTxtFmtColls::GetPos(const SwTxtFmtColl* p) const diff --git a/sw/source/core/frmedt/fecopy.cxx b/sw/source/core/frmedt/fecopy.cxx index e3612e40beba..3669a5902734 100644 --- a/sw/source/core/frmedt/fecopy.cxx +++ b/sw/source/core/frmedt/fecopy.cxx @@ -1028,6 +1028,10 @@ bool SwFEShell::Paste( SwDoc* pClpDoc, bool bIncludingPageFrames ) GetDoc()->ClearBoxNumAttrs( rInsPos.nNode ); } + // ** + // ** Update SwDoc::Append, if you change the following code ** + // ** + // find out if the clipboard document starts with a table bool bStartWithTable = 0 != aCpyPam.Start()->nNode.GetNode().FindTableNode(); SwPosition aInsertPosition( rInsPos ); diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx index 20bcefb26d46..7b013a7cf678 100644 --- a/sw/source/uibase/dbui/dbmgr.cxx +++ b/sw/source/uibase/dbui/dbmgr.cxx @@ -885,7 +885,6 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, // in case of creating a single resulting file this has to be created here SwWrtShell* pTargetShell = 0; SwDoc* pTargetDoc = 0; - SwNodes* pTargetNodes = 0; // the shell will be explicitly closed at the end of the method, but it is // still more safe to use SfxObjectShellLock here @@ -897,6 +896,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, OUString sStartingPageDesc; sal_uInt16 nStartingPageNo = 0; bool bPageStylesWithHeaderFooter = false; + if(bAsSingleFile || rMergeDescriptor.bCreateSingleFile) { // create a target docshell to put the merged document into @@ -910,7 +910,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, pTargetView->AttrChangedNotify( &pTargetView->GetWrtShell() ); pTargetShell = pTargetView->GetWrtShellPtr(); pTargetDoc = pTargetShell->GetDoc(); - pTargetNodes = &pTargetDoc->GetNodes(); + //copy the styles from the source to the target document pTargetView->GetDocShell()->_LoadStyles( *pSourceDocSh, true ); //determine the page style and number used at the start of the source document @@ -1050,66 +1050,32 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, } // insert the document into the target document - rWorkShell.SttEndDoc(false); - rWorkShell.SttEndDoc(true); - rWorkShell.SelAll(); - pTargetShell->SwCrsrShell::SttEndDoc( false ); - //#i72517# the headers and footers are still those from the source - update in case of fields inside header/footer - if( !nDocNo && bPageStylesWithHeaderFooter ) - pTargetShell->GetView().GetDocShell()->_LoadStyles( *rWorkShell.GetView().GetDocShell(), true ); + //#i72517# put the styles to the target document //if the source uses headers or footers each new copy need to copy a new page styles + SwPageDesc* pTargetPageDesc; if(bPageStylesWithHeaderFooter) { //create a new pagestyle //copy the pagedesc from the current document to the new document and change the name of the to-be-applied style - SwPageDesc* pSourcePageDesc = rWorkShell.FindPageDescByName( sStartingPageDesc ); OUString sNewPageDescName = lcl_FindUniqueName(pTargetShell, sStartingPageDesc, nDocNo ); - pTargetDoc->MakePageDesc( sNewPageDescName ); - SwPageDesc* pTargetPageDesc = pTargetShell->FindPageDescByName( sNewPageDescName ); - if(pSourcePageDesc && pTargetPageDesc) + pTargetPageDesc = pTargetDoc->MakePageDesc( sNewPageDescName ); + const SwPageDesc* pWorkPageDesc = rWorkShell.FindPageDescByName( sStartingPageDesc ); + + if(pWorkPageDesc && pTargetPageDesc) { - pTargetDoc->CopyPageDesc( *pSourcePageDesc, *pTargetPageDesc, false ); + pTargetDoc->CopyPageDesc( *pWorkPageDesc, *pTargetPageDesc, false ); sModifiedStartingPageDesc = sNewPageDescName; - lcl_CopyFollowPageDesc( *pTargetShell, *pSourcePageDesc, *pTargetPageDesc, nDocNo ); + lcl_CopyFollowPageDesc( *pTargetShell, *pWorkPageDesc, *pTargetPageDesc, nDocNo ); } } - - if(nDocNo > 1) - pTargetShell->InsertPageBreak( &sModifiedStartingPageDesc, nStartingPageNo ); else - pTargetShell->SetPageStyle(sModifiedStartingPageDesc); - OSL_ENSURE(!pTargetShell->GetTableFmt(),"target document ends with a table - paragraph should be appended"); + pTargetPageDesc = pTargetShell->FindPageDescByName( sModifiedStartingPageDesc ); - //#i51359# add a second paragraph in case there's only one - bool para_added = false; - { - SwNodeIndex aIdx( pWorkDoc->GetNodes().GetEndOfExtras(), 2 ); - SwPosition aTestPos( aIdx ); - SwCursor aTestCrsr(aTestPos,0,false); - if(!aTestCrsr.MovePara(fnParaNext, fnParaStart)) - { - //append a paragraph - pWorkDoc->getIDocumentContentOperations().AppendTxtNode( aTestPos ); - para_added = true; - } - } - pTargetShell->Paste( rWorkShell.GetDoc(), true ); - - if ( para_added ) { - // Move cursor to the start or Delete will assert because - // of the cursors SwIndex ref on the deleting node. - pTargetShell->SttEndDoc( true ); - SwNodeIndex aTargetIdx( pTargetNodes->GetEndOfContent(), -1 ); - pTargetNodes->Delete( aTargetIdx, 1 ); - } + pTargetDoc->Append( *(rWorkShell.GetDoc()), nStartingPageNo, pTargetPageDesc, nDocNo == 1 ); - //convert fields in page styles (header/footer - has to be done after the first document has been pasted - if(1 == nDocNo) - { - pTargetShell->CalcLayout(); - pTargetShell->ConvertFieldsToText(); - } + // #i72820# calculate layout to be able to find the correct page index + pTargetShell->CalcLayout(); } else { @@ -2775,7 +2741,8 @@ sal_Int32 SwDBManager::MergeDocuments( SwMailMergeConfigItem& rMMConfig, pTargetView->AttrChangedNotify( &pTargetView->GetWrtShell() ); SwWrtShell* pTargetShell = pTargetView->GetWrtShellPtr(); SwDoc* pTargetDoc = pTargetShell->GetDoc(); - SwNodes* pTargetNodes = &pTargetDoc->GetNodes(); + + pTargetView->GetDocShell()->_LoadStyles( *rSourceView.GetDocShell(), true ); // #i63806# const SwPageDesc* pSourcePageDesc = rSourceShell.FindPageDescByName( sStartingPageDesc ); @@ -2852,21 +2819,16 @@ sal_Int32 SwDBManager::MergeDocuments( SwMailMergeConfigItem& rMMConfig, } // insert the document into the target document - rWorkShell.SttEndDoc(false); - rWorkShell.SttEndDoc(true); - rWorkShell.SelAll(); - pTargetShell->SttEndDoc(false); //#i63806# put the styles to the target document //if the source uses headers or footers each new copy need to copy a new page styles + SwPageDesc* pTargetPageDesc; if(bPageStylesWithHeaderFooter) { //create a new pagestyle //copy the pagedesc from the current document to the new document and change the name of the to-be-applied style - OUString sNewPageDescName = lcl_FindUniqueName(pTargetShell, sStartingPageDesc, nDocNo ); - pTargetShell->GetDoc()->MakePageDesc( sNewPageDescName ); - SwPageDesc* pTargetPageDesc = pTargetShell->FindPageDescByName( sNewPageDescName ); + pTargetPageDesc = pTargetDoc->MakePageDesc( sNewPageDescName ); const SwPageDesc* pWorkPageDesc = rWorkShell.FindPageDescByName( sStartingPageDesc ); if(pWorkPageDesc && pTargetPageDesc) @@ -2876,50 +2838,20 @@ sal_Int32 SwDBManager::MergeDocuments( SwMailMergeConfigItem& rMMConfig, lcl_CopyFollowPageDesc( *pTargetShell, *pWorkPageDesc, *pTargetPageDesc, nDocNo ); } } - if(nDocNo == 1 || bPageStylesWithHeaderFooter) - pTargetView->GetDocShell()->_LoadStyles( *rSourceView.GetDocShell(), true ); - if(nDocNo > 1) - pTargetShell->InsertPageBreak( &sModifiedStartingPageDesc, nStartingPageNo ); else - pTargetShell->SetPageStyle(sModifiedStartingPageDesc); + pTargetPageDesc = pTargetShell->FindPageDescByName( sModifiedStartingPageDesc ); sal_uInt16 nPageCountBefore = pTargetShell->GetPageCnt(); OSL_ENSURE(!pTargetShell->GetTableFmt(),"target document ends with a table - paragraph should be appended"); - bool para_added = false; - - //#i51359# add a second paragraph in case there's only one - { - SwNodeIndex aIdx( pWorkDoc->GetNodes().GetEndOfExtras(), 2 ); - SwPosition aTestPos( aIdx ); - SwCursor aTestCrsr( aTestPos, 0, false ); - if ( !aTestCrsr.MovePara(fnParaNext, fnParaStart) ) - { - //append a paragraph - pWorkDoc->getIDocumentContentOperations().AppendTxtNode( aTestPos ); - para_added = true; - } - } #ifdef DBG_UTIL if ( nDocNo <= MAX_DOC_DUMP ) lcl_SaveDoc( xWorkDocSh, "WorkDoc", nDocNo ); #endif - pTargetShell->Paste( rWorkShell.GetDoc(), true ); - - if ( para_added ) { - // Move cursor to the start or Delete will assert because - // of the cursors SwIndex ref on the deleting node. - pTargetShell->SttEndDoc( true ); - SwNodeIndex aTargetIdx( pTargetNodes->GetEndOfContent(), -1 ); - pTargetNodes->Delete( aTargetIdx, 1 ); - } + pTargetDoc->Append( *(rWorkShell.GetDoc()), nStartingPageNo, pTargetPageDesc, nDocNo == 1 ); - //convert fields in page styles (header/footer - has to be done after the first document has been pasted - if(1 == nDocNo) - { - pTargetShell->CalcLayout(); - pTargetShell->ConvertFieldsToText(); - } + // #i72820# calculate layout to be able to find the correct page index + pTargetShell->CalcLayout(); #ifdef DBG_UTIL if ( nDocNo <= MAX_DOC_DUMP ) lcl_SaveDoc( xTargetDocShell, "MergeDoc" ); @@ -2928,8 +2860,6 @@ sal_Int32 SwDBManager::MergeDocuments( SwMailMergeConfigItem& rMMConfig, // add the document info to the config item SwDocMergeInfo aMergeInfo; aMergeInfo.nStartPageInTarget = nPageCountBefore; - //#i72820# calculate layout to be able to find the correct page index - pTargetShell->CalcLayout(); aMergeInfo.nEndPageInTarget = pTargetShell->GetPageCnt(); aMergeInfo.nDBRow = nStartRow; rMMConfig.AddMergedDocument( aMergeInfo ); -- cgit v1.2.3