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 32 #include <hintids.hxx> 33 #include <editeng/boxitem.hxx> 34 #include <tblrwcl.hxx> 35 #include <swtblfmt.hxx> 36 37 38 inline const SvxBorderLine* GetLineTB( const SvxBoxItem* pBox, sal_Bool bTop ) 39 { 40 return bTop ? pBox->GetTop() : pBox->GetBottom(); 41 } 42 43 44 sal_Bool _SwGCBorder_BoxBrd::CheckLeftBorderOfFormat( const SwFrmFmt& rFmt ) 45 { 46 const SvxBorderLine* pBrd; 47 const SfxPoolItem* pItem; 48 if( SFX_ITEM_SET == rFmt.GetItemState( RES_BOX, sal_True, &pItem ) && 49 0 != ( pBrd = ((SvxBoxItem*)pItem)->GetLeft() ) ) 50 { 51 if( *pBrdLn == *pBrd ) 52 bAnyBorderFnd = sal_True; 53 return sal_True; 54 } 55 return sal_False; 56 } 57 58 59 60 sal_Bool lcl_GCBorder_ChkBoxBrd_L( const SwTableLine*& rpLine, void* pPara ) 61 { 62 const SwTableBox* pBox = rpLine->GetTabBoxes()[ 0 ]; 63 return lcl_GCBorder_ChkBoxBrd_B( pBox, pPara ); 64 } 65 66 sal_Bool lcl_GCBorder_ChkBoxBrd_B( const SwTableBox*& rpBox, void* pPara ) 67 { 68 sal_Bool bRet = sal_True; 69 if( rpBox->GetTabLines().Count() ) 70 { 71 for( sal_uInt16 n = 0, nLines = rpBox->GetTabLines().Count(); 72 n < nLines && bRet; ++n ) 73 { 74 const SwTableLine* pLine = rpBox->GetTabLines()[ n ]; 75 bRet = lcl_GCBorder_ChkBoxBrd_L( pLine, pPara ); 76 } 77 } 78 else 79 { 80 _SwGCBorder_BoxBrd* pBPara = (_SwGCBorder_BoxBrd*)pPara; 81 bRet = pBPara->CheckLeftBorderOfFormat( *rpBox->GetFrmFmt() ); 82 } 83 return bRet; 84 } 85 86 sal_Bool lcl_GCBorder_GetLastBox_L( const SwTableLine*& rpLine, void* pPara ) 87 { 88 const SwTableBoxes& rBoxes = rpLine->GetTabBoxes(); 89 const SwTableBox* pBox = rBoxes[ rBoxes.Count()-1 ]; 90 ::lcl_GCBorder_GetLastBox_B( pBox, pPara ); 91 return sal_True; 92 } 93 94 sal_Bool lcl_GCBorder_GetLastBox_B( const SwTableBox*& rpBox, void* pPara ) 95 { 96 SwTableLines& rLines = (SwTableLines&)rpBox->GetTabLines(); 97 if( rLines.Count() ) 98 rLines.ForEach( &lcl_GCBorder_GetLastBox_L, pPara ); 99 else 100 ((SwTableBoxes*)pPara)->Insert( rpBox, ((SwTableBoxes*)pPara)->Count() ); 101 return sal_True; 102 } 103 104 // suche das "Ende" der vorgegebene BorderLine. Returnt wird die "Layout"Pos! 105 sal_uInt16 lcl_FindEndPosOfBorder( const SwCollectTblLineBoxes& rCollTLB, 106 const SvxBorderLine& rBrdLn, sal_uInt16& rStt, sal_Bool bTop ) 107 { 108 sal_uInt16 nPos, nLastPos = 0; 109 for( sal_uInt16 nEnd = rCollTLB.Count(); rStt < nEnd; ++rStt ) 110 { 111 const SfxPoolItem* pItem; 112 const SvxBorderLine* pBrd; 113 const SwTableBox& rBox = rCollTLB.GetBox( rStt, &nPos ); 114 115 if( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState(RES_BOX,sal_True, &pItem ) 116 || 0 == ( pBrd = GetLineTB( (SvxBoxItem*)pItem, bTop )) 117 || !( *pBrd == rBrdLn )) 118 break; 119 nLastPos = nPos; 120 } 121 return nLastPos; 122 } 123 124 inline const SvxBorderLine* lcl_GCBorder_GetBorder( const SwTableBox& rBox, 125 sal_Bool bTop, 126 const SfxPoolItem** ppItem ) 127 { 128 return SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOX, sal_True, ppItem ) 129 ? GetLineTB( (SvxBoxItem*)*ppItem, bTop ) 130 : 0; 131 } 132 133 void lcl_GCBorder_DelBorder( const SwCollectTblLineBoxes& rCollTLB, 134 sal_uInt16& rStt, sal_Bool bTop, 135 const SvxBorderLine& rLine, 136 const SfxPoolItem* pItem, 137 sal_uInt16 nEndPos, 138 SwShareBoxFmts* pShareFmts ) 139 { 140 SwTableBox* pBox = (SwTableBox*)&rCollTLB.GetBox( rStt ); 141 sal_uInt16 nNextPos; 142 const SvxBorderLine* pLn = &rLine; 143 144 do { 145 if( pLn && *pLn == rLine ) 146 { 147 SvxBoxItem aBox( *(SvxBoxItem*)pItem ); 148 if( bTop ) 149 aBox.SetLine( 0, BOX_LINE_TOP ); 150 else 151 aBox.SetLine( 0, BOX_LINE_BOTTOM ); 152 153 if( pShareFmts ) 154 pShareFmts->SetAttr( *pBox, aBox ); 155 else 156 pBox->ClaimFrmFmt()->SetFmtAttr( aBox ); 157 } 158 159 if( ++rStt >= rCollTLB.Count() ) 160 break; 161 162 pBox = (SwTableBox*)&rCollTLB.GetBox( rStt, &nNextPos ); 163 if( nNextPos > nEndPos ) 164 break; 165 166 pLn = lcl_GCBorder_GetBorder( *pBox, bTop, &pItem ); 167 168 } while( sal_True ); 169 } 170 171 172 sal_Bool lcl_GC_Line_Border( const SwTableLine*& rpLine, void* pPara ) 173 { 174 _SwGCLineBorder* pGCPara = (_SwGCLineBorder*)pPara; 175 176 // zuerst die rechte Kante mit der linken Kante der naechsten Box 177 // innerhalb dieser Line 178 { 179 _SwGCBorder_BoxBrd aBPara; 180 const SvxBorderLine* pBrd; 181 const SfxPoolItem* pItem; 182 const SwTableBoxes& rBoxes = rpLine->GetTabBoxes(); 183 for( sal_uInt16 n = 0, nBoxes = rBoxes.Count() - 1; n < nBoxes; ++n ) 184 { 185 SwTableBoxes aBoxes; 186 { 187 const SwTableBox* pBox = rBoxes[ n ]; 188 if( pBox->GetSttNd() ) 189 aBoxes.Insert( pBox, 0 ); 190 else 191 lcl_GCBorder_GetLastBox_B( pBox, &aBoxes ); 192 } 193 194 SwTableBox* pBox; 195 for( sal_uInt16 i = aBoxes.Count(); i; ) 196 if( SFX_ITEM_SET == (pBox = aBoxes[ --i ])->GetFrmFmt()-> 197 GetItemState( RES_BOX, sal_True, &pItem ) && 198 0 != ( pBrd = ((SvxBoxItem*)pItem)->GetRight() ) ) 199 { 200 aBPara.SetBorder( *pBrd ); 201 const SwTableBox* pNextBox = rBoxes[n+1]; 202 if( lcl_GCBorder_ChkBoxBrd_B( pNextBox, &aBPara ) && 203 aBPara.IsAnyBorderFound() ) 204 { 205 SvxBoxItem aBox( *(SvxBoxItem*)pItem ); 206 aBox.SetLine( 0, BOX_LINE_RIGHT ); 207 if( pGCPara->pShareFmts ) 208 pGCPara->pShareFmts->SetAttr( *pBox, aBox ); 209 else 210 pBox->ClaimFrmFmt()->SetFmtAttr( aBox ); 211 } 212 } 213 214 aBoxes.Remove( 0, aBoxes.Count() ); 215 } 216 } 217 218 // und jetzt die eigene untere Kante mit der nachfolgenden oberen Kante 219 if( !pGCPara->IsLastLine() ) 220 { 221 SwCollectTblLineBoxes aBottom( sal_False ); 222 SwCollectTblLineBoxes aTop( sal_True ); 223 224 ::lcl_Line_CollectBox( rpLine, &aBottom ); 225 226 const SwTableLine* pNextLine = (*pGCPara->pLines)[ pGCPara->nLinePos+1 ]; 227 ::lcl_Line_CollectBox( pNextLine, &aTop ); 228 229 // dann entferne mal alle "doppelten" gleichen Lines 230 sal_uInt16 nBtmPos, nTopPos, 231 nSttBtm = 0, nSttTop = 0, 232 nEndBtm = aBottom.Count(), nEndTop = aTop.Count(); 233 234 const SwTableBox *pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ), 235 *pTopBox = &aTop.GetBox( nSttTop++, &nTopPos ); 236 const SfxPoolItem *pBtmItem = 0, *pTopItem = 0; 237 const SvxBorderLine *pBtmLine(0), *pTopLine(0); 238 sal_Bool bGetTopItem = sal_True, bGetBtmItem = sal_True; 239 240 do { 241 if( bGetBtmItem ) 242 pBtmLine = lcl_GCBorder_GetBorder( *pBtmBox, sal_False, &pBtmItem ); 243 if( bGetTopItem ) 244 pTopLine = lcl_GCBorder_GetBorder( *pTopBox, sal_True, &pTopItem ); 245 246 if( pTopLine && pBtmLine && *pTopLine == *pBtmLine ) 247 { 248 // dann kann einer entfernt werden, aber welche? 249 sal_uInt16 nSavSttBtm = nSttBtm, nSavSttTop = nSttTop; 250 sal_uInt16 nBtmEndPos = ::lcl_FindEndPosOfBorder( aBottom, 251 *pTopLine, nSttBtm, sal_False ); 252 if( !nBtmEndPos ) nBtmEndPos = nBtmPos; 253 sal_uInt16 nTopEndPos = ::lcl_FindEndPosOfBorder( aTop, 254 *pTopLine, nSttTop, sal_True ); 255 if( !nTopEndPos ) nTopEndPos = nTopPos; 256 257 258 if( nTopEndPos <= nBtmEndPos ) 259 { 260 // dann die TopBorder bis zur BottomEndPos loeschen 261 nSttTop = nSavSttTop; 262 if( nTopPos <= nBtmEndPos ) 263 lcl_GCBorder_DelBorder( aTop, --nSttTop, sal_True, 264 *pBtmLine, pTopItem, nBtmEndPos, 265 pGCPara->pShareFmts ); 266 else 267 nSttBtm = nSavSttBtm; 268 } 269 else 270 { 271 // sonst die BottomBorder bis zur TopEndPos loeschen 272 nSttBtm = nSavSttBtm; 273 if( nBtmPos <= nTopEndPos ) 274 lcl_GCBorder_DelBorder( aBottom, --nSttBtm, sal_False, 275 *pTopLine, pBtmItem, nTopEndPos, 276 pGCPara->pShareFmts ); 277 else 278 nSttTop = nSavSttTop; 279 } 280 nTopPos = nBtmPos; 281 } 282 283 if( nTopPos == nBtmPos ) 284 { 285 if( nSttBtm >= nEndBtm || nSttTop >= nEndTop ) 286 break; 287 288 pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ); 289 pTopBox = &aTop.GetBox( nSttTop++, &nTopPos ); 290 bGetTopItem = bGetBtmItem = sal_True; 291 } 292 else if( nTopPos < nBtmPos ) 293 { 294 if( nSttTop >= nEndTop ) 295 break; 296 pTopBox = &aTop.GetBox( nSttTop++, &nTopPos ); 297 bGetTopItem = sal_True; 298 bGetBtmItem = sal_False; 299 } 300 else 301 { 302 if( nSttBtm >= nEndBtm ) 303 break; 304 pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ); 305 bGetTopItem = sal_False; 306 bGetBtmItem = sal_True; 307 } 308 309 } while( sal_True ); 310 } 311 312 ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_GC_Box_Border, pPara ); 313 314 ++pGCPara->nLinePos; 315 316 return sal_True; 317 } 318 319 sal_Bool lcl_GC_Box_Border( const SwTableBox*& rpBox, void* pPara ) 320 { 321 if( rpBox->GetTabLines().Count() ) 322 { 323 _SwGCLineBorder aPara( *rpBox ); 324 aPara.pShareFmts = ((_SwGCLineBorder*)pPara)->pShareFmts; 325 ((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_GC_Line_Border, &aPara ); 326 } 327 return sal_True; 328 } 329 330 struct _GCLinePara 331 { 332 SwTableLines* pLns; 333 SwShareBoxFmts* pShareFmts; 334 335 _GCLinePara( SwTableLines& rLns, _GCLinePara* pPara = 0 ) 336 : pLns( &rLns ), pShareFmts( pPara ? pPara->pShareFmts : 0 ) 337 {} 338 }; 339 340 sal_Bool lcl_MergeGCBox( const SwTableBox*& rpTblBox, void* pPara ) 341 { 342 SwTableBox*& rpBox = (SwTableBox*&)rpTblBox; 343 sal_uInt16 n, nLen = rpBox->GetTabLines().Count(); 344 if( nLen ) 345 { 346 // ACHTUNG: die Anzahl der Lines kann sich aendern! 347 _GCLinePara aPara( rpBox->GetTabLines(), (_GCLinePara*)pPara ); 348 for( n = 0; n < rpBox->GetTabLines().Count() && 349 lcl_MergeGCLine( *(rpBox->GetTabLines().GetData() + n), &aPara ); 350 ++n ) 351 ; 352 353 if( 1 == rpBox->GetTabLines().Count() ) 354 { 355 // Box mit einer Line, dann verschiebe alle Boxen der Line 356 // hinter diese Box in der Parent-Line und loesche diese Box 357 SwTableLine* pInsLine = rpBox->GetUpper(); 358 SwTableLine* pCpyLine = rpBox->GetTabLines()[0]; 359 sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, rpBox ); 360 for( n = 0; n < pCpyLine->GetTabBoxes().Count(); ++n ) 361 pCpyLine->GetTabBoxes()[n]->SetUpper( pInsLine ); 362 363 pInsLine->GetTabBoxes().Insert( &pCpyLine->GetTabBoxes(), nInsPos+1 ); 364 pCpyLine->GetTabBoxes().Remove( 0, n ); 365 // loesche alte die Box mit der Line 366 pInsLine->GetTabBoxes().DeleteAndDestroy( nInsPos ); 367 368 return sal_False; // neu aufsetzen 369 } 370 } 371 return sal_True; 372 } 373 374 sal_Bool lcl_MergeGCLine( const SwTableLine*& rpLine, void* pPara ) 375 { 376 SwTableLine* pLn = (SwTableLine*)rpLine; 377 sal_uInt16 nLen = pLn->GetTabBoxes().Count(); 378 if( nLen ) 379 { 380 _GCLinePara* pGCPara = (_GCLinePara*)pPara; 381 while( 1 == nLen ) 382 { 383 // es gibt eine Box mit Lines 384 SwTableBox* pBox = pLn->GetTabBoxes()[0]; 385 if( !pBox->GetTabLines().Count() ) 386 break; 387 388 SwTableLine* pLine = pBox->GetTabLines()[0]; 389 390 // pLine wird zu der aktuellen, also der rpLine, 391 // die restlichen werden ins LinesArray hinter der akt. 392 // verschoben. 393 // Das LinesArray ist im pPara! 394 nLen = pBox->GetTabLines().Count(); 395 396 SwTableLines& rLns = *pGCPara->pLns; 397 const SwTableLine* pTmp = pLn; 398 sal_uInt16 nInsPos = rLns.GetPos( pTmp ); 399 ASSERT( USHRT_MAX != nInsPos, "Line nicht gefunden!" ); 400 401 SwTableBox* pUpper = pLn->GetUpper(); 402 403 rLns.Remove( nInsPos, 1 ); // die Line dem aus Array loeschen 404 rLns.Insert( &pBox->GetTabLines(), nInsPos ); 405 406 // JP 31.03.99: Bug 60000 - die Attribute der zu loeschenden 407 // Line an die "eingefuegten" uebertragen 408 const SfxPoolItem* pItem; 409 if( SFX_ITEM_SET == pLn->GetFrmFmt()->GetItemState( 410 RES_BACKGROUND, sal_True, &pItem )) 411 { 412 SwTableLines& rBoxLns = pBox->GetTabLines(); 413 for( sal_uInt16 nLns = 0; nLns < nLen; ++nLns ) 414 if( SFX_ITEM_SET != rBoxLns[ nLns ]->GetFrmFmt()-> 415 GetItemState( RES_BACKGROUND, sal_True )) 416 pGCPara->pShareFmts->SetAttr( *rBoxLns[ nLns ], *pItem ); 417 } 418 419 pBox->GetTabLines().Remove( 0, nLen ); // Lines aus Array loeschen 420 421 delete pLn; 422 423 // Abhaengigkeit neu setzen 424 while( nLen-- ) 425 rLns[ nInsPos++ ]->SetUpper( pUpper ); 426 427 pLn = pLine; // und neu setzen 428 nLen = pLn->GetTabBoxes().Count(); 429 } 430 431 // ACHTUNG: die Anzahl der Boxen kann sich aendern! 432 for( nLen = 0; nLen < pLn->GetTabBoxes().Count(); ++nLen ) 433 if( !lcl_MergeGCBox( *(pLn->GetTabBoxes().GetData() + nLen ), pPara )) 434 --nLen; 435 } 436 return sal_True; 437 } 438 439 // Struktur ein wenig aufraeumen 440 void SwTable::GCLines() 441 { 442 // ACHTUNG: die Anzahl der Lines kann sich aendern! 443 _GCLinePara aPara( GetTabLines() ); 444 SwShareBoxFmts aShareFmts; 445 aPara.pShareFmts = &aShareFmts; 446 for( sal_uInt16 n = 0; n < GetTabLines().Count() && 447 lcl_MergeGCLine( *(GetTabLines().GetData() + n ), &aPara ); ++n ) 448 ; 449 } 450 451 452