xref: /trunk/main/sw/source/core/txtnode/atrflyin.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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