/************************************************************** * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern sal_uInt16 GetHtmlMode( const SwDocShell* ); using namespace ::com::sun::star; sal_uInt16 SwDoc::GetFlyCount( FlyCntType eType ) const { const SwSpzFrmFmts& rFmts = *GetSpzFrmFmts(); sal_uInt16 nSize = rFmts.Count(); sal_uInt16 nCount = 0; const SwNodeIndex* pIdx; for ( sal_uInt16 i = 0; i < nSize; i++) { const SwFrmFmt* pFlyFmt = rFmts[ i ]; if( RES_FLYFRMFMT == pFlyFmt->Which() && 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() ) && pIdx->GetNodes().IsDocNodes() ) { const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ]; switch( eType ) { case FLYCNTTYPE_FRM: if(!pNd->IsNoTxtNode()) nCount++; break; case FLYCNTTYPE_GRF: if( pNd->IsGrfNode() ) nCount++; break; case FLYCNTTYPE_OLE: if(pNd->IsOLENode()) nCount++; break; default: nCount++; } } } return nCount; } // If you change this, also update SwXFrameEnumeration in unocoll. SwFrmFmt* SwDoc::GetFlyNum( sal_uInt16 nIdx, FlyCntType eType ) { SwSpzFrmFmts& rFmts = *GetSpzFrmFmts(); SwFrmFmt* pRetFmt = 0; sal_uInt16 nSize = rFmts.Count(); const SwNodeIndex* pIdx; sal_uInt16 nCount = 0; for( sal_uInt16 i = 0; !pRetFmt && i < nSize; ++i ) { SwFrmFmt* pFlyFmt = rFmts[ i ]; if( RES_FLYFRMFMT == pFlyFmt->Which() && 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() ) && pIdx->GetNodes().IsDocNodes() ) { const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ]; switch( eType ) { case FLYCNTTYPE_FRM: if( !pNd->IsNoTxtNode() && nIdx == nCount++) pRetFmt = pFlyFmt; break; case FLYCNTTYPE_GRF: if(pNd->IsGrfNode() && nIdx == nCount++ ) pRetFmt = pFlyFmt; break; case FLYCNTTYPE_OLE: if(pNd->IsOLENode() && nIdx == nCount++) pRetFmt = pFlyFmt; break; default: if(nIdx == nCount++) pRetFmt = pFlyFmt; } } } return pRetFmt; } Point lcl_FindAnchorLayPos( SwDoc& rDoc, const SwFmtAnchor& rAnch, const SwFrmFmt* pFlyFmt ) { Point aRet; if( rDoc.GetCurrentViewShell() ) //swmod 071107//swmod 071225 switch( rAnch.GetAnchorId() ) { case FLY_AS_CHAR: if( pFlyFmt && rAnch.GetCntntAnchor() ) { const SwFrm* pOld = ((SwFlyFrmFmt*)pFlyFmt)->GetFrm( &aRet, sal_False ); if( pOld ) aRet = pOld->Frm().Pos(); } break; case FLY_AT_PARA: case FLY_AT_CHAR: // LAYER_IMPL if( rAnch.GetCntntAnchor() ) { const SwPosition *pPos = rAnch.GetCntntAnchor(); const SwCntntNode* pNd = pPos->nNode.GetNode().GetCntntNode(); const SwFrm* pOld = pNd ? pNd->getLayoutFrm( rDoc.GetCurrentLayout(), &aRet, 0, sal_False ) : 0; if( pOld ) aRet = pOld->Frm().Pos(); } break; case FLY_AT_FLY: // LAYER_IMPL if( rAnch.GetCntntAnchor() ) { const SwFlyFrmFmt* pFmt = (SwFlyFrmFmt*)rAnch.GetCntntAnchor()-> nNode.GetNode().GetFlyFmt(); const SwFrm* pOld = pFmt ? pFmt->GetFrm( &aRet, sal_False ) : 0; if( pOld ) aRet = pOld->Frm().Pos(); } break; case FLY_AT_PAGE: { sal_uInt16 nPgNum = rAnch.GetPageNum(); const SwPageFrm *pPage = (SwPageFrm*)rDoc.GetCurrentLayout()->Lower(); for( sal_uInt16 i = 1; (i <= nPgNum) && pPage; ++i, pPage = (const SwPageFrm*)pPage->GetNext() ) if( i == nPgNum ) { aRet = pPage->Frm().Pos(); break; } } break; default: break; } return aRet; } #define MAKEFRMS 0 #define IGNOREANCHOR 1 #define DONTMAKEFRMS 2 sal_Int8 SwDoc::SetFlyFrmAnchor( SwFrmFmt& rFmt, SfxItemSet& rSet, sal_Bool bNewFrms ) { //Ankerwechsel sind fast immer in alle 'Richtungen' erlaubt. //Ausnahme: Absatz- bzw. Zeichengebundene Rahmen duerfen wenn sie in //Kopf-/Fusszeilen stehen nicht Seitengebunden werden. const SwFmtAnchor &rOldAnch = rFmt.GetAnchor(); const RndStdIds nOld = rOldAnch.GetAnchorId(); SwFmtAnchor aNewAnch( (SwFmtAnchor&)rSet.Get( RES_ANCHOR ) ); RndStdIds nNew = aNewAnch.GetAnchorId(); // ist der neue ein gueltiger Anker? if( !aNewAnch.GetCntntAnchor() && (FLY_AT_FLY == nNew || (FLY_AT_PARA == nNew) || (FLY_AS_CHAR == nNew) || (FLY_AT_CHAR == nNew) )) { return IGNOREANCHOR; } if( nOld == nNew ) return DONTMAKEFRMS; Point aOldAnchorPos( ::lcl_FindAnchorLayPos( *this, rOldAnch, &rFmt )); Point aNewAnchorPos( ::lcl_FindAnchorLayPos( *this, aNewAnch, 0 )); //Die alten Frms vernichten. Dabei werden die Views implizit gehidet und //doppeltes hiden waere so eine art Show! rFmt.DelFrms(); if ( FLY_AS_CHAR == nOld ) { //Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet //werden. Leider reisst dies neben den Frms auch noch das Format mit //in sein Grab. Um dass zu unterbinden loesen wir vorher die //Verbindung zwischen Attribut und Format. const SwPosition *pPos = rOldAnch.GetCntntAnchor(); SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode(); ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); const xub_StrLen nIdx = pPos->nContent.GetIndex(); SwTxtAttr * const pHnt = pTxtNode->GetTxtAttrForCharAt( nIdx, RES_TXTATR_FLYCNT ); ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT, "Missing FlyInCnt-Hint." ); ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == &rFmt, "Wrong TxtFlyCnt-Hint." ); const_cast(pHnt->GetFlyCnt()).SetFlyFmt(); //Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet //werden. pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx ); } //Endlich kann das Attribut gesetzt werden. Es muss das erste Attribut //sein; Undo depends on it! rFmt.SetFmtAttr( aNewAnch ); //Positionskorrekturen const SfxPoolItem* pItem; switch( nNew ) { case FLY_AS_CHAR: //Wenn keine Positionsattribute hereinkommen, dann muss dafuer //gesorgt werden, das keine unerlaubte automatische Ausrichtung //bleibt. { const SwPosition *pPos = aNewAnch.GetCntntAnchor(); SwTxtNode *pNd = pPos->nNode.GetNode().GetTxtNode(); ASSERT( pNd, "Crsr steht nicht auf TxtNode." ); SwFmtFlyCnt aFmt( static_cast(&rFmt) ); pNd->InsertItem( aFmt, pPos->nContent.GetIndex(), 0 ); } if( SFX_ITEM_SET != rSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem )) { SwFmtVertOrient aOldV( rFmt.GetVertOrient() ); sal_Bool bSet = sal_True; switch( aOldV.GetVertOrient() ) { case text::VertOrientation::LINE_TOP: aOldV.SetVertOrient( text::VertOrientation::TOP ); break; case text::VertOrientation::LINE_CENTER: aOldV.SetVertOrient( text::VertOrientation::CENTER); break; case text::VertOrientation::LINE_BOTTOM: aOldV.SetVertOrient( text::VertOrientation::BOTTOM); break; case text::VertOrientation::NONE: aOldV.SetVertOrient( text::VertOrientation::CENTER); break; default: bSet = sal_False; } if( bSet ) rSet.Put( aOldV ); } break; case FLY_AT_PARA: case FLY_AT_CHAR: // LAYER_IMPL case FLY_AT_FLY: // LAYER_IMPL case FLY_AT_PAGE: { //Wenn keine Positionsattribute hereinschneien korrigieren wir //die Position so, dass die Dokumentkoordinaten des Flys erhalten //bleiben. //Chg: Wenn sich in den Positionsattributen lediglich die //Ausrichtung veraendert (text::RelOrientation::FRAME vs. text::RelOrientation::PRTAREA), dann wird die //Position ebenfalls korrigiert. if( SFX_ITEM_SET != rSet.GetItemState( RES_HORI_ORIENT, sal_False, &pItem )) pItem = 0; SwFmtHoriOrient aOldH( rFmt.GetHoriOrient() ); if( text::HoriOrientation::NONE == aOldH.GetHoriOrient() && ( !pItem || aOldH.GetPos() == ((SwFmtHoriOrient*)pItem)->GetPos() )) { SwTwips nPos = (FLY_AS_CHAR == nOld) ? 0 : aOldH.GetPos(); nPos += aOldAnchorPos.X() - aNewAnchorPos.X(); if( pItem ) { SwFmtHoriOrient* pH = (SwFmtHoriOrient*)pItem; aOldH.SetHoriOrient( pH->GetHoriOrient() ); aOldH.SetRelationOrient( pH->GetRelationOrient() ); } aOldH.SetPos( nPos ); rSet.Put( aOldH ); } if( SFX_ITEM_SET != rSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem )) pItem = 0; SwFmtVertOrient aOldV( rFmt.GetVertOrient() ); // OD 2004-05-14 #i28922# - correction: compare if( text::VertOrientation::NONE == aOldV.GetVertOrient() && (!pItem || aOldV.GetPos() == ((SwFmtVertOrient*)pItem)->GetPos() ) ) { SwTwips nPos = (FLY_AS_CHAR == nOld) ? 0 : aOldV.GetPos(); nPos += aOldAnchorPos.Y() - aNewAnchorPos.Y(); if( pItem ) { SwFmtVertOrient* pV = (SwFmtVertOrient*)pItem; aOldV.SetVertOrient( pV->GetVertOrient() ); aOldV.SetRelationOrient( pV->GetRelationOrient() ); } aOldV.SetPos( nPos ); rSet.Put( aOldV ); } } break; default: break; } if( bNewFrms ) rFmt.MakeFrms(); return MAKEFRMS; } static bool lcl_SetFlyFrmAttr(SwDoc & rDoc, sal_Int8 (SwDoc::*pSetFlyFrmAnchor)(SwFrmFmt &, SfxItemSet &, sal_Bool), SwFrmFmt & rFlyFmt, SfxItemSet & rSet) { // #i32968# Inserting columns in the frame causes MakeFrmFmt to put two // objects of type SwUndoFrmFmt on the undo stack. We don't want them. ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); //Ist das Ankerattribut dabei? Falls ja ueberlassen wir die Verarbeitung //desselben einer Spezialmethode. Sie Returnt sal_True wenn der Fly neu //erzeugt werden muss (z.B. weil ein Wechsel des FlyTyps vorliegt). sal_Int8 const nMakeFrms = (SFX_ITEM_SET == rSet.GetItemState( RES_ANCHOR, sal_False )) ? (rDoc.*pSetFlyFrmAnchor)( rFlyFmt, rSet, sal_False ) : DONTMAKEFRMS; const SfxPoolItem* pItem; SfxItemIter aIter( rSet ); SfxItemSet aTmpSet( rDoc.GetAttrPool(), aFrmFmtSetRange ); sal_uInt16 nWhich = aIter.GetCurItem()->Which(); do { switch( nWhich ) { case RES_FILL_ORDER: case RES_BREAK: case RES_PAGEDESC: case RES_CNTNT: case RES_FOOTER: OSL_ENSURE(false, ":-) unknown Attribute for Fly."); // kein break; case RES_CHAIN: rSet.ClearItem( nWhich ); break; case RES_ANCHOR: if( DONTMAKEFRMS != nMakeFrms ) break; default: if( !IsInvalidItem( aIter.GetCurItem() ) && ( SFX_ITEM_SET != rFlyFmt.GetAttrSet().GetItemState( nWhich, sal_True, &pItem ) || *pItem != *aIter.GetCurItem() )) aTmpSet.Put( *aIter.GetCurItem() ); break; } if( aIter.IsAtEnd() ) break; } while( 0 != ( nWhich = aIter.NextItem()->Which() ) ); if( aTmpSet.Count() ) rFlyFmt.SetFmtAttr( aTmpSet ); if( MAKEFRMS == nMakeFrms ) rFlyFmt.MakeFrms(); return aTmpSet.Count() || MAKEFRMS == nMakeFrms; } void SwDoc::CheckForUniqueItemForLineFillNameOrIndex(SfxItemSet& rSet) { SwDrawModel* pDrawModel = GetOrCreateDrawModel(); SfxItemIter aIter(rSet); for(const SfxPoolItem* pItem = aIter.FirstItem(); pItem; pItem = aIter.NextItem()) { const SfxPoolItem* pResult = pItem; switch(pItem->Which()) { case XATTR_FILLBITMAP: { pResult = static_cast< const XFillBitmapItem* >(pItem)->checkForUniqueItem(pDrawModel); break; } case XATTR_LINEDASH: { pResult = static_cast< const XLineDashItem* >(pItem)->checkForUniqueItem(pDrawModel); break; } case XATTR_LINESTART: { pResult = static_cast< const XLineStartItem* >(pItem)->checkForUniqueItem(pDrawModel); break; } case XATTR_LINEEND: { pResult = static_cast< const XLineEndItem* >(pItem)->checkForUniqueItem(pDrawModel); break; } case XATTR_FILLGRADIENT: { pResult = static_cast< const XFillGradientItem* >(pItem)->checkForUniqueItem(pDrawModel); break; } case XATTR_FILLFLOATTRANSPARENCE: { pResult = static_cast< const XFillFloatTransparenceItem* >(pItem)->checkForUniqueItem(pDrawModel); break; } case XATTR_FILLHATCH: { pResult = static_cast< const XFillHatchItem* >(pItem)->checkForUniqueItem(pDrawModel); break; } } if(pResult != pItem) { rSet.Put(*pResult); delete pResult; } } } sal_Bool SwDoc::SetFlyFrmAttr( SwFrmFmt& rFlyFmt, SfxItemSet& rSet ) { if( !rSet.Count() ) return sal_False; ::std::auto_ptr pSaveUndo; if (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().ClearRedo(); // AppendUndo far below, so leave it pSaveUndo.reset( new SwUndoFmtAttrHelper( rFlyFmt ) ); } bool const bRet = lcl_SetFlyFrmAttr(*this, &SwDoc::SetFlyFrmAnchor, rFlyFmt, rSet); if ( pSaveUndo.get() ) { if ( pSaveUndo->GetUndo() ) { GetIDocumentUndoRedo().AppendUndo( pSaveUndo->ReleaseUndo() ); } } SetModified(); return bRet; } // --> OD 2009-07-20 #i73249# void SwDoc::SetFlyFrmTitle( SwFlyFrmFmt& rFlyFrmFmt, const String& sNewTitle ) { if ( rFlyFrmFmt.GetObjTitle() == sNewTitle ) { return; } ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo()); if (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt, UNDO_FLYFRMFMT_TITLE, rFlyFrmFmt.GetObjTitle(), sNewTitle ) ); } rFlyFrmFmt.SetObjTitle( sNewTitle, true ); SetModified(); } void SwDoc::SetFlyFrmDescription( SwFlyFrmFmt& rFlyFrmFmt, const String& sNewDescription ) { if ( rFlyFrmFmt.GetObjDescription() == sNewDescription ) { return; } ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo()); if (GetIDocumentUndoRedo().DoesUndo()) { GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt, UNDO_FLYFRMFMT_DESCRIPTION, rFlyFrmFmt.GetObjDescription(), sNewDescription ) ); } rFlyFrmFmt.SetObjDescription( sNewDescription, true ); SetModified(); } // <-- sal_Bool SwDoc::SetFrmFmtToFly( SwFrmFmt& rFmt, SwFrmFmt& rNewFmt, SfxItemSet* pSet, sal_Bool bKeepOrient ) { sal_Bool bChgAnchor = sal_False, bFrmSz = sal_False; const SwFmtFrmSize aFrmSz( rFmt.GetFrmSize() ); const SwFmtVertOrient aVert( rFmt.GetVertOrient() ); const SwFmtHoriOrient aHori( rFmt.GetHoriOrient() ); SwUndoSetFlyFmt* pUndo = 0; bool const bUndo = GetIDocumentUndoRedo().DoesUndo(); if (bUndo) { pUndo = new SwUndoSetFlyFmt( rFmt, rNewFmt ); GetIDocumentUndoRedo().AppendUndo(pUndo); } // #i32968# Inserting columns in the section causes MakeFrmFmt to put // 2 objects of type SwUndoFrmFmt on the undo stack. We don't want them. ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); //Erstmal die Spalten setzen, sonst gibts nix als Aerger mit dem //Set/Reset/Abgleich usw. const SfxPoolItem* pItem; if( SFX_ITEM_SET != rNewFmt.GetAttrSet().GetItemState( RES_COL )) rFmt.ResetFmtAttr( RES_COL ); if( rFmt.DerivedFrom() != &rNewFmt ) { rFmt.SetDerivedFrom( &rNewFmt ); // 1. wenn nicht automatisch -> ignorieren, sonst -> wech // 2. wech damit, MB! if( SFX_ITEM_SET == rNewFmt.GetAttrSet().GetItemState( RES_FRM_SIZE, sal_False )) { rFmt.ResetFmtAttr( RES_FRM_SIZE ); bFrmSz = sal_True; } const SfxItemSet* pAsk = pSet; if( !pAsk ) pAsk = &rNewFmt.GetAttrSet(); if( SFX_ITEM_SET == pAsk->GetItemState( RES_ANCHOR, sal_False, &pItem ) && ((SwFmtAnchor*)pItem)->GetAnchorId() != rFmt.GetAnchor().GetAnchorId() ) { if( pSet ) bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, *pSet, sal_False ); else { //JP 23.04.98: muss den FlyFmt-Range haben, denn im SetFlyFrmAnchor // werden Attribute in diesen gesetzt! SfxItemSet aFlySet( *rNewFmt.GetAttrSet().GetPool(), rNewFmt.GetAttrSet().GetRanges() ); aFlySet.Put( *pItem ); bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, aFlySet, sal_False); } } } //Hori und Vert nur dann resetten, wenn in der Vorlage eine //automatische Ausrichtung eingestellt ist, anderfalls den alten Wert //wieder hineinstopfen. //JP 09.06.98: beim Update der RahmenVorlage sollte der Fly NICHT // seine Orientierng verlieren (diese wird nicht geupdatet!) //OS: #96584# text::HoriOrientation::NONE and text::VertOrientation::NONE are allowed now if (!bKeepOrient) { rFmt.ResetFmtAttr(RES_VERT_ORIENT); rFmt.ResetFmtAttr(RES_HORI_ORIENT); } rFmt.ResetFmtAttr( RES_PRINT, RES_SURROUND ); rFmt.ResetFmtAttr( RES_LR_SPACE, RES_UL_SPACE ); rFmt.ResetFmtAttr( RES_BACKGROUND, RES_COL ); rFmt.ResetFmtAttr( RES_URL, RES_EDIT_IN_READONLY ); if( !bFrmSz ) rFmt.SetFmtAttr( aFrmSz ); if( bChgAnchor ) rFmt.MakeFrms(); if( pUndo ) pUndo->DeRegisterFromFormat( rFmt ); SetModified(); return bChgAnchor; } void SwDoc::GetGrfNms( const SwFlyFrmFmt& rFmt, String* pGrfName, String* pFltName ) const { SwNodeIndex aIdx( *rFmt.GetCntnt().GetCntntIdx(), 1 ); const SwGrfNode* pGrfNd = aIdx.GetNode().GetGrfNode(); if( pGrfNd && pGrfNd->IsLinkedFile() ) pGrfNd->GetFileFilterNms( pGrfName, pFltName ); } sal_Bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList, RndStdIds _eAnchorType, const sal_Bool _bSameOnly, const sal_Bool _bPosCorr ) { ASSERT( GetCurrentLayout(), "Ohne Layout geht gar nichts" ); //swmod 080218 if ( !_rMrkList.GetMarkCount() || _rMrkList.GetMark( 0 )->GetMarkedSdrObj()->GetUpGroup() ) { return false; } GetIDocumentUndoRedo().StartUndo( UNDO_INSATTR, NULL ); sal_Bool bUnmark = sal_False; for ( sal_uInt16 i = 0; i < _rMrkList.GetMarkCount(); ++i ) { SdrObject* pObj = _rMrkList.GetMark( i )->GetMarkedSdrObj(); if ( !pObj->ISA(SwVirtFlyDrawObj) ) { SwDrawContact* pContact = static_cast(GetUserCall(pObj)); // OD 27.06.2003 #108784# - consider, that drawing object has // no user call. E.g.: a 'virtual' drawing object is disconnected by // the anchor type change of the 'master' drawing object. // Continue with next selected object and assert, if this isn't excepted. if ( !pContact ) { #ifdef DBG_UTIL bool bNoUserCallExcepted = pObj->ISA(SwDrawVirtObj) && !static_cast(pObj)->IsConnected(); ASSERT( bNoUserCallExcepted, "SwDoc::ChgAnchor(..) - no contact at selected drawing object" ); #endif continue; } // OD 2004-03-29 #i26791# const SwFrm* pOldAnchorFrm = pContact->GetAnchorFrm( pObj ); const SwFrm* pNewAnchorFrm = pOldAnchorFrm; // --> OD 2006-03-01 #i54336# // Instead of only keeping the index position for an as-character // anchored object the complete is kept, because the // anchor index position could be moved, if the object again is // anchored as character. // xub_StrLen nIndx = STRING_NOTFOUND; const SwPosition* pOldAsCharAnchorPos( 0L ); const RndStdIds eOldAnchorType = pContact->GetAnchorId(); if ( !_bSameOnly && eOldAnchorType == FLY_AS_CHAR ) { pOldAsCharAnchorPos = new SwPosition( pContact->GetCntntAnchor() ); } // <-- if ( _bSameOnly ) _eAnchorType = eOldAnchorType; SwFmtAnchor aNewAnch( _eAnchorType ); Rectangle aObjRect( pContact->GetAnchoredObj( pObj )->GetObjRect().SVRect() ); const Point aPt( aObjRect.TopLeft() ); switch ( _eAnchorType ) { case FLY_AT_PARA: case FLY_AT_CHAR: { const Point aNewPoint = pOldAnchorFrm && ( pOldAnchorFrm->IsVertical() || pOldAnchorFrm->IsRightToLeft() ) ? aObjRect.TopRight() : aPt; // OD 18.06.2003 #108784# - allow drawing objects in header/footer pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aNewPoint, false ); if ( pNewAnchorFrm->IsTxtFrm() && ((SwTxtFrm*)pNewAnchorFrm)->IsFollow() ) { pNewAnchorFrm = ((SwTxtFrm*)pNewAnchorFrm)->FindMaster(); } if ( pNewAnchorFrm->IsProtected() ) { pNewAnchorFrm = 0; } else { SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() ); aNewAnch.SetType( _eAnchorType ); aNewAnch.SetAnchor( &aPos ); } } break; case FLY_AT_FLY: // LAYER_IMPL { //Ausgehend von der linken oberen Ecke des Fly den //dichtesten SwFlyFrm suchen. SwFrm *pTxtFrm; { SwCrsrMoveState aState( MV_SETONLYTEXT ); SwPosition aPos( GetNodes() ); Point aPoint( aPt ); aPoint.X() -= 1; GetCurrentLayout()->GetCrsrOfst( &aPos, aPoint, &aState ); // OD 20.06.2003 #108784# - consider that drawing objects // can be in header/footer. Thus, by left-top-corner pTxtFrm = aPos.nNode.GetNode(). GetCntntNode()->getLayoutFrm( GetCurrentLayout(), &aPt, 0, sal_False ); } const SwFrm *pTmp = ::FindAnchor( pTxtFrm, aPt ); pNewAnchorFrm = pTmp->FindFlyFrm(); if( pNewAnchorFrm && !pNewAnchorFrm->IsProtected() ) { const SwFrmFmt *pTmpFmt = ((SwFlyFrm*)pNewAnchorFrm)->GetFmt(); const SwFmtCntnt& rCntnt = pTmpFmt->GetCntnt(); SwPosition aPos( *rCntnt.GetCntntIdx() ); aNewAnch.SetAnchor( &aPos ); break; } aNewAnch.SetType( FLY_AT_PAGE ); // no break } case FLY_AT_PAGE: { pNewAnchorFrm = GetCurrentLayout()->Lower(); while ( pNewAnchorFrm && !pNewAnchorFrm->Frm().IsInside( aPt ) ) pNewAnchorFrm = pNewAnchorFrm->GetNext(); if ( !pNewAnchorFrm ) continue; aNewAnch.SetPageNum( ((SwPageFrm*)pNewAnchorFrm)->GetPhyPageNum()); } break; case FLY_AS_CHAR: if( _bSameOnly ) // Positions/Groessenaenderung { if( !pOldAnchorFrm ) { pContact->ConnectToLayout(); pOldAnchorFrm = pContact->GetAnchorFrm(); } ((SwTxtFrm*)pOldAnchorFrm)->Prepare(); } else // Ankerwechsel { // OD 18.06.2003 #108784# - allow drawing objects in header/footer pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aPt, false ); if( pNewAnchorFrm->IsProtected() ) { pNewAnchorFrm = 0; break; } bUnmark = ( 0 != i ); Point aPoint( aPt ); aPoint.X() -= 1; // nicht im DrawObj landen!! aNewAnch.SetType( FLY_AS_CHAR ); SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() ); if ( pNewAnchorFrm->Frm().IsInside( aPoint ) ) { // es muss ein TextNode gefunden werden, denn nur dort // ist ein inhaltsgebundenes DrawObjekt zu verankern SwCrsrMoveState aState( MV_SETONLYTEXT ); GetCurrentLayout()->GetCrsrOfst( &aPos, aPoint, &aState ); //swmod 080218 } else { SwCntntNode &rCNd = (SwCntntNode&) *((SwCntntFrm*)pNewAnchorFrm)->GetNode(); if ( pNewAnchorFrm->Frm().Bottom() < aPt.Y() ) rCNd.MakeStartIndex( &aPos.nContent ); else rCNd.MakeEndIndex( &aPos.nContent ); } aNewAnch.SetAnchor( &aPos ); SetAttr( aNewAnch, *pContact->GetFmt() ); // OD 2004-04-13 #i26791# - adjust vertical positioning to // 'center to baseline' SetAttr( SwFmtVertOrient( 0, text::VertOrientation::CENTER, text::RelOrientation::FRAME ), *pContact->GetFmt() ); SwTxtNode *pNd = aPos.nNode.GetNode().GetTxtNode(); ASSERT( pNd, "Cursor not positioned at TxtNode." ); SwFmtFlyCnt aFmt( pContact->GetFmt() ); pNd->InsertItem( aFmt, aPos.nContent.GetIndex(), 0 ); } break; default: ASSERT( sal_False, "unexpected AnchorId." ); } if ( (FLY_AS_CHAR != _eAnchorType) && pNewAnchorFrm && ( !_bSameOnly || pNewAnchorFrm != pOldAnchorFrm ) ) { // OD 2004-04-06 #i26791# - Direct object positioning no longer // needed. Apply of attributes (method call ) takes // care of the invalidation of the object position. SetAttr( aNewAnch, *pContact->GetFmt() ); if ( _bPosCorr ) { // --> OD 2004-08-24 #i33313# - consider not connected // 'virtual' drawing objects if ( pObj->ISA(SwDrawVirtObj) && !static_cast(pObj)->IsConnected() ) { SwRect aNewObjRect( aObjRect ); static_cast(pContact->GetAnchoredObj( 0L )) ->AdjustPositioningAttr( pNewAnchorFrm, &aNewObjRect ); } else { static_cast(pContact->GetAnchoredObj( pObj )) ->AdjustPositioningAttr( pNewAnchorFrm ); } } } // --> OD 2006-03-01 #i54336# if ( pNewAnchorFrm && pOldAsCharAnchorPos ) { //Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet //werden. Leider reisst dies neben den Frms auch noch das Format mit //in sein Grab. Um dass zu unterbinden loesen wir vorher die //Verbindung zwischen Attribut und Format. const xub_StrLen nIndx( pOldAsCharAnchorPos->nContent.GetIndex() ); SwTxtNode* pTxtNode( pOldAsCharAnchorPos->nNode.GetNode().GetTxtNode() ); ASSERT( pTxtNode, " - missing previous anchor text node for as-character anchored object" ); ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); SwTxtAttr * const pHnt = pTxtNode->GetTxtAttrForCharAt( nIndx, RES_TXTATR_FLYCNT ); const_cast(pHnt->GetFlyCnt()).SetFlyFmt(); //Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet //werden. pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIndx, nIndx ); delete pOldAsCharAnchorPos; } // <-- } } GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); SetModified(); return bUnmark; } int SwDoc::Chainable( const SwFrmFmt &rSource, const SwFrmFmt &rDest ) { //Die Source darf noch keinen Follow haben. const SwFmtChain &rOldChain = rSource.GetChain(); if ( rOldChain.GetNext() ) return SW_CHAIN_SOURCE_CHAINED; //Ziel darf natuerlich nicht gleich Source sein und es //darf keine geschlossene Kette entstehen. const SwFrmFmt *pFmt = &rDest; do { if( pFmt == &rSource ) return SW_CHAIN_SELF; pFmt = pFmt->GetChain().GetNext(); } while ( pFmt ); //Auch eine Verkettung von Innen nach aussen oder von aussen //nach innen ist nicht zulaessig. if( rDest.IsLowerOf( rSource ) || rSource .IsLowerOf( rDest ) ) return SW_CHAIN_SELF; //Das Ziel darf noch keinen Master haben. const SwFmtChain &rChain = rDest.GetChain(); if( rChain.GetPrev() ) return SW_CHAIN_IS_IN_CHAIN; //Das Ziel muss leer sein. const SwNodeIndex* pCntIdx = rDest.GetCntnt().GetCntntIdx(); if( !pCntIdx ) return SW_CHAIN_NOT_FOUND; SwNodeIndex aNxtIdx( *pCntIdx, 1 ); const SwTxtNode* pTxtNd = aNxtIdx.GetNode().GetTxtNode(); if( !pTxtNd ) return SW_CHAIN_NOT_FOUND; const sal_uLong nFlySttNd = pCntIdx->GetIndex(); if( 2 != ( pCntIdx->GetNode().EndOfSectionIndex() - nFlySttNd ) || pTxtNd->GetTxt().Len() ) return SW_CHAIN_NOT_EMPTY; sal_uInt16 nArrLen = GetSpzFrmFmts()->Count(); for( sal_uInt16 n = 0; n < nArrLen; ++n ) { const SwFmtAnchor& rAnchor = (*GetSpzFrmFmts())[ n ]->GetAnchor(); sal_uLong nTstSttNd; // OD 11.12.2003 #i20622# - to-frame anchored objects are allowed. if ( ((rAnchor.GetAnchorId() == FLY_AT_PARA) || (rAnchor.GetAnchorId() == FLY_AT_CHAR)) && 0 != rAnchor.GetCntntAnchor() && nFlySttNd <= ( nTstSttNd = rAnchor.GetCntntAnchor()->nNode.GetIndex() ) && nTstSttNd < nFlySttNd + 2 ) { return SW_CHAIN_NOT_EMPTY; } } //Auf die richtige Area muessen wir auch noch einen Blick werfen. //Beide Flys muessen im selben Bereich (Body, Head/Foot, Fly) sitzen //Wenn die Source nicht der selektierte Rahmen ist, so reicht es //Wenn ein passender gefunden wird (Der Wunsch kann z.B. von der API //kommen). // both in the same fly, header, footer or on the page? const SwFmtAnchor &rSrcAnchor = rSource.GetAnchor(), &rDstAnchor = rDest.GetAnchor(); sal_uLong nEndOfExtras = GetNodes().GetEndOfExtras().GetIndex(); sal_Bool bAllowed = sal_False; if ( FLY_AT_PAGE == rSrcAnchor.GetAnchorId() ) { if ( (FLY_AT_PAGE == rDstAnchor.GetAnchorId()) || ( rDstAnchor.GetCntntAnchor() && rDstAnchor.GetCntntAnchor()->nNode.GetIndex() > nEndOfExtras )) bAllowed = sal_True; } else if( rSrcAnchor.GetCntntAnchor() && rDstAnchor.GetCntntAnchor() ) { const SwNodeIndex &rSrcIdx = rSrcAnchor.GetCntntAnchor()->nNode, &rDstIdx = rDstAnchor.GetCntntAnchor()->nNode; const SwStartNode* pSttNd = 0; if( rSrcIdx == rDstIdx || ( !pSttNd && 0 != ( pSttNd = rSrcIdx.GetNode().FindFlyStartNode() ) && pSttNd == rDstIdx.GetNode().FindFlyStartNode() ) || ( !pSttNd && 0 != ( pSttNd = rSrcIdx.GetNode().FindFooterStartNode() ) && pSttNd == rDstIdx.GetNode().FindFooterStartNode() ) || ( !pSttNd && 0 != ( pSttNd = rSrcIdx.GetNode().FindHeaderStartNode() ) && pSttNd == rDstIdx.GetNode().FindHeaderStartNode() ) || ( !pSttNd && rDstIdx.GetIndex() > nEndOfExtras && rSrcIdx.GetIndex() > nEndOfExtras )) bAllowed = sal_True; } return bAllowed ? SW_CHAIN_OK : SW_CHAIN_WRONG_AREA; } int SwDoc::Chain( SwFrmFmt &rSource, const SwFrmFmt &rDest ) { int nErr = Chainable( rSource, rDest ); if ( !nErr ) { GetIDocumentUndoRedo().StartUndo( UNDO_CHAINE, NULL ); SwFlyFrmFmt& rDestFmt = (SwFlyFrmFmt&)rDest; //Follow an den Master haengen. SwFmtChain aChain = rDestFmt.GetChain(); aChain.SetPrev( &(SwFlyFrmFmt&)rSource ); SetAttr( aChain, rDestFmt ); SfxItemSet aSet( GetAttrPool(), RES_FRM_SIZE, RES_FRM_SIZE, RES_CHAIN, RES_CHAIN, 0 ); //Follow an den Master haengen. aChain.SetPrev( &(SwFlyFrmFmt&)rSource ); SetAttr( aChain, rDestFmt ); //Master an den Follow haengen und dafuer sorgen, dass der Master //eine fixierte Hoehe hat. aChain = rSource.GetChain(); aChain.SetNext( &rDestFmt ); aSet.Put( aChain ); SwFmtFrmSize aSize( rSource.GetFrmSize() ); if ( aSize.GetHeightSizeType() != ATT_FIX_SIZE ) { SwFlyFrm *pFly = SwIterator::FirstElement( rSource ); if ( pFly ) aSize.SetHeight( pFly->Frm().Height() ); aSize.SetHeightSizeType( ATT_FIX_SIZE ); aSet.Put( aSize ); } SetAttr( aSet, rSource ); GetIDocumentUndoRedo().EndUndo( UNDO_CHAINE, NULL ); } return nErr; } void SwDoc::Unchain( SwFrmFmt &rFmt ) { SwFmtChain aChain( rFmt.GetChain() ); if ( aChain.GetNext() ) { GetIDocumentUndoRedo().StartUndo( UNDO_UNCHAIN, NULL ); SwFrmFmt *pFollow = aChain.GetNext(); aChain.SetNext( 0 ); SetAttr( aChain, rFmt ); aChain = pFollow->GetChain(); aChain.SetPrev( 0 ); SetAttr( aChain, *pFollow ); GetIDocumentUndoRedo().EndUndo( UNDO_UNCHAIN, NULL ); } }