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