xref: /aoo42x/main/sw/source/core/txtnode/atrflyin.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include "hintids.hxx"
32 #include "cntfrm.hxx"       // _GetFly
33 #include "doc.hxx"
34 #include <IDocumentUndoRedo.hxx>
35 #include "pam.hxx"          // fuer SwTxtFlyCnt
36 #include "flyfrm.hxx"       // fuer SwTxtFlyCnt
37 #include "ndtxt.hxx"        // SwFlyFrmFmt
38 #include "frmfmt.hxx"       // SwFlyFrmFmt
39 #include <fmtflcnt.hxx>
40 #include <txtflcnt.hxx>
41 #include <fmtanchr.hxx>
42 #include "swfont.hxx"
43 #include "txtfrm.hxx"
44 #include "flyfrms.hxx"
45 #include <objectformatter.hxx>
46 #include <switerator.hxx>
47 
48 SwFmtFlyCnt::SwFmtFlyCnt( SwFrmFmt *pFrmFmt )
49 	: SfxPoolItem( RES_TXTATR_FLYCNT ),
50     pTxtAttr( 0 ),
51     pFmt( pFrmFmt )
52 {
53 }
54 
55 int __EXPORT SwFmtFlyCnt::operator==( const SfxPoolItem& rAttr ) const
56 {
57 	ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
58 	return( pTxtAttr && ((SwFmtFlyCnt&)rAttr).pTxtAttr &&
59 			*pTxtAttr->GetStart() == *((SwFmtFlyCnt&)rAttr).pTxtAttr->GetStart() &&
60 			pFmt == ((SwFmtFlyCnt&)rAttr).GetFrmFmt() );
61 }
62 
63 SfxPoolItem* __EXPORT SwFmtFlyCnt::Clone( SfxItemPool* ) const
64 {
65 	return new SwFmtFlyCnt( pFmt );
66 }
67 
68 SwTxtFlyCnt::SwTxtFlyCnt( SwFmtFlyCnt& rAttr, xub_StrLen nStartPos )
69     : SwTxtAttr( rAttr, nStartPos )
70 {
71     rAttr.pTxtAttr = this;
72     SetHasDummyChar(true);
73 }
74 
75 
76 
77 /*************************************************************************
78  *                  SwTxtFlyCnt::MakeTxtHint()
79  *
80  * An dieser Stelle soll einmal der Gesamtzusammenhang bei der Erzeugung
81  * eines neuen SwTxtFlyCnt erlaeutert werden.
82  * Das MakeTxtHint() wird z.B. im SwTxtNode::Copy() gerufen.
83  * Fuer die komplette Verdopplung sind folgende Schritte notwendig:
84  * 1) Duplizieren des pFmt incl. Inhalt, Attributen etc.
85  * 2) Setzen des Ankers
86  * 3) Benachrichtigung
87  * Da fuer die Bewaeltigung der Aufgaben nicht immer alle Informationen
88  * bereitstehen und darueber hinaus bestimmte Methoden erst zu einem
89  * spaeteren Zeitpunkt gerufen werden duerfen (weil nocht nicht alle
90  * Nodeinformationen vorliegen), verteilt sich der Ablauf.
91  * ad 1) MakeTxtHint() wird durch den Aufruf von SwDoc::CopyLayout()
92  * der das neue FlyFrmFmt erzeugt und mit dem duplizierten Inhalt des
93  * FlyFrm verbunden.
94  * ad 2) SetAnchor() wird von SwTxtNode::Insert() gerufen und sorgt fuer das
95  * setzen des Ankers (die SwPosition des Dummy-Zeichens wird dem FlyFrmFmt
96  * per SetAttr bekannt gegeben). Dies kann nicht im MakeTxtHint erledigt
97  * werden, da der Zielnode unbestimmt ist.
98  * ad 3) _GetFlyFrm() wird im Formatierungsprozess vom LineIter gerufen
99  * und sucht den FlyFrm zum Dummyzeichen des aktuellen CntntFrm. Wird keiner
100  * gefunden, so wird ein neuer FlyFrm angelegt.
101  * Kritisch an diesem Vorgehen ist, dass das pCntnt->AppendFly() eine
102  * sofortige Neuformatierung von pCntnt anstoesst. Die Rekursion kommt
103  * allerdings durch den Lockmechanismus in SwTxtFrm::Format() nicht
104  * zu stande.
105  * Attraktiv ist der Umstand, dass niemand ueber die vom Node abhaengigen
106  * CntntFrms iterieren braucht, um die FlyInCntFrm anzulegen. Dies geschieht
107  * bei der Arbeit.
108  *************************************************************************/
109 
110 void SwTxtFlyCnt::CopyFlyFmt( SwDoc* pDoc )
111 {
112 	SwFrmFmt* pFmt = GetFlyCnt().GetFrmFmt();
113 	ASSERT( pFmt, "von welchem Format soll ich eine Kopie erzeugen?" )
114 	// Das FlyFrmFmt muss dupliziert werden.
115 	// In CopyLayoutFmt (siehe doclay.cxx) wird das FlyFrmFmt erzeugt
116 	// und der Inhalt dupliziert.
117 
118     // disable undo while copying attribute
119     ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
120 	SwFmtAnchor aAnchor( pFmt->GetAnchor() );
121     if ((FLY_AT_PAGE != aAnchor.GetAnchorId()) &&
122         (pDoc != pFmt->GetDoc()))   // different documents?
123     {
124 		// JP 03.06.96: dann sorge dafuer, das der koperierte Anker auf
125 		//				gueltigen Content zeigt! Die Umsetzung auf die
126 		//				richtige Position erfolgt spaeter.
127 		SwNodeIndex aIdx( pDoc->GetNodes().GetEndOfExtras(), +2 );
128 		SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
129 		if( !pCNd )
130 			pCNd = pDoc->GetNodes().GoNext( &aIdx );
131 
132 		SwPosition* pPos = (SwPosition*)aAnchor.GetCntntAnchor();
133 		pPos->nNode = aIdx;
134         if (FLY_AS_CHAR == aAnchor.GetAnchorId())
135         {
136 			pPos->nContent.Assign( pCNd, 0 );
137         }
138 		else
139 		{
140 			pPos->nContent.Assign( 0, 0 );
141 			ASSERT( !this, "CopyFlyFmt: Was fuer ein Anker?" );
142 		}
143 	}
144 
145     SwFrmFmt* pNew = pDoc->CopyLayoutFmt( *pFmt, aAnchor, false, false );
146 	((SwFmtFlyCnt&)GetFlyCnt()).SetFlyFmt( pNew );
147 }
148 
149 /*************************************************************************
150  *                  SwTxtFlyCnt::SetAnchor()
151  *
152  * SetAnchor() wird von SwTxtNode::Insert() gerufen und sorgt fuer das
153  * setzen des Ankers (die SwPosition des Dummy-Zeichens wird dem FlyFrmFmt
154  * per SetAttr bekannt gegeben). Dies kann nicht im MakeTxtHint erledigt
155  * werden, da der Zielnode unbestimmt ist.
156  * (siehe Kommentar in SwTxtFlyCnt::MakeTxtHint)
157  *************************************************************************/
158 
159 void SwTxtFlyCnt::SetAnchor( const SwTxtNode *pNode )
160 {
161 	// fuers Undo muss der neue Anker schon bekannt sein !
162 
163 	// Wir ermitteln den Index im Nodesarray zum Node
164 
165 	SwDoc* pDoc = (SwDoc*)pNode->GetDoc();
166 
167 	SwIndex aIdx( (SwTxtNode*)pNode, *GetStart() );
168 	SwPosition aPos( *pNode->StartOfSectionNode(), aIdx );
169 	SwFrmFmt* pFmt = GetFlyCnt().GetFrmFmt();
170 	SwFmtAnchor aAnchor( pFmt->GetAnchor() );
171 
172 	if( !aAnchor.GetCntntAnchor() ||
173 		!aAnchor.GetCntntAnchor()->nNode.GetNode().GetNodes().IsDocNodes() ||
174 		&aAnchor.GetCntntAnchor()->nNode.GetNode() != (SwNode*)pNode )
175 		aPos.nNode = *pNode;
176 	else
177 		aPos.nNode = aAnchor.GetCntntAnchor()->nNode;
178 
179     aAnchor.SetType( FLY_AS_CHAR );        // default!
180 	aAnchor.SetAnchor( &aPos );
181 
182 	// beim Ankerwechsel werden immer alle FlyFrms vom Attribut geloescht
183 	// JP 25.04.95: wird innerhalb des SplitNodes die Frames verschoben
184 	//				koennen die Frames erhalten bleiben.
185 	if( ( !pNode->GetpSwpHints() || !pNode->GetpSwpHints()->IsInSplitNode() )
186 		&& RES_DRAWFRMFMT != pFmt->Which() )
187 		pFmt->DelFrms();
188 
189 	// stehen wir noch im falschen Dokument ?
190 	if( pDoc != pFmt->GetDoc() )
191     {
192         // disable undo while copying attribute
193         ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
194         SwFrmFmt* pNew = pDoc->CopyLayoutFmt( *pFmt, aAnchor, false, false );
195 
196         ::sw::UndoGuard const undoGuardFmt(
197             pFmt->GetDoc()->GetIDocumentUndoRedo());
198 		pFmt->GetDoc()->DelLayoutFmt( pFmt );
199 		((SwFmtFlyCnt&)GetFlyCnt()).SetFlyFmt( pNew );
200 	}
201 	else if( pNode->GetpSwpHints() &&
202 			pNode->GetpSwpHints()->IsInSplitNode() &&
203 			RES_DRAWFRMFMT != pFmt->Which() )
204 	{
205 		pFmt->LockModify();
206         pFmt->SetFmtAttr( aAnchor );        // nur den Anker neu setzen
207 		pFmt->UnlockModify();
208 	}
209 	else
210         pFmt->SetFmtAttr( aAnchor );        // nur den Anker neu setzen
211 
212 	// Am Node haengen u.a. abhaengige CntFrms.
213 	// Fuer jeden CntFrm wird ein SwFlyInCntFrm angelegt.
214 }
215 
216 /*************************************************************************
217  *                      SwTxtFlyCnt::_GetFlyFrm()
218  *
219  * _GetFlyFrm() wird im Formatierungsprozess vom LineIter gerufen
220  * und sucht den FlyFrm zum Dummyzeichen des aktuellen CntntFrm. Wird keiner
221  * gefunden, so wird ein neuer FlyFrm angelegt.
222  * (siehe Kommentar ind SwTxtFlyCnt::MakeTxtHint)
223  *************************************************************************/
224 
225 SwFlyInCntFrm *SwTxtFlyCnt::_GetFlyFrm( const SwFrm *pCurrFrm )
226 {
227 	SwFrmFmt* pFrmFmt = GetFlyCnt().GetFrmFmt();
228 	if( RES_DRAWFRMFMT == pFrmFmt->Which() )
229 	{
230 		ASSERT(  !this, "SwTxtFlyCnt::_GetFlyFrm: DrawInCnt-Baustelle!" );
231 		return NULL;
232 	}
233 
234 	SwIterator<SwFlyFrm,SwFmt> aIter( *GetFlyCnt().pFmt );
235 	ASSERT( pCurrFrm->IsTxtFrm(), "SwTxtFlyCnt::_GetFlyFrm for TxtFrms only." );
236     SwFrm* pFrm = aIter.First();
237     if ( pFrm )
238 	{
239 		SwTxtFrm *pFirst = (SwTxtFrm*)pCurrFrm;
240 		while ( pFirst->IsFollow() )
241 			pFirst = pFirst->FindMaster();
242 		do
243 			{
244 				SwTxtFrm *pTmp = pFirst;
245 				do
246                 {   if( ( (SwFlyFrm*)pFrm )->GetAnchorFrm() == (SwFrm*) pTmp )
247 					{
248 						if ( pTmp != pCurrFrm )
249 						{
250 							pTmp->RemoveFly( (SwFlyFrm*)pFrm );
251 							((SwTxtFrm*)pCurrFrm)->AppendFly( (SwFlyFrm*)pFrm );
252 						}
253 						return (SwFlyInCntFrm*)pFrm;
254 					}
255 					pTmp = pTmp->GetFollow();
256 				} while ( pTmp );
257 
258                 pFrm = aIter.Next();
259 
260 		} while( pFrm );
261 	}
262 
263 	// Wir haben keinen passenden FlyFrm gefunden, deswegen wird ein
264 	// neuer angelegt.
265 	// Dabei wird eine sofortige Neuformatierung von pCurrFrm angestossen.
266 	// Die Rekursion wird durch den Lockmechanismus in SwTxtFrm::Format()
267 	// abgewuergt.
268     SwFrm* pCurrFrame = const_cast< SwFrm* >(pCurrFrm);
269 	SwFlyInCntFrm *pFly = new SwFlyInCntFrm( (SwFlyFrmFmt*)pFrmFmt, pCurrFrame, pCurrFrame );
270 	pCurrFrame->AppendFly( pFly );
271 	pFly->RegistFlys();
272 
273     // 7922: Wir muessen dafuer sorgen, dass der Inhalt des FlyInCnt
274     // nach seiner Konstruktion stramm durchformatiert wird.
275     // --> OD 2004-11-09 #i26945# - Use new object formatter to format Writer
276     // fly frame and its content.
277     SwObjectFormatter::FormatObj( *pFly, const_cast<SwFrm*>(pCurrFrm),
278                                   pCurrFrm->FindPageFrm() );
279     // <--
280 
281 	return pFly;
282 }
283 
284 
285