| /************************************************************** |
| * |
| * 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 <hintids.hxx> |
| #include <svl/itemiter.hxx> |
| #include <svx/svdobj.hxx> |
| #include <svx/svdpage.hxx> |
| #include <svx/svdmodel.hxx> |
| #include <svx/svdocapt.hxx> |
| #include <svx/svdmark.hxx> |
| #include <fmtfsize.hxx> |
| #include <fmtornt.hxx> |
| #include <fmtsrnd.hxx> |
| #include <dcontact.hxx> |
| |
| #include <ndgrf.hxx> |
| #include <doc.hxx> |
| #include <IDocumentUndoRedo.hxx> |
| #include <ndindex.hxx> |
| #include <docary.hxx> |
| #include <fmtcntnt.hxx> |
| #include <fmtanchr.hxx> |
| #include <txtflcnt.hxx> |
| #include <fmtflcnt.hxx> |
| #include <txtfrm.hxx> |
| #include <pagefrm.hxx> |
| #include <rootfrm.hxx> |
| #include <flyfrms.hxx> |
| #include <frmtool.hxx> |
| #include <frmfmt.hxx> |
| #include <ndtxt.hxx> |
| #include <pam.hxx> |
| #include <tblsel.hxx> |
| #include <swundo.hxx> |
| #include <swtable.hxx> |
| #include <crstate.hxx> |
| #include <UndoCore.hxx> |
| #include <UndoAttribute.hxx> |
| #include <fmtcnct.hxx> |
| #include <dflyobj.hxx> |
| #include <undoflystrattr.hxx> |
| #include <switerator.hxx> |
| |
| 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<SwFmtFlyCnt&>(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<SwFlyFrmFmt*>(&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 <aOldV.GetVertOrient() |
| // with <text::VertOrientation::NONE> |
| 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; |
| } |
| |
| sal_Bool SwDoc::SetFlyFrmAttr( SwFrmFmt& rFlyFmt, SfxItemSet& rSet ) |
| { |
| if( !rSet.Count() ) |
| return sal_False; |
| |
| ::std::auto_ptr<SwUndoFmtAttrHelper> 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<SwDrawContact*>(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<SwDrawVirtObj*>(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 <SwPosition> 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, <GetFrm()> 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( !this, "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 <SetAttr(..)>) 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<SwDrawVirtObj*>(pObj)->IsConnected() ) |
| { |
| SwRect aNewObjRect( aObjRect ); |
| static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( 0L )) |
| ->AdjustPositioningAttr( pNewAnchorFrm, |
| &aNewObjRect ); |
| |
| } |
| else |
| { |
| static_cast<SwAnchoredDrawObject*>(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, "<SwDoc::ChgAnchor(..)> - 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<SwFmtFlyCnt&>(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<SwFlyFrm,SwFmt>::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 ); |
| } |
| } |
| |
| |
| |