summaryrefslogtreecommitdiff
path: root/sw/source
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2014-11-09 15:30:08 +0100
committerLuboš Luňák <l.lunak@collabora.com>2014-11-09 19:45:27 +0100
commit738fb2ad77e5a1a4d6e2dc540886a17f4527e4db (patch)
tree2c0e0b5c4c4cef085bf4ed41766099502b0ac46e /sw/source
parentb21df5a993a3815cf736fe3d2eab73eee646b38e (diff)
faster mapping from nodes to SwFrmFmt's anchored at them
The SwFrmFmtAnchorMap class provides reverse mapping to SwFrmFmt::GetAnchor().GetCntntAnchor(), so that when code somewhere needs to update SwFrmFmt's anchored at a position, it's not necessary to iterate over all of them (which can be a large number e.g. with mail merge). One special catch with the multimap of SwNodeIndex keys is that the values of those keys change (whenever the node structure of the document changes, indexes of nodes change as a result). This makes it impossible to use any hashing container, as the hashes would change without the container noticing, but multimap should work fine, as it just requires that the keys remain sorted, and that is the case. Nevertheless, the old code in the two converted places is intentionally left there in debug mode to verify the reverse mapping is updated correctly. I intentionally went with SwNodeIndex rather than SwPosition, as SwIndex (the other component of SwPosition) was causing some trouble (see e.g. the SwPosition comparison operator< , where two same positions are different if one is registered and the other not) and it doesn't appear to be actually necessary. Change-Id: I7f1768558f60155d4ba83c84aa7f9e34dc65ebf9
Diffstat (limited to 'sw/source')
-rw-r--r--sw/source/core/attr/swatrset.cxx27
-rw-r--r--sw/source/core/doc/docnew.cxx2
-rw-r--r--sw/source/core/inc/flyfrm.hxx2
-rw-r--r--sw/source/core/inc/frmtool.hxx2
-rw-r--r--sw/source/core/layout/atrfrm.cxx83
-rw-r--r--sw/source/core/layout/frmtool.cxx35
-rw-r--r--sw/source/core/layout/tabfrm.cxx2
-rw-r--r--sw/source/core/txtnode/ndtxt.cxx35
8 files changed, 175 insertions, 13 deletions
diff --git a/sw/source/core/attr/swatrset.cxx b/sw/source/core/attr/swatrset.cxx
index 383abcfaa80e..62b30cc025dc 100644
--- a/sw/source/core/attr/swatrset.cxx
+++ b/sw/source/core/attr/swatrset.cxx
@@ -27,6 +27,7 @@
#include <editeng/lineitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/editeng.hxx>
+#include <fmtanchr.hxx>
#include <fmtpdsc.hxx>
#include <hintids.hxx>
#include <istyleaccess.hxx>
@@ -380,12 +381,15 @@ void SwAttrSet::CopyToModify( SwModify& rMod ) const
}
}
+ boost::scoped_ptr< SfxItemSet > tmpSet;
+
const SwPageDesc* pPgDesc;
if( pSrcDoc != pDstDoc && SfxItemState::SET == GetItemState(
RES_PAGEDESC, false, &pItem ) &&
0 != ( pPgDesc = ((SwFmtPageDesc*)pItem)->GetPageDesc()) )
{
- SfxItemSet aTmpSet( *this );
+ if( !tmpSet )
+ tmpSet.reset( new SfxItemSet( *this ));
SwPageDesc* pDstPgDesc = pDstDoc->FindPageDesc(pPgDesc->GetName());
if( !pDstPgDesc )
@@ -395,20 +399,33 @@ void SwAttrSet::CopyToModify( SwModify& rMod ) const
}
SwFmtPageDesc aDesc( pDstPgDesc );
aDesc.SetNumOffset( ((SwFmtPageDesc*)pItem)->GetNumOffset() );
- aTmpSet.Put( aDesc );
+ tmpSet->Put( aDesc );
+ }
+ if( pSrcDoc != pDstDoc && SfxItemState::SET == GetItemState( RES_ANCHOR, false, &pItem )
+ && static_cast< const SwFmtAnchor* >( pItem )->GetCntntAnchor() != NULL )
+ {
+ if( !tmpSet )
+ tmpSet.reset( new SfxItemSet( *this ));
+ // Anchors at any node position cannot be copied to another document, because the SwPosition
+ // would still point to the old document. It needs to be fixed up explicitly.
+ tmpSet->ClearItem( RES_ANCHOR );
+ }
+
+ if( tmpSet )
+ {
if( pCNd )
{
// #i92811#
if ( pNewListIdItem != 0 )
{
- aTmpSet.Put( *pNewListIdItem );
+ tmpSet->Put( *pNewListIdItem );
}
- pCNd->SetAttr( aTmpSet );
+ pCNd->SetAttr( *tmpSet );
}
else
{
- pFmt->SetFmtAttr( aTmpSet );
+ pFmt->SetFmtAttr( *tmpSet );
}
}
else if( pCNd )
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index 70bda8ca87ff..c6d353bd3b10 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -231,6 +231,7 @@ SwDoc::SwDoc()
mpDfltTxtFmtColl( new SwTxtFmtColl( GetAttrPool(), sTxtCollStr ) ),
mpDfltGrfFmtColl( new SwGrfFmtColl( GetAttrPool(), sGrfCollStr ) ),
mpFrmFmtTbl( new SwFrmFmts() ),
+ mpFrmFmtAnchorMap( new SwFrmFmtAnchorMap( this ) ),
mpCharFmtTbl( new SwCharFmts() ),
mpSpzFrmFmtTbl( new SwFrmFmts() ),
mpSectionFmtTbl( new SwSectionFmts() ),
@@ -609,6 +610,7 @@ SwDoc::~SwDoc()
delete mpDfltCharFmt;
delete mpDfltFrmFmt;
delete mpLayoutCache;
+ delete mpFrmFmtAnchorMap;
SfxItemPool::Free(mpAttrPool);
}
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index 33f0aa7ab8c6..3208259dc615 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -57,7 +57,7 @@ bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, bool bMove = true );
class SwFlyFrm : public SwLayoutFrm, public SwAnchoredObject
{
// is allowed to lock, implemented in frmtool.cxx
- friend void AppendObjs ( const SwFrmFmts *, sal_uLong, SwFrm *, SwPageFrm * );
+ friend void AppendObjs ( const SwFrmFmts *, sal_uLong, SwFrm *, SwPageFrm *, SwDoc* );
friend void Notify( SwFlyFrm *, SwPageFrm *pOld, const SwRect &rOld,
const SwRect* pOldPrt );
diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx
index 8df9df179ac7..8003042244f5 100644
--- a/sw/source/core/inc/frmtool.hxx
+++ b/sw/source/core/inc/frmtool.hxx
@@ -52,7 +52,7 @@ class SwFrmFmts;
#define GRFNUM_REPLACE 2
void AppendObjs( const SwFrmFmts *pTbl, sal_uLong nIndex,
- SwFrm *pFrm, SwPageFrm *pPage );
+ SwFrm *pFrm, SwPageFrm *pPage, SwDoc* doc );
// draw background with brush or graphics
// The 6th parameter indicates that the method should consider background
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index d9ffa19bfa1d..f3304f5fbe81 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -2423,6 +2423,16 @@ SwFrmFmt::SwFrmFmt(
{
}
+SwFrmFmt::~SwFrmFmt()
+{
+ if( !GetDoc()->IsInDtor())
+ {
+ const SwFmtAnchor& anchor = GetAnchor();
+ if( anchor.GetCntntAnchor() != NULL )
+ GetDoc()->GetFrmFmtAnchorMap()->Remove( this, anchor.GetCntntAnchor()->nNode );
+ }
+}
+
bool SwFrmFmt::supportsFullDrawingLayerFillAttributeSet() const
{
return true;
@@ -2490,6 +2500,31 @@ void SwFrmFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
{ // invalidate cached uno object
SetXObject(uno::Reference<uno::XInterface>(0));
}
+
+ const SwPosition* oldAnchorPosition = NULL;
+ const SwPosition* newAnchorPosition = NULL;
+ if( pNew && pNew->Which() == RES_ATTRSET_CHG )
+ {
+ const SfxPoolItem* tmp = NULL;
+ static_cast< const SwAttrSetChg* >(pNew)->GetChgSet()->GetItemState( RES_ANCHOR, false, &tmp );
+ if( tmp )
+ newAnchorPosition = static_cast< const SwFmtAnchor* >( tmp )->GetCntntAnchor();
+ }
+ if( pNew && pNew->Which() == RES_ANCHOR )
+ newAnchorPosition = static_cast< const SwFmtAnchor* >( pNew )->GetCntntAnchor();
+ if( pOld && pOld->Which() == RES_ATTRSET_CHG )
+ {
+ const SfxPoolItem* tmp = NULL;
+ static_cast< const SwAttrSetChg* >(pOld)->GetChgSet()->GetItemState( RES_ANCHOR, false, &tmp );
+ if( tmp )
+ oldAnchorPosition = static_cast< const SwFmtAnchor* >( tmp )->GetCntntAnchor();
+ }
+ if( pOld && pOld->Which() == RES_ANCHOR )
+ oldAnchorPosition = static_cast< const SwFmtAnchor* >( pOld )->GetCntntAnchor();
+ if( oldAnchorPosition != NULL && ( newAnchorPosition == NULL || oldAnchorPosition->nNode.GetIndex() != newAnchorPosition->nNode.GetIndex()))
+ GetDoc()->GetFrmFmtAnchorMap()->Remove( this, oldAnchorPosition->nNode );
+ if( newAnchorPosition != NULL && ( oldAnchorPosition == NULL || oldAnchorPosition->nNode.GetIndex() != newAnchorPosition->nNode.GetIndex()))
+ GetDoc()->GetFrmFmtAnchorMap()->Add( this, newAnchorPosition->nNode );
}
void SwFrmFmt::RegisterToFormat( SwFmt& rFmt )
@@ -3299,4 +3334,52 @@ bool IsFlyFrmFmtInHeader(const SwFrmFmt& rFmt)
return false;
}
+
+SwFrmFmtAnchorMap::SwFrmFmtAnchorMap( const SwDoc* _doc )
+: doc( _doc )
+{
+}
+
+void SwFrmFmtAnchorMap::Add( SwFrmFmt* fmt, const SwNodeIndex& pos )
+{
+ assert( pos.GetNode().GetDoc() == doc );
+ items.insert( std::make_pair( pos, fmt ));
+}
+
+void SwFrmFmtAnchorMap::Remove( SwFrmFmt* fmt, const SwNodeIndex& pos )
+{
+ assert( pos.GetNode().GetDoc() == doc );
+ typedef std::multimap< SwNodeIndex, SwFrmFmt* >::iterator iterator;
+ std::pair< iterator, iterator > range = items.equal_range( pos );
+ for( iterator it = range.first; it != range.second; ++it )
+ {
+ if( it->second == fmt )
+ {
+ items.erase( it );
+ return;
+ }
+ }
+ assert( false );
+}
+
+SwFrmFmtAnchorMap::const_iterator_pair SwFrmFmtAnchorMap::equal_range( const SwNodeIndex& pos ) const
+{
+ return items.equal_range( pos );
+}
+
+SwFrmFmtAnchorMap::const_iterator SwFrmFmtAnchorMap::lower_bound( const SwNodeIndex& pos ) const
+{
+ return items.lower_bound( pos );
+}
+
+SwFrmFmtAnchorMap::const_iterator SwFrmFmtAnchorMap::upper_bound( const SwNodeIndex& pos ) const
+{
+ return items.upper_bound( pos );
+}
+
+SwFrmFmtAnchorMap::const_iterator SwFrmFmtAnchorMap::end() const
+{
+ return items.end();
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 8d92e4fa594f..5132eecc9591 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -999,15 +999,36 @@ SwCntntNotify::~SwCntntNotify()
}
void AppendObjs( const SwFrmFmts *pTbl, sal_uLong nIndex,
- SwFrm *pFrm, SwPageFrm *pPage )
+ SwFrm *pFrm, SwPageFrm *pPage, SwDoc* doc )
{
+#if OSL_DEBUG_LEVEL > 0
+ std::list<SwFrmFmt*> checkFmts;
for ( sal_uInt16 i = 0; i < pTbl->size(); ++i )
{
- SwFrmFmt *pFmt = (SwFrmFmt*)(*pTbl)[i];
+ SwFrmFmt *pFmt = (*pTbl)[i];
const SwFmtAnchor &rAnch = pFmt->GetAnchor();
if ( rAnch.GetCntntAnchor() &&
(rAnch.GetCntntAnchor()->nNode.GetIndex() == nIndex) )
{
+ checkFmts.push_back( pFmt );
+ }
+ }
+#endif
+ SwFrmFmtAnchorMap::const_iterator_pair range = doc->GetFrmFmtAnchorMap()->equal_range( SwNodeIndex( doc->GetNodes(), nIndex ));
+ for( std::multimap< SwNodeIndex, SwFrmFmt* >::const_iterator it = range.first;
+ it != range.second;
+ )
+ {
+ SwFrmFmt *pFmt = it->second;
+ const SwFmtAnchor &rAnch = pFmt->GetAnchor();
+ if ( rAnch.GetCntntAnchor() &&
+ (rAnch.GetCntntAnchor()->nNode.GetIndex() == nIndex) )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ std::list<SwFrmFmt*>::iterator checkPos = std::find( checkFmts.begin(), checkFmts.end(), pFmt );
+ assert( checkPos != checkFmts.end());
+ checkFmts.erase( checkPos );
+#endif
const bool bFlyAtFly = rAnch.GetAnchorId() == FLY_AT_FLY; // LAYER_IMPL
//Is a frame or a SdrObject described?
const bool bSdrObj = RES_DRAWFRMFMT == pFmt->Which();
@@ -1025,8 +1046,8 @@ void AppendObjs( const SwFrmFmts *pTbl, sal_uLong nIndex,
if ( bSdrObj && 0 == (pSdrObj = pFmt->FindSdrObject()) )
{
OSL_ENSURE( !bSdrObj, "DrawObject not found." );
+ ++it;
pFmt->GetDoc()->DelFrmFmt( pFmt );
- --i;
continue;
}
if ( pSdrObj )
@@ -1071,7 +1092,11 @@ void AppendObjs( const SwFrmFmts *pTbl, sal_uLong nIndex,
}
}
}
+ ++it;
}
+#if OSL_DEBUG_LEVEL > 0
+ assert( checkFmts.empty());
+#endif
}
static bool lcl_ObjConnected( const SwFrmFmt *pFmt, const SwFrm* pSib )
@@ -1311,7 +1336,7 @@ void _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc,
pPrv = pFrm;
if ( !pTbl->empty() && bObjsDirect && !bDontCreateObjects )
- AppendObjs( pTbl, nIndex, pFrm, pPage );
+ AppendObjs( pTbl, nIndex, pFrm, pPage, pDoc );
}
else if ( pNd->IsTableNode() )
{ //Should we have encountered a table?
@@ -1531,7 +1556,7 @@ void _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc,
{
SwFlyFrm* pFly = pLay->FindFlyFrm();
if( pFly )
- AppendObjs( pTbl, nIndex, pFly, pPage );
+ AppendObjs( pTbl, nIndex, pFly, pPage, pDoc );
}
}
else
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index cbf90520ec43..bdc39aa8f2e8 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -1093,7 +1093,7 @@ bool SwTabFrm::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKee
while( pFrm )
{
nIndex = pFrm->GetNode()->GetIndex();
- AppendObjs( pTbl, nIndex, pFrm, pPage );
+ AppendObjs( pTbl, nIndex, pFrm, pPage, GetFmt()->GetDoc());
pFrm = pFrm->GetNextCntntFrm();
if( !pHeadline->IsAnLower( pFrm ) )
break;
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index bf15ea2521c6..0146d4f2a9ce 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -1106,6 +1106,8 @@ void SwTxtNode::Update(
}
// at-char anchored flys shouldn't be moved, either.
+#if OSL_DEBUG_LEVEL > 0
+ std::list<SwFrmFmt*> checkFmts;
const SwFrmFmts& rFmts = *GetDoc()->GetSpzFrmFmts();
for (SwFrmFmts::const_iterator pFmt = rFmts.begin(); pFmt != rFmts.end(); ++pFmt)
{
@@ -1116,10 +1118,43 @@ void SwTxtNode::Update(
// The fly is at-char anchored and has an anchor position.
SwIndex& rEndIdx = const_cast<SwIndex&>(pCntntAnchor->nContent);
if (&pCntntAnchor->nNode.GetNode() == this && rEndIdx.GetIndex() == rPos.GetIndex())
+ {
// The anchor position is exactly our insert position.
+ #if 0
rEndIdx.Assign(&aTmpIdxReg, rEndIdx.GetIndex());
+ #endif
+ checkFmts.push_back( *pFmt );
+ }
}
}
+#endif
+ SwFrmFmtAnchorMap::const_iterator_pair range = GetDoc()->GetFrmFmtAnchorMap()->equal_range( SwNodeIndex( *this ));
+ for( SwFrmFmtAnchorMap::const_iterator it = range.first;
+ it != range.second;
+ ++it )
+ {
+ SwFrmFmt *pFmt = it->second;
+ const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
+ const SwPosition* pCntntAnchor = rAnchor.GetCntntAnchor();
+ if (rAnchor.GetAnchorId() == FLY_AT_CHAR && pCntntAnchor)
+ {
+ // The fly is at-char anchored and has an anchor position.
+ SwIndex& rEndIdx = const_cast<SwIndex&>(pCntntAnchor->nContent);
+ if (&pCntntAnchor->nNode.GetNode() == this && rEndIdx.GetIndex() == rPos.GetIndex())
+ {
+ // The anchor position is exactly our insert position.
+ rEndIdx.Assign(&aTmpIdxReg, rEndIdx.GetIndex());
+#if OSL_DEBUG_LEVEL > 0
+ std::list<SwFrmFmt*>::iterator checkPos = std::find( checkFmts.begin(), checkFmts.end(), pFmt );
+ assert( checkPos != checkFmts.end());
+ checkFmts.erase( checkPos );
+#endif
+ }
+ }
+ }
+#if OSL_DEBUG_LEVEL > 0
+ assert( checkFmts.empty());
+#endif
}
// base class