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