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 <switerator.hxx> 32 #include <calbck.hxx> 33 #include <node.hxx> 34 #include <ndindex.hxx> 35 #include <swtable.hxx> 36 #include <ftnfrm.hxx> 37 #include <sectfrm.hxx> 38 #include "frmfmt.hxx" 39 #include "cntfrm.hxx" 40 #include "tabfrm.hxx" 41 #include "frmtool.hxx" 42 #include "section.hxx" 43 #include "node2lay.hxx" 44 45 /* -----------------25.02.99 10:31------------------- 46 * Die SwNode2LayImpl-Klasse erledigt die eigentliche Arbeit, 47 * die SwNode2Layout-Klasse ist nur die der Oefffentlichkeit bekannte Schnittstelle 48 * --------------------------------------------------*/ 49 class SwNode2LayImpl 50 { 51 SwIterator<SwFrm,SwModify>* pIter; 52 SwModify* pMod; 53 SvPtrarr *pUpperFrms;// Zum Einsammeln der Upper 54 sal_uLong nIndex; // Der Index des einzufuegenden Nodes 55 sal_Bool bMaster : 1; // sal_True => nur Master , sal_False => nur Frames ohne Follow 56 sal_Bool bInit : 1; // Ist am SwClient bereits ein First()-Aufruf erfolgt? 57 public: 58 SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch ); 59 ~SwNode2LayImpl() { delete pIter; delete pUpperFrms; } 60 SwFrm* NextFrm(); // liefert den naechsten "sinnvollen" Frame 61 SwLayoutFrm* UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ); 62 void SaveUpperFrms(); // Speichert (und lockt ggf.) die pUpper 63 // Fuegt unter jeden pUpper des Arrays einen Frame ein. 64 void RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ); 65 66 SwFrm* GetFrm( const Point* pDocPos = 0, 67 const SwPosition *pPos = 0, 68 const sal_Bool bCalcFrm = sal_True ) const; 69 }; 70 71 /* -----------------25.02.99 10:38------------------- 72 * Hauptaufgabe des Ctor: Das richtige SwModify zu ermitteln, 73 * ueber das iteriert wird. 74 * Uebergibt man bSearch == sal_True, so wird der naechste Cntnt- oder TableNode 75 * gesucht, der Frames besitzt ( zum Einsammeln der pUpper ), ansonsten wird 76 * erwartet, das rNode bereits auf einem solchen Cntnt- oder TableNode sitzt, 77 * vor oder hinter den eingefuegt werden soll. 78 * --------------------------------------------------*/ 79 80 SwNode* GoNextWithFrm(const SwNodes& rNodes, SwNodeIndex *pIdx) 81 { 82 if( pIdx->GetIndex() >= rNodes.Count() - 1 ) 83 return 0; 84 85 SwNodeIndex aTmp(*pIdx, +1); 86 SwNode* pNd = 0; 87 while( aTmp < rNodes.Count()-1 ) 88 { 89 pNd = &aTmp.GetNode(); 90 bool bFound = false; 91 if ( pNd->IsCntntNode() ) 92 bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0); 93 else if ( pNd->IsTableNode() ) 94 bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 ); 95 else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() ) 96 { 97 pNd = 0; 98 break; 99 } 100 if ( bFound ) 101 break; 102 aTmp++; 103 } 104 105 if( aTmp == rNodes.Count()-1 ) 106 pNd = 0; 107 else if( pNd ) 108 (*pIdx) = aTmp; 109 return pNd; 110 } 111 112 SwNode* GoPreviousWithFrm(SwNodeIndex *pIdx) 113 { 114 if( !pIdx->GetIndex() ) 115 return 0; 116 117 SwNodeIndex aTmp( *pIdx, -1 ); 118 SwNode* pNd(0); 119 while( aTmp.GetIndex() ) 120 { 121 pNd = &aTmp.GetNode(); 122 bool bFound = false; 123 if ( pNd->IsCntntNode() ) 124 bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0); 125 else if ( pNd->IsTableNode() ) 126 bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 ); 127 else if( pNd->IsStartNode() && !pNd->IsSectionNode() ) 128 { 129 pNd = 0; 130 break; 131 } 132 if ( bFound ) 133 break; 134 aTmp--; 135 } 136 137 if( !aTmp.GetIndex() ) 138 pNd = 0; 139 else if( pNd ) 140 (*pIdx) = aTmp; 141 return pNd; 142 } 143 144 145 SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch ) 146 : pUpperFrms( NULL ), nIndex( nIdx ), bInit( sal_False ) 147 { 148 const SwNode* pNd; 149 if( bSearch || rNode.IsSectionNode() ) 150 { 151 // Suche den naechsten Cntnt/TblNode, der einen Frame besitzt, 152 // damit wir uns vor/hinter ihn haengen koennen 153 if( !bSearch && rNode.GetIndex() < nIndex ) 154 { 155 SwNodeIndex aTmp( *rNode.EndOfSectionNode(), +1 ); 156 pNd = GoPreviousWithFrm( &aTmp ); 157 if( !bSearch && pNd && rNode.GetIndex() > pNd->GetIndex() ) 158 pNd = NULL; // Nicht ueber den Bereich hinausschiessen 159 bMaster = sal_False; 160 } 161 else 162 { 163 SwNodeIndex aTmp( rNode, -1 ); 164 pNd = GoNextWithFrm( rNode.GetNodes(), &aTmp ); 165 bMaster = sal_True; 166 if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() ) 167 pNd = NULL; // Nicht ueber den Bereich hinausschiessen 168 } 169 } 170 else 171 { 172 pNd = &rNode; 173 bMaster = nIndex < rNode.GetIndex(); 174 } 175 if( pNd ) 176 { 177 if( pNd->IsCntntNode() ) 178 pMod = (SwModify*)pNd->GetCntntNode(); 179 else 180 { 181 ASSERT( pNd->IsTableNode(), "For Tablenodes only" ); 182 pMod = pNd->GetTableNode()->GetTable().GetFrmFmt(); 183 } 184 pIter = new SwIterator<SwFrm,SwModify>( *pMod ); 185 } 186 else 187 { 188 pIter = NULL; 189 pMod = 0; 190 } 191 } 192 193 /* -----------------25.02.99 10:41------------------- 194 * SwNode2LayImpl::NextFrm() liefert den naechsten "sinnvollen" Frame, 195 * beim ersten Aufruf wird am eigentlichen Iterator ein First gerufen, 196 * danach die Next-Methode. Das Ergebnis wird auf Brauchbarkeit untersucht, 197 * so werden keine Follows akzeptiert, ein Master wird beim Einsammeln der 198 * pUpper und beim Einfuegen vor ihm akzeptiert. Beim Einfuegen dahinter 199 * wird vom Master ausgehend der letzte Follow gesucht und zurueckgegeben. 200 * Wenn der Frame innerhalb eines SectionFrms liegt, wird noch festgestellt, 201 * ob statt des Frames der SectionFrm der geeignete Rueckgabewert ist, dies 202 * ist der Fall, wenn der neu einzufuegende Node ausserhalb des Bereichs liegt. 203 * --------------------------------------------------*/ 204 SwFrm* SwNode2LayImpl::NextFrm() 205 { 206 SwFrm* pRet; 207 if( !pIter ) 208 return sal_False; 209 if( !bInit ) 210 { 211 pRet = pIter->First(); 212 bInit = sal_True; 213 } 214 else 215 pRet = pIter->Next(); 216 while( pRet ) 217 { 218 SwFlowFrm* pFlow = SwFlowFrm::CastFlowFrm( pRet ); 219 ASSERT( pFlow, "Cntnt or Table expected?!" ); 220 // Follows sind fluechtige Gestalten, deshalb werden sie ignoriert. 221 // Auch wenn wir hinter dem Frame eingefuegt werden sollen, nehmen wir 222 // zunaechst den Master, hangeln uns dann aber zum letzten Follow durch. 223 if( !pFlow->IsFollow() ) 224 { 225 if( !bMaster ) 226 { 227 while( pFlow->HasFollow() ) 228 pFlow = pFlow->GetFollow(); 229 pRet = pFlow->GetFrm(); 230 } 231 if( pRet->IsInSct() ) 232 { 233 SwSectionFrm* pSct = pRet->FindSctFrm(); 234 // Vorsicht: Wenn wir in einer Fussnote sind, so kann diese 235 // Layoutmaessig in einem spaltigen Bereich liegen, obwohl 236 // sie nodemaessig ausserhalb liegt. Deshalb muss bei Fussnoten 237 // ueberprueft werden, ob auch der SectionFrm in der Fussnote 238 // und nicht ausserhalb liegt. 239 if( !pRet->IsInFtn() || pSct->IsInFtn() ) 240 { 241 ASSERT( pSct && pSct->GetSection(), "Where's my section?" ); 242 SwSectionNode* pNd = pSct->GetSection()->GetFmt()->GetSectionNode(); 243 ASSERT( pNd, "Lost SectionNode" ); 244 // Wenn der erhaltene Frame in einem Bereichsframe steht, 245 // dessen Bereich den Ausgangsnode nicht umfasst, so kehren 246 // wir mit dem SectionFrm zurueck, sonst mit dem Cntnt/TabFrm 247 if( bMaster ) 248 { 249 if( pNd->GetIndex() >= nIndex ) 250 pRet = pSct; 251 } 252 else if( pNd->EndOfSectionIndex() < nIndex ) 253 pRet = pSct; 254 } 255 } 256 return pRet; 257 } 258 pRet = pIter->Next(); 259 } 260 return NULL; 261 } 262 263 void SwNode2LayImpl::SaveUpperFrms() 264 { 265 pUpperFrms = new SvPtrarr( 0, 20 ); 266 SwFrm* pFrm; 267 while( 0 != (pFrm = NextFrm()) ) 268 { 269 SwFrm* pPrv = pFrm->GetPrev(); 270 pFrm = pFrm->GetUpper(); 271 if( pFrm ) 272 { 273 if( pFrm->IsFtnFrm() ) 274 ((SwFtnFrm*)pFrm)->ColLock(); 275 else if( pFrm->IsInSct() ) 276 pFrm->FindSctFrm()->ColLock(); 277 if( pPrv && pPrv->IsSctFrm() ) 278 ((SwSectionFrm*)pPrv)->LockJoin(); 279 pUpperFrms->Insert( (void*)pPrv, pUpperFrms->Count() ); 280 pUpperFrms->Insert( (void*)pFrm, pUpperFrms->Count() ); 281 } 282 } 283 delete pIter; 284 pIter = NULL; 285 pMod = 0; 286 } 287 288 SwLayoutFrm* SwNode2LayImpl::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ) 289 { 290 rpFrm = NextFrm(); 291 if( !rpFrm ) 292 return NULL; 293 SwLayoutFrm* pUpper = rpFrm->GetUpper(); 294 if( rpFrm->IsSctFrm() ) 295 { 296 const SwNode* pNode = rNode.StartOfSectionNode(); 297 if( pNode->IsSectionNode() ) 298 { 299 SwFrm* pFrm = bMaster ? rpFrm->FindPrev() : rpFrm->FindNext(); 300 if( pFrm && pFrm->IsSctFrm() ) 301 { 302 // #137684#: pFrm could be a "dummy"-section 303 if( ((SwSectionFrm*)pFrm)->GetSection() && 304 (&((SwSectionNode*)pNode)->GetSection() == 305 ((SwSectionFrm*)pFrm)->GetSection()) ) 306 { 307 // OD 2004-06-02 #i22922# - consider columned sections 308 // 'Go down' the section frame as long as the layout frame 309 // is found, which would contain content. 310 while ( pFrm->IsLayoutFrm() && 311 static_cast<SwLayoutFrm*>(pFrm)->Lower() && 312 !static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsFlowFrm() && 313 static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsLayoutFrm() ) 314 { 315 pFrm = static_cast<SwLayoutFrm*>(pFrm)->Lower(); 316 } 317 ASSERT( pFrm->IsLayoutFrm(), 318 "<SwNode2LayImpl::UpperFrm(..)> - expected upper frame isn't a layout frame." ); 319 rpFrm = bMaster ? NULL 320 : static_cast<SwLayoutFrm*>(pFrm)->Lower(); 321 ASSERT( !rpFrm || rpFrm->IsFlowFrm(), 322 "<SwNode2LayImpl::UpperFrm(..)> - expected sibling isn't a flow frame." ); 323 return static_cast<SwLayoutFrm*>(pFrm); 324 } 325 326 pUpper = new SwSectionFrm(((SwSectionNode*)pNode)->GetSection(), rpFrm); 327 pUpper->Paste( rpFrm->GetUpper(), 328 bMaster ? rpFrm : rpFrm->GetNext() ); 329 static_cast<SwSectionFrm*>(pUpper)->Init(); 330 rpFrm = NULL; 331 // 'Go down' the section frame as long as the layout frame 332 // is found, which would contain content. 333 while ( pUpper->Lower() && 334 !pUpper->Lower()->IsFlowFrm() && 335 pUpper->Lower()->IsLayoutFrm() ) 336 { 337 pUpper = static_cast<SwLayoutFrm*>(pUpper->Lower()); 338 } 339 return pUpper; 340 } 341 } 342 }; 343 if( !bMaster ) 344 rpFrm = rpFrm->GetNext(); 345 return pUpper; 346 } 347 348 void SwNode2LayImpl::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ) 349 { 350 ASSERT( pUpperFrms, "RestoreUpper without SaveUpper?" ) 351 SwNode* pNd; 352 SwDoc *pDoc = rNds.GetDoc(); 353 sal_Bool bFirst = sal_True; 354 for( ; nStt < nEnd; ++nStt ) 355 { 356 SwFrm* pNew = 0; 357 SwFrm* pNxt; 358 SwLayoutFrm* pUp; 359 if( (pNd = rNds[nStt])->IsCntntNode() ) 360 for( sal_uInt16 n = 0; n < pUpperFrms->Count(); ) 361 { 362 pNxt = (SwFrm*)(*pUpperFrms)[n++]; 363 if( bFirst && pNxt && pNxt->IsSctFrm() ) 364 ((SwSectionFrm*)pNxt)->UnlockJoin(); 365 pUp = (SwLayoutFrm*)(*pUpperFrms)[n++]; 366 if( pNxt ) 367 pNxt = pNxt->GetNext(); 368 else 369 pNxt = pUp->Lower(); 370 pNew = ((SwCntntNode*)pNd)->MakeFrm( pUp ); 371 pNew->Paste( pUp, pNxt ); 372 (*pUpperFrms)[n-2] = pNew; 373 } 374 else if( pNd->IsTableNode() ) 375 for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ) 376 { 377 pNxt = (SwFrm*)(*pUpperFrms)[x++]; 378 if( bFirst && pNxt && pNxt->IsSctFrm() ) 379 ((SwSectionFrm*)pNxt)->UnlockJoin(); 380 pUp = (SwLayoutFrm*)(*pUpperFrms)[x++]; 381 if( pNxt ) 382 pNxt = pNxt->GetNext(); 383 else 384 pNxt = pUp->Lower(); 385 pNew = ((SwTableNode*)pNd)->MakeFrm( pUp ); 386 ASSERT( pNew->IsTabFrm(), "Table exspected" ); 387 pNew->Paste( pUp, pNxt ); 388 ((SwTabFrm*)pNew)->RegistFlys(); 389 (*pUpperFrms)[x-2] = pNew; 390 } 391 else if( pNd->IsSectionNode() ) 392 { 393 nStt = pNd->EndOfSectionIndex(); 394 for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ) 395 { 396 pNxt = (SwFrm*)(*pUpperFrms)[x++]; 397 if( bFirst && pNxt && pNxt->IsSctFrm() ) 398 ((SwSectionFrm*)pNxt)->UnlockJoin(); 399 pUp = (SwLayoutFrm*)(*pUpperFrms)[x++]; 400 ASSERT( pUp->GetUpper() || pUp->IsFlyFrm(), "Lost Upper" ); 401 ::_InsertCnt( pUp, pDoc, pNd->GetIndex(), sal_False, nStt+1, pNxt ); 402 pNxt = pUp->GetLastLower(); 403 (*pUpperFrms)[x-2] = pNxt; 404 } 405 } 406 bFirst = sal_False; 407 } 408 for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ++x ) 409 { 410 SwFrm* pTmp = (SwFrm*)(*pUpperFrms)[++x]; 411 if( pTmp->IsFtnFrm() ) 412 ((SwFtnFrm*)pTmp)->ColUnlock(); 413 else if ( pTmp->IsInSct() ) 414 { 415 SwSectionFrm* pSctFrm = pTmp->FindSctFrm(); 416 pSctFrm->ColUnlock(); 417 // OD 26.08.2003 #i18103# - invalidate size of section in order to 418 // assure, that the section is formatted, unless it was 'Collocked' 419 // from its 'collection' until its 'restoration'. 420 pSctFrm->_InvalidateSize(); 421 } 422 } 423 } 424 425 SwFrm* SwNode2LayImpl::GetFrm( const Point* pDocPos, 426 const SwPosition *pPos, 427 const sal_Bool bCalcFrm ) const 428 { 429 // mba: test if change of member pIter -> pMod broke anything 430 return pMod ? ::GetFrmOfModify( 0, *pMod, USHRT_MAX, pDocPos, pPos, bCalcFrm ) : 0; 431 } 432 433 SwNode2Layout::SwNode2Layout( const SwNode& rNd, sal_uLong nIdx ) 434 { 435 pImpl = new SwNode2LayImpl( rNd, nIdx, sal_False ); 436 } 437 438 SwNode2Layout::SwNode2Layout( const SwNode& rNd ) 439 { 440 pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), sal_True ); 441 pImpl->SaveUpperFrms(); 442 } 443 444 void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ) 445 { 446 ASSERT( pImpl, "RestoreUpperFrms without SaveUpperFrms" ); 447 pImpl->RestoreUpperFrms( rNds, nStt, nEnd ); 448 } 449 450 SwFrm* SwNode2Layout::NextFrm() 451 { 452 return pImpl->NextFrm(); 453 } 454 455 SwLayoutFrm* SwNode2Layout::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ) 456 { 457 return pImpl->UpperFrm( rpFrm, rNode ); 458 } 459 460 SwNode2Layout::~SwNode2Layout() 461 { 462 delete pImpl; 463 } 464 465 SwFrm* SwNode2Layout::GetFrm( const Point* pDocPos, 466 const SwPosition *pPos, 467 const sal_Bool bCalcFrm ) const 468 { 469 return pImpl->GetFrm( pDocPos, pPos, bCalcFrm ); 470 } 471 472 473