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 #include "hintids.hxx" 28 #include <editeng/lrspitem.hxx> 29 #include <editeng/boxitem.hxx> 30 #include <editeng/brshitem.hxx> 31 #include <editeng/frmdiritem.hxx> 32 #include <fmtornt.hxx> 33 #include <fmtfsize.hxx> 34 #include <fmtlsplt.hxx> 35 #include <fmtrowsplt.hxx> 36 #include <tabcol.hxx> 37 #include <frmatr.hxx> 38 #include <cellfrm.hxx> 39 #include <tabfrm.hxx> 40 #include <cntfrm.hxx> 41 #include <txtfrm.hxx> 42 #include <svx/svxids.hrc> 43 #include <doc.hxx> 44 #include <IDocumentUndoRedo.hxx> 45 #include "pam.hxx" 46 #include "swcrsr.hxx" 47 #include "viscrs.hxx" 48 #include "swtable.hxx" 49 #include "htmltbl.hxx" 50 #include "tblsel.hxx" 51 #include "swtblfmt.hxx" 52 #include "docary.hxx" 53 #include "ndindex.hxx" 54 #include "undobj.hxx" 55 #include "switerator.hxx" 56 #include <UndoTable.hxx> 57 58 using namespace ::com::sun::star; 59 60 61 extern void ClearFEShellTabCols(); 62 63 //siehe auch swtable.cxx 64 #define COLFUZZY 20L 65 66 inline sal_Bool IsSame( long nA, long nB ) { return Abs(nA-nB) <= COLFUZZY; } 67 68 class SwTblFmtCmp 69 { 70 public: 71 SwFrmFmt *pOld, 72 *pNew; 73 sal_Int16 nType; 74 75 SwTblFmtCmp( SwFrmFmt *pOld, SwFrmFmt *pNew, sal_Int16 nType ); 76 77 static SwFrmFmt *FindNewFmt( SvPtrarr &rArr, SwFrmFmt*pOld, sal_Int16 nType ); 78 static void Delete( SvPtrarr &rArr ); 79 }; 80 81 82 SwTblFmtCmp::SwTblFmtCmp( SwFrmFmt *pO, SwFrmFmt *pN, sal_Int16 nT ) 83 : pOld ( pO ), pNew ( pN ), nType( nT ) 84 { 85 } 86 87 SwFrmFmt *SwTblFmtCmp::FindNewFmt( SvPtrarr &rArr, SwFrmFmt *pOld, sal_Int16 nType ) 88 { 89 for ( sal_uInt16 i = 0; i < rArr.Count(); ++i ) 90 { 91 SwTblFmtCmp *pCmp = (SwTblFmtCmp*)rArr[i]; 92 if ( pCmp->pOld == pOld && pCmp->nType == nType ) 93 return pCmp->pNew; 94 } 95 return 0; 96 } 97 98 void SwTblFmtCmp::Delete( SvPtrarr &rArr ) 99 { 100 for ( sal_uInt16 i = 0; i < rArr.Count(); ++i ) 101 delete (SwTblFmtCmp*)rArr[i]; 102 } 103 104 void lcl_GetStartEndCell( const SwCursor& rCrsr, 105 SwLayoutFrm *&prStart, SwLayoutFrm *&prEnd ) 106 { 107 ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( sal_False ), 108 "Tabselection nicht auf Cnt." ); 109 110 Point aPtPos, aMkPos; 111 const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr); 112 if( pShCrsr ) 113 { 114 aPtPos = pShCrsr->GetPtPos(); 115 aMkPos = pShCrsr->GetMkPos(); 116 } 117 118 // robust: 119 SwCntntNode* pPointNd = rCrsr.GetCntntNode(); 120 SwCntntNode* pMarkNd = rCrsr.GetCntntNode(sal_False); 121 122 SwFrm* pPointFrm = pPointNd ? pPointNd->getLayoutFrm( pPointNd->GetDoc()->GetCurrentLayout(), &aPtPos ) : 0; 123 SwFrm* pMarkFrm = pMarkNd ? pMarkNd->getLayoutFrm( pMarkNd->GetDoc()->GetCurrentLayout(), &aMkPos ) : 0; 124 125 prStart = pPointFrm ? pPointFrm->GetUpper() : 0; 126 prEnd = pMarkFrm ? pMarkFrm->GetUpper() : 0; 127 } 128 129 sal_Bool lcl_GetBoxSel( const SwCursor& rCursor, SwSelBoxes& rBoxes, 130 sal_Bool bAllCrsr = sal_False ) 131 { 132 const SwTableCursor* pTblCrsr = 133 dynamic_cast<const SwTableCursor*>(&rCursor); 134 if( pTblCrsr ) 135 ::GetTblSelCrs( *pTblCrsr, rBoxes ); 136 else 137 { 138 const SwPaM *pCurPam = &rCursor, *pSttPam = pCurPam; 139 do { 140 const SwNode* pNd = pCurPam->GetNode()->FindTableBoxStartNode(); 141 if( pNd ) 142 { 143 SwTableBox* pBox = (SwTableBox*)pNd->FindTableNode()->GetTable(). 144 GetTblBox( pNd->GetIndex() ); 145 rBoxes.Insert( pBox ); 146 } 147 } while( bAllCrsr && 148 pSttPam != ( pCurPam = (SwPaM*)pCurPam->GetNext()) ); 149 } 150 return 0 != rBoxes.Count(); 151 } 152 153 /*********************************************************************** 154 #* Class : SwDoc 155 #* Methoden : SetRowHeight(), GetRowHeight() 156 #* Datum : MA 17. May. 93 157 #* Update : JP 28.04.98 158 #***********************************************************************/ 159 //Die Zeilenhoehe wird ausgehend von der Selektion ermittelt/gesetzt. 160 //Ausgehend von jeder Zelle innerhalb der Selektion werden nach oben alle 161 //Zeilen abgeklappert, die oberste Zeile erhaelt den gewuenschten Wert alle 162 //tieferliegenden Zeilen einen entsprechenden Wert der sich aus der 163 //Relation der alten und neuen Groesse der obersten Zeile und ihrer 164 //eigenen Groesse ergiebt. 165 //Alle veraenderten Zeilen erhalten ggf. ein eigenes FrmFmt. 166 //Natuerlich darf jede Zeile nur einmal angefasst werden. 167 168 inline void InsertLine( SvPtrarr& rLineArr, SwTableLine* pLine ) 169 { 170 if( USHRT_MAX == rLineArr.GetPos( pLine ) ) 171 rLineArr.Insert( pLine, rLineArr.Count() ); 172 } 173 174 //----------------------------------------------------------------------------- 175 176 sal_Bool lcl_IsAnLower( const SwTableLine *pLine, const SwTableLine *pAssumed ) 177 { 178 const SwTableLine *pTmp = pAssumed->GetUpper() ? 179 pAssumed->GetUpper()->GetUpper() : 0; 180 while ( pTmp ) 181 { 182 if ( pTmp == pLine ) 183 return sal_True; 184 pTmp = pTmp->GetUpper() ? pTmp->GetUpper()->GetUpper() : 0; 185 } 186 return sal_False; 187 } 188 //----------------------------------------------------------------------------- 189 190 struct LinesAndTable 191 { 192 SvPtrarr &rLines; 193 const SwTable &rTable; 194 sal_Bool bInsertLines; 195 196 LinesAndTable( SvPtrarr &rL, const SwTable &rTbl ) : 197 rLines( rL ), rTable( rTbl ), bInsertLines( sal_True ) {} 198 }; 199 200 201 sal_Bool _FindLine( const _FndLine*& rpLine, void* pPara ); 202 203 sal_Bool _FindBox( const _FndBox*& rpBox, void* pPara ) 204 { 205 if ( rpBox->GetLines().Count() ) 206 { 207 ((LinesAndTable*)pPara)->bInsertLines = sal_True; 208 ((_FndBox*)rpBox)->GetLines().ForEach( _FindLine, pPara ); 209 if ( ((LinesAndTable*)pPara)->bInsertLines ) 210 { 211 const SwTableLines &rLines = rpBox->GetBox() 212 ? rpBox->GetBox()->GetTabLines() 213 : ((LinesAndTable*)pPara)->rTable.GetTabLines(); 214 if ( rpBox->GetLines().Count() == rLines.Count() ) 215 { 216 for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) 217 ::InsertLine( ((LinesAndTable*)pPara)->rLines, 218 (SwTableLine*)rLines[i] ); 219 } 220 else 221 ((LinesAndTable*)pPara)->bInsertLines = sal_False; 222 } 223 } 224 else if ( rpBox->GetBox() ) 225 ::InsertLine( ((LinesAndTable*)pPara)->rLines, 226 (SwTableLine*)rpBox->GetBox()->GetUpper() ); 227 return sal_True; 228 } 229 230 sal_Bool _FindLine( const _FndLine*& rpLine, void* pPara ) 231 { 232 ((_FndLine*)rpLine)->GetBoxes().ForEach( _FindBox, pPara ); 233 return sal_True; 234 } 235 236 void lcl_CollectLines( SvPtrarr &rArr, const SwCursor& rCursor, bool bRemoveLines ) 237 { 238 //Zuerst die selektierten Boxen einsammeln. 239 SwSelBoxes aBoxes; 240 if( !::lcl_GetBoxSel( rCursor, aBoxes )) 241 return ; 242 243 //Die selektierte Struktur kopieren. 244 const SwTable &rTable = aBoxes[0]->GetSttNd()->FindTableNode()->GetTable(); 245 LinesAndTable aPara( rArr, rTable ); 246 _FndBox aFndBox( 0, 0 ); 247 { 248 _FndPara aTmpPara( aBoxes, &aFndBox ); 249 ((SwTableLines&)rTable.GetTabLines()).ForEach( &_FndLineCopyCol, &aTmpPara ); 250 } 251 252 //Diejenigen Lines einsammeln, die nur selektierte Boxen enthalten. 253 const _FndBox *pTmp = &aFndBox; 254 ::_FindBox( pTmp, &aPara ); 255 256 // Remove lines, that have a common superordinate row. 257 // (Not for row split) 258 if ( bRemoveLines ) 259 { 260 for ( sal_uInt16 i = 0; i < rArr.Count(); ++i ) 261 { 262 SwTableLine *pUpLine = (SwTableLine*)rArr[i]; 263 for ( sal_uInt16 k = 0; k < rArr.Count(); ++k ) 264 { 265 if ( k != i && ::lcl_IsAnLower( pUpLine, (SwTableLine*)rArr[k] ) ) 266 { 267 rArr.Remove( k ); 268 if ( k <= i ) 269 --i; 270 --k; 271 } 272 } 273 } 274 } 275 } 276 277 //----------------------------------------------------------------------------- 278 279 void lcl_ProcessRowAttr( SvPtrarr& rFmtCmp, SwTableLine* pLine, const SfxPoolItem& rNew ) 280 { 281 SwFrmFmt *pNewFmt; 282 if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( rFmtCmp, pLine->GetFrmFmt(), 0 ))) 283 pLine->ChgFrmFmt( (SwTableLineFmt*)pNewFmt ); 284 else 285 { 286 SwFrmFmt *pOld = pLine->GetFrmFmt(); 287 SwFrmFmt *pNew = pLine->ClaimFrmFmt(); 288 pNew->SetFmtAttr( rNew ); 289 rFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), rFmtCmp.Count()); 290 } 291 } 292 293 //----------------------------------------------------------------------------- 294 295 void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew ); 296 297 void lcl_ProcessRowSize( SvPtrarr &rFmtCmp, SwTableLine *pLine, const SwFmtFrmSize &rNew ) 298 { 299 lcl_ProcessRowAttr( rFmtCmp, pLine, rNew ); 300 SwTableBoxes &rBoxes = pLine->GetTabBoxes(); 301 for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) 302 ::lcl_ProcessBoxSize( rFmtCmp, rBoxes[i], rNew ); 303 } 304 305 //----------------------------------------------------------------------------- 306 307 void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew ) 308 { 309 SwTableLines &rLines = pBox->GetTabLines(); 310 if ( rLines.Count() ) 311 { 312 SwFmtFrmSize aSz( rNew ); 313 aSz.SetHeight( rNew.GetHeight() ? rNew.GetHeight() / rLines.Count() : 0 ); 314 for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) 315 ::lcl_ProcessRowSize( rFmtCmp, rLines[i], aSz ); 316 } 317 } 318 319 //----------------------------------------------------------------------------- 320 321 /****************************************************************************** 322 * void SwDoc::SetRowSplit() 323 ******************************************************************************/ 324 void SwDoc::SetRowSplit( const SwCursor& rCursor, const SwFmtRowSplit &rNew ) 325 { 326 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 327 if( pTblNd ) 328 { 329 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. 330 ::lcl_CollectLines( aRowArr, rCursor, false ); 331 332 if( aRowArr.Count() ) 333 { 334 if (GetIDocumentUndoRedo().DoesUndo()) 335 { 336 GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); 337 } 338 339 SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); 340 341 for( sal_uInt16 i = 0; i < aRowArr.Count(); ++i ) 342 ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); 343 344 SwTblFmtCmp::Delete( aFmtCmp ); 345 SetModified(); 346 } 347 } 348 } 349 350 351 /****************************************************************************** 352 * SwTwips SwDoc::GetRowSplit() const 353 ******************************************************************************/ 354 void SwDoc::GetRowSplit( const SwCursor& rCursor, SwFmtRowSplit *& rpSz ) const 355 { 356 rpSz = 0; 357 358 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 359 if( pTblNd ) 360 { 361 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. 362 ::lcl_CollectLines( aRowArr, rCursor, false ); 363 364 if( aRowArr.Count() ) 365 { 366 rpSz = &(SwFmtRowSplit&)((SwTableLine*)aRowArr[0])-> 367 GetFrmFmt()->GetRowSplit(); 368 369 for ( sal_uInt16 i = 1; i < aRowArr.Count() && rpSz; ++i ) 370 { 371 if ( (*rpSz).GetValue() != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetRowSplit().GetValue() ) 372 rpSz = 0; 373 } 374 if ( rpSz ) 375 rpSz = new SwFmtRowSplit( *rpSz ); 376 } 377 } 378 } 379 380 381 /****************************************************************************** 382 * void SwDoc::SetRowHeight( SwTwips nNew ) 383 ******************************************************************************/ 384 void SwDoc::SetRowHeight( const SwCursor& rCursor, const SwFmtFrmSize &rNew ) 385 { 386 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 387 if( pTblNd ) 388 { 389 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. 390 ::lcl_CollectLines( aRowArr, rCursor, true ); 391 392 if( aRowArr.Count() ) 393 { 394 if (GetIDocumentUndoRedo().DoesUndo()) 395 { 396 GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); 397 } 398 399 SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); 400 for ( sal_uInt16 i = 0; i < aRowArr.Count(); ++i ) 401 ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); 402 SwTblFmtCmp::Delete( aFmtCmp ); 403 404 SetModified(); 405 } 406 } 407 } 408 409 410 /****************************************************************************** 411 * SwTwips SwDoc::GetRowHeight() const 412 ******************************************************************************/ 413 void SwDoc::GetRowHeight( const SwCursor& rCursor, SwFmtFrmSize *& rpSz ) const 414 { 415 rpSz = 0; 416 417 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 418 if( pTblNd ) 419 { 420 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. 421 ::lcl_CollectLines( aRowArr, rCursor, true ); 422 423 if( aRowArr.Count() ) 424 { 425 rpSz = &(SwFmtFrmSize&)((SwTableLine*)aRowArr[0])-> 426 GetFrmFmt()->GetFrmSize(); 427 428 for ( sal_uInt16 i = 1; i < aRowArr.Count() && rpSz; ++i ) 429 { 430 if ( *rpSz != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetFrmSize() ) 431 rpSz = 0; 432 } 433 if ( rpSz ) 434 rpSz = new SwFmtFrmSize( *rpSz ); 435 } 436 } 437 } 438 439 sal_Bool SwDoc::BalanceRowHeight( const SwCursor& rCursor, sal_Bool bTstOnly ) 440 { 441 sal_Bool bRet = sal_False; 442 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 443 if( pTblNd ) 444 { 445 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. 446 ::lcl_CollectLines( aRowArr, rCursor, true ); 447 448 if( 1 < aRowArr.Count() ) 449 { 450 if( !bTstOnly ) 451 { 452 long nHeight = 0; 453 sal_uInt16 i; 454 455 for ( i = 0; i < aRowArr.Count(); ++i ) 456 { 457 SwIterator<SwFrm,SwFmt> aIter( *((SwTableLine*)aRowArr[i])->GetFrmFmt() ); 458 SwFrm* pFrm = aIter.First(); 459 while ( pFrm ) 460 { 461 nHeight = Max( nHeight, pFrm->Frm().Height() ); 462 pFrm = aIter.Next(); 463 } 464 } 465 SwFmtFrmSize aNew( ATT_MIN_SIZE, 0, nHeight ); 466 467 if (GetIDocumentUndoRedo().DoesUndo()) 468 { 469 GetIDocumentUndoRedo().AppendUndo( 470 new SwUndoAttrTbl(*pTblNd)); 471 } 472 473 SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); 474 for( i = 0; i < aRowArr.Count(); ++i ) 475 ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], aNew ); 476 SwTblFmtCmp::Delete( aFmtCmp ); 477 478 SetModified(); 479 } 480 bRet = sal_True; 481 } 482 } 483 return bRet; 484 } 485 486 /****************************************************************************** 487 * void SwDoc::SetRowBackground() 488 ******************************************************************************/ 489 void SwDoc::SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew ) 490 { 491 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 492 if( pTblNd ) 493 { 494 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. 495 ::lcl_CollectLines( aRowArr, rCursor, true ); 496 497 if( aRowArr.Count() ) 498 { 499 if (GetIDocumentUndoRedo().DoesUndo()) 500 { 501 GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); 502 } 503 504 SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); 505 506 for( sal_uInt16 i = 0; i < aRowArr.Count(); ++i ) 507 ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); 508 509 SwTblFmtCmp::Delete( aFmtCmp ); 510 SetModified(); 511 } 512 } 513 } 514 515 /****************************************************************************** 516 * SwTwips SwDoc::GetRowBackground() const 517 ******************************************************************************/ 518 sal_Bool SwDoc::GetRowBackground( const SwCursor& rCursor, SvxBrushItem &rToFill ) const 519 { 520 sal_Bool bRet = sal_False; 521 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 522 if( pTblNd ) 523 { 524 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. 525 ::lcl_CollectLines( aRowArr, rCursor, true ); 526 527 if( aRowArr.Count() ) 528 { 529 rToFill = ((SwTableLine*)aRowArr[0])->GetFrmFmt()->GetBackground(); 530 531 bRet = sal_True; 532 for ( sal_uInt16 i = 1; i < aRowArr.Count(); ++i ) 533 if ( rToFill != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetBackground() ) 534 { 535 bRet = sal_False; 536 break; 537 } 538 } 539 } 540 return bRet; 541 } 542 543 /*********************************************************************** 544 #* Class : SwDoc 545 #* Methoden : SetTabBorders(), GetTabBorders() 546 #* Datum : MA 18. May. 93 547 #* Update : JP 29.04.98 548 #***********************************************************************/ 549 inline void InsertCell( SvPtrarr& rCellArr, SwCellFrm* pCellFrm ) 550 { 551 if( USHRT_MAX == rCellArr.GetPos( pCellFrm ) ) 552 rCellArr.Insert( pCellFrm, rCellArr.Count() ); 553 } 554 555 //----------------------------------------------------------------------------- 556 void lcl_CollectCells( SvPtrarr &rArr, const SwRect &rUnion, 557 SwTabFrm *pTab ) 558 { 559 SwLayoutFrm *pCell = pTab->FirstCell(); 560 do 561 { 562 // Wenn in der Zelle ein spaltiger Bereich sitzt, muessen wir 563 // uns erst wieder zur Zelle hochhangeln 564 while ( !pCell->IsCellFrm() ) 565 pCell = pCell->GetUpper(); 566 ASSERT( pCell, "Frame ist keine Zelle." ); 567 if ( rUnion.IsOver( pCell->Frm() ) ) 568 ::InsertCell( rArr, (SwCellFrm*)pCell ); 569 //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche) 570 SwLayoutFrm *pTmp = pCell; 571 do 572 { pTmp = pTmp->GetNextLayoutLeaf(); 573 } while ( pCell->IsAnLower( pTmp ) ); 574 pCell = pTmp; 575 } while( pCell && pTab->IsAnLower( pCell ) ); 576 } 577 578 void SwDoc::SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet ) 579 { 580 SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); 581 SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; 582 if( !pTblNd ) 583 return ; 584 585 SwLayoutFrm *pStart, *pEnd; 586 ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); 587 588 SwSelUnions aUnions; 589 ::MakeSelUnions( aUnions, pStart, pEnd ); 590 591 if( aUnions.Count() ) 592 { 593 SwTable& rTable = pTblNd->GetTable(); 594 if (GetIDocumentUndoRedo().DoesUndo()) 595 { 596 GetIDocumentUndoRedo().AppendUndo( new SwUndoAttrTbl(*pTblNd) ); 597 } 598 599 SvPtrarr aFmtCmp( 255, 255 ); 600 const SvxBoxItem* pSetBox; 601 const SvxBoxInfoItem *pSetBoxInfo; 602 603 const SvxBorderLine* pLeft = 0; 604 const SvxBorderLine* pRight = 0; 605 const SvxBorderLine* pTop = 0; 606 const SvxBorderLine* pBottom = 0; 607 const SvxBorderLine* pHori = 0; 608 const SvxBorderLine* pVert = 0; 609 sal_Bool bHoriValid = sal_True, bVertValid = sal_True, 610 bTopValid = sal_True, bBottomValid = sal_True, 611 bLeftValid = sal_True, bRightValid = sal_True; 612 613 // JP 21.07.95: die Flags im BoxInfo-Item entscheiden, wann eine 614 // BorderLine gueltig ist!! 615 if( SFX_ITEM_SET == rSet.GetItemState( SID_ATTR_BORDER_INNER, sal_False, 616 (const SfxPoolItem**)&pSetBoxInfo) ) 617 { 618 pHori = pSetBoxInfo->GetHori(); 619 pVert = pSetBoxInfo->GetVert(); 620 621 bHoriValid = pSetBoxInfo->IsValid(VALID_HORI); 622 bVertValid = pSetBoxInfo->IsValid(VALID_VERT); 623 624 // wollen wir die auswerten ?? 625 bTopValid = pSetBoxInfo->IsValid(VALID_TOP); 626 bBottomValid = pSetBoxInfo->IsValid(VALID_BOTTOM); 627 bLeftValid = pSetBoxInfo->IsValid(VALID_LEFT); 628 bRightValid = pSetBoxInfo->IsValid(VALID_RIGHT); 629 } 630 631 if( SFX_ITEM_SET == rSet.GetItemState( RES_BOX, sal_False, 632 (const SfxPoolItem**)&pSetBox) ) 633 { 634 pLeft = pSetBox->GetLeft(); 635 pRight = pSetBox->GetRight(); 636 pTop = pSetBox->GetTop(); 637 pBottom = pSetBox->GetBottom(); 638 } 639 else 640 { 641 // nicht gesetzt, also keine gueltigen Werte 642 bTopValid = bBottomValid = bLeftValid = bRightValid = sal_False; 643 pSetBox = 0; 644 } 645 646 sal_Bool bFirst = sal_True; 647 for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) 648 { 649 SwSelUnion *pUnion = aUnions[i]; 650 SwTabFrm *pTab = pUnion->GetTable(); 651 const SwRect &rUnion = pUnion->GetUnion(); 652 const sal_Bool bLast = i == aUnions.Count() - 1 ? sal_True : sal_False; 653 654 SvPtrarr aCellArr( 255, 255 ); 655 ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab ); 656 657 //Alle Zellenkanten, die mit dem UnionRect uebereinstimmen oder 658 //darueber hinausragen sind Aussenkanten. Alle anderen sind 659 //Innenkanten. 660 //neu: Die Aussenkanten koennen abhaengig davon, ob es sich um eine 661 //Start/Mittlere/Folge -Tabelle (bei Selektionen ueber FollowTabs) 662 //handelt doch keine Aussenkanten sein. 663 //Aussenkanten werden links, rechts, oben und unten gesetzt. 664 //Innenkanten werden nur oben und links gesetzt. 665 for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j ) 666 { 667 SwCellFrm *pCell = (SwCellFrm*)aCellArr[j]; 668 const sal_Bool bVert = pTab->IsVertical(); 669 const sal_Bool bRTL = pTab->IsRightToLeft(); 670 sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver; 671 if ( bVert ) 672 { 673 bTopOver = pCell->Frm().Right() >= rUnion.Right(); 674 bLeftOver = pCell->Frm().Top() <= rUnion.Top(); 675 bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom(); 676 bBottomOver = pCell->Frm().Left() <= rUnion.Left(); 677 } 678 else 679 { 680 bTopOver = pCell->Frm().Top() <= rUnion.Top(); 681 bLeftOver = pCell->Frm().Left() <= rUnion.Left(); 682 bRightOver = pCell->Frm().Right() >= rUnion.Right(); 683 bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom(); 684 } 685 686 if ( bRTL ) 687 { 688 sal_Bool bTmp = bRightOver; 689 bRightOver = bLeftOver; 690 bLeftOver = bTmp; 691 } 692 693 //Grundsaetzlich nichts setzen in HeadlineRepeats. 694 if ( pTab->IsFollow() && 695 ( pTab->IsInHeadline( *pCell ) || 696 // --> FME 2006-02-07 #126092# Same holds for follow flow rows. 697 pCell->IsInFollowFlowRow() ) ) 698 // <-- 699 continue; 700 701 SvxBoxItem aBox( pCell->GetFmt()->GetBox() ); 702 703 sal_Int16 nType = 0; 704 705 //Obere Kante 706 if( bTopValid ) 707 { 708 if ( bFirst && bTopOver ) 709 { 710 aBox.SetLine( pTop, BOX_LINE_TOP ); 711 nType |= 0x0001; 712 } 713 else if ( bHoriValid ) 714 { 715 aBox.SetLine( 0, BOX_LINE_TOP ); 716 nType |= 0x0002; 717 } 718 } 719 720 //Linke Kante 721 if ( bLeftOver ) 722 { 723 if( bLeftValid ) 724 { 725 aBox.SetLine( pLeft, BOX_LINE_LEFT ); 726 nType |= 0x0004; 727 } 728 } 729 else if( bVertValid ) 730 { 731 aBox.SetLine( pVert, BOX_LINE_LEFT ); 732 nType |= 0x0008; 733 } 734 735 //Rechte Kante 736 if( bRightValid ) 737 { 738 if ( bRightOver ) 739 { 740 aBox.SetLine( pRight, BOX_LINE_RIGHT ); 741 nType |= 0x0010; 742 } 743 else if ( bVertValid ) 744 { 745 aBox.SetLine( 0, BOX_LINE_RIGHT ); 746 nType |= 0x0020; 747 } 748 } 749 750 //Untere Kante 751 if ( bLast && bBottomOver ) 752 { 753 if( bBottomValid ) 754 { 755 aBox.SetLine( pBottom, BOX_LINE_BOTTOM ); 756 nType |= 0x0040; 757 } 758 } 759 else if( bHoriValid ) 760 { 761 aBox.SetLine( pHori, BOX_LINE_BOTTOM ); 762 nType |= 0x0080; 763 } 764 765 if( pSetBox ) 766 { 767 static sal_uInt16 __READONLY_DATA aBorders[] = { 768 BOX_LINE_BOTTOM, BOX_LINE_TOP, 769 BOX_LINE_RIGHT, BOX_LINE_LEFT }; 770 const sal_uInt16* pBrd = aBorders; 771 for( int k = 0; k < 4; ++k, ++pBrd ) 772 aBox.SetDistance( pSetBox->GetDistance( *pBrd ), *pBrd ); 773 } 774 775 SwTableBox *pBox = (SwTableBox*)pCell->GetTabBox(); 776 SwFrmFmt *pNewFmt; 777 if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), nType ))) 778 pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt ); 779 else 780 { 781 SwFrmFmt *pOld = pBox->GetFrmFmt(); 782 SwFrmFmt *pNew = pBox->ClaimFrmFmt(); 783 pNew->SetFmtAttr( aBox ); 784 aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, nType ), aFmtCmp.Count()); 785 } 786 } 787 788 bFirst = sal_False; 789 } 790 791 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); 792 if( pTableLayout ) 793 { 794 SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); 795 SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); 796 797 pTableLayout->BordersChanged( 798 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True ); 799 } 800 SwTblFmtCmp::Delete( aFmtCmp ); 801 ::ClearFEShellTabCols(); 802 SetModified(); 803 } 804 } 805 806 void lcl_SetLineStyle( SvxBorderLine *pToSet, 807 const Color *pColor, const SvxBorderLine *pBorderLine) 808 { 809 if ( pBorderLine ) 810 { 811 if ( !pColor ) 812 { 813 Color aTmp( pToSet->GetColor() ); 814 *pToSet = *pBorderLine; 815 pToSet->SetColor( aTmp ); 816 } 817 else 818 *pToSet = *pBorderLine; 819 } 820 if ( pColor ) 821 pToSet->SetColor( *pColor ); 822 } 823 824 void SwDoc::SetTabLineStyle( const SwCursor& rCursor, 825 const Color* pColor, sal_Bool bSetLine, 826 const SvxBorderLine* pBorderLine ) 827 { 828 SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); 829 SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; 830 if( !pTblNd ) 831 return ; 832 833 SwLayoutFrm *pStart, *pEnd; 834 ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); 835 836 SwSelUnions aUnions; 837 ::MakeSelUnions( aUnions, pStart, pEnd ); 838 839 if( aUnions.Count() ) 840 { 841 SwTable& rTable = pTblNd->GetTable(); 842 if (GetIDocumentUndoRedo().DoesUndo()) 843 { 844 GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); 845 } 846 847 for( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) 848 { 849 SwSelUnion *pUnion = aUnions[i]; 850 SwTabFrm *pTab = pUnion->GetTable(); 851 SvPtrarr aCellArr( 255, 255 ); 852 ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab ); 853 854 for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j ) 855 { 856 SwCellFrm *pCell = ( SwCellFrm* )aCellArr[j]; 857 858 //Grundsaetzlich nichts setzen in HeadlineRepeats. 859 if ( pTab->IsFollow() && pTab->IsInHeadline( *pCell ) ) 860 continue; 861 862 ((SwTableBox*)pCell->GetTabBox())->ClaimFrmFmt(); 863 SwFrmFmt *pFmt = pCell->GetFmt(); 864 SvxBoxItem aBox( pFmt->GetBox() ); 865 866 if ( !pBorderLine && bSetLine ) 867 aBox = *(SvxBoxItem*)::GetDfltAttr( RES_BOX ); 868 else 869 { 870 if ( aBox.GetTop() ) 871 ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetTop(), 872 pColor, pBorderLine ); 873 if ( aBox.GetBottom() ) 874 ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetBottom(), 875 pColor, pBorderLine ); 876 if ( aBox.GetLeft() ) 877 ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetLeft(), 878 pColor, pBorderLine ); 879 if ( aBox.GetRight() ) 880 ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetRight(), 881 pColor, pBorderLine ); 882 } 883 pFmt->SetFmtAttr( aBox ); 884 } 885 } 886 887 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); 888 if( pTableLayout ) 889 { 890 SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); 891 SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); 892 893 pTableLayout->BordersChanged( 894 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True ); 895 } 896 ::ClearFEShellTabCols(); 897 SetModified(); 898 } 899 } 900 901 void SwDoc::GetTabBorders( const SwCursor& rCursor, SfxItemSet& rSet ) const 902 { 903 SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); 904 SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; 905 if( !pTblNd ) 906 return ; 907 908 SwLayoutFrm *pStart, *pEnd; 909 ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); 910 911 SwSelUnions aUnions; 912 ::MakeSelUnions( aUnions, pStart, pEnd ); 913 914 if( aUnions.Count() ) 915 { 916 SvxBoxItem aSetBox ((const SvxBoxItem &) rSet.Get(RES_BOX )); 917 SvxBoxInfoItem aSetBoxInfo((const SvxBoxInfoItem&) rSet.Get(SID_ATTR_BORDER_INNER)); 918 919 sal_Bool bTopSet = sal_False, 920 bBottomSet = sal_False, 921 bLeftSet = sal_False, 922 bRightSet = sal_False, 923 bHoriSet = sal_False, 924 bVertSet = sal_False, 925 bDistanceSet = sal_False; 926 927 aSetBoxInfo.ResetFlags(); 928 929 for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) 930 { 931 SwSelUnion *pUnion = aUnions[i]; 932 const SwTabFrm *pTab = pUnion->GetTable(); 933 const SwRect &rUnion = pUnion->GetUnion(); 934 const sal_Bool bFirst = i == 0 ? sal_True : sal_False; 935 const sal_Bool bLast = i == aUnions.Count() - 1 ? sal_True : sal_False; 936 937 SvPtrarr aCellArr( 255, 255 ); 938 ::lcl_CollectCells( aCellArr, rUnion, (SwTabFrm*)pTab ); 939 940 for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j ) 941 { 942 const SwCellFrm *pCell = (const SwCellFrm*)aCellArr[j]; 943 const sal_Bool bVert = pTab->IsVertical(); 944 const sal_Bool bRTL = pTab->IsRightToLeft(); 945 sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver; 946 if ( bVert ) 947 { 948 bTopOver = pCell->Frm().Right() >= rUnion.Right(); 949 bLeftOver = pCell->Frm().Top() <= rUnion.Top(); 950 bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom(); 951 bBottomOver = pCell->Frm().Left() <= rUnion.Left(); 952 } 953 else 954 { 955 bTopOver = pCell->Frm().Top() <= rUnion.Top(); 956 bLeftOver = pCell->Frm().Left() <= rUnion.Left(); 957 bRightOver = pCell->Frm().Right() >= rUnion.Right(); 958 bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom(); 959 } 960 961 if ( bRTL ) 962 { 963 sal_Bool bTmp = bRightOver; 964 bRightOver = bLeftOver; 965 bLeftOver = bTmp; 966 } 967 968 const SwFrmFmt *pFmt = pCell->GetFmt(); 969 const SvxBoxItem &rBox = pFmt->GetBox(); 970 971 //Obere Kante 972 if ( bFirst && bTopOver ) 973 { 974 if (aSetBoxInfo.IsValid(VALID_TOP)) 975 { 976 if ( !bTopSet ) 977 { bTopSet = sal_True; 978 aSetBox.SetLine( rBox.GetTop(), BOX_LINE_TOP ); 979 } 980 else if ((aSetBox.GetTop() && rBox.GetTop() && 981 !(*aSetBox.GetTop() == *rBox.GetTop())) || 982 ((!aSetBox.GetTop()) ^ (!rBox.GetTop()))) // XOR-Ausdruck ist sal_True, wenn genau einer der beiden Pointer 0 ist 983 { 984 aSetBoxInfo.SetValid(VALID_TOP, sal_False ); 985 aSetBox.SetLine( 0, BOX_LINE_TOP ); 986 } 987 } 988 } 989 990 //Linke Kante 991 if ( bLeftOver ) 992 { 993 if (aSetBoxInfo.IsValid(VALID_LEFT)) 994 { 995 if ( !bLeftSet ) 996 { bLeftSet = sal_True; 997 aSetBox.SetLine( rBox.GetLeft(), BOX_LINE_LEFT ); 998 } 999 else if ((aSetBox.GetLeft() && rBox.GetLeft() && 1000 !(*aSetBox.GetLeft() == *rBox.GetLeft())) || 1001 ((!aSetBox.GetLeft()) ^ (!rBox.GetLeft()))) 1002 { 1003 aSetBoxInfo.SetValid(VALID_LEFT, sal_False ); 1004 aSetBox.SetLine( 0, BOX_LINE_LEFT ); 1005 } 1006 } 1007 } 1008 else 1009 { 1010 if (aSetBoxInfo.IsValid(VALID_VERT)) 1011 { 1012 if ( !bVertSet ) 1013 { bVertSet = sal_True; 1014 aSetBoxInfo.SetLine( rBox.GetLeft(), BOXINFO_LINE_VERT ); 1015 } 1016 else if ((aSetBoxInfo.GetVert() && rBox.GetLeft() && 1017 !(*aSetBoxInfo.GetVert() == *rBox.GetLeft())) || 1018 ((!aSetBoxInfo.GetVert()) ^ (!rBox.GetLeft()))) 1019 { aSetBoxInfo.SetValid( VALID_VERT, sal_False ); 1020 aSetBoxInfo.SetLine( 0, BOXINFO_LINE_VERT ); 1021 } 1022 } 1023 } 1024 1025 //Rechte Kante 1026 if ( aSetBoxInfo.IsValid(VALID_RIGHT) && bRightOver ) 1027 { 1028 if ( !bRightSet ) 1029 { bRightSet = sal_True; 1030 aSetBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT ); 1031 } 1032 else if ((aSetBox.GetRight() && rBox.GetRight() && 1033 !(*aSetBox.GetRight() == *rBox.GetRight())) || 1034 (!aSetBox.GetRight() ^ !rBox.GetRight())) 1035 { aSetBoxInfo.SetValid( VALID_RIGHT, sal_False ); 1036 aSetBox.SetLine( 0, BOX_LINE_RIGHT ); 1037 } 1038 } 1039 1040 //Untere Kante 1041 if ( bLast && bBottomOver ) 1042 { 1043 if ( aSetBoxInfo.IsValid(VALID_BOTTOM) ) 1044 { 1045 if ( !bBottomSet ) 1046 { bBottomSet = sal_True; 1047 aSetBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM ); 1048 } 1049 else if ((aSetBox.GetBottom() && rBox.GetBottom() && 1050 !(*aSetBox.GetBottom() == *rBox.GetBottom())) || 1051 (!aSetBox.GetBottom() ^ !rBox.GetBottom())) 1052 { aSetBoxInfo.SetValid( VALID_BOTTOM, sal_False ); 1053 aSetBox.SetLine( 0, BOX_LINE_BOTTOM ); 1054 } 1055 } 1056 } 1057 //in allen Zeilen ausser der letzten werden die 1058 // horiz. Linien aus der Bottom-Linie entnommen 1059 else 1060 { 1061 if (aSetBoxInfo.IsValid(VALID_HORI)) 1062 { 1063 if ( !bHoriSet ) 1064 { bHoriSet = sal_True; 1065 aSetBoxInfo.SetLine( rBox.GetBottom(), BOXINFO_LINE_HORI ); 1066 } 1067 else if ((aSetBoxInfo.GetHori() && rBox.GetBottom() && 1068 !(*aSetBoxInfo.GetHori() == *rBox.GetBottom())) || 1069 ((!aSetBoxInfo.GetHori()) ^ (!rBox.GetBottom()))) 1070 { 1071 aSetBoxInfo.SetValid( VALID_HORI, sal_False ); 1072 aSetBoxInfo.SetLine( 0, BOXINFO_LINE_HORI ); 1073 } 1074 } 1075 } 1076 1077 // Abstand zum Text 1078 if (aSetBoxInfo.IsValid(VALID_DISTANCE)) 1079 { 1080 static sal_uInt16 __READONLY_DATA aBorders[] = { 1081 BOX_LINE_BOTTOM, BOX_LINE_TOP, 1082 BOX_LINE_RIGHT, BOX_LINE_LEFT }; 1083 const sal_uInt16* pBrd = aBorders; 1084 1085 if( !bDistanceSet ) // bei 1. Durchlauf erstmal setzen 1086 { 1087 bDistanceSet = sal_True; 1088 for( int k = 0; k < 4; ++k, ++pBrd ) 1089 aSetBox.SetDistance( rBox.GetDistance( *pBrd ), 1090 *pBrd ); 1091 } 1092 else 1093 { 1094 for( int k = 0; k < 4; ++k, ++pBrd ) 1095 if( aSetBox.GetDistance( *pBrd ) != 1096 rBox.GetDistance( *pBrd ) ) 1097 { 1098 aSetBoxInfo.SetValid( VALID_DISTANCE, sal_False ); 1099 aSetBox.SetDistance( (sal_uInt16) 0 ); 1100 break; 1101 } 1102 } 1103 } 1104 } 1105 } 1106 rSet.Put( aSetBox ); 1107 rSet.Put( aSetBoxInfo ); 1108 } 1109 } 1110 1111 /*********************************************************************** 1112 #* Class : SwDoc 1113 #* Methoden : SetBoxAttr 1114 #* Datum : MA 18. Dec. 96 1115 #* Update : JP 29.04.98 1116 #***********************************************************************/ 1117 void SwDoc::SetBoxAttr( const SwCursor& rCursor, const SfxPoolItem &rNew ) 1118 { 1119 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 1120 SwSelBoxes aBoxes; 1121 if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes, sal_True ) ) 1122 { 1123 SwTable& rTable = pTblNd->GetTable(); 1124 if (GetIDocumentUndoRedo().DoesUndo()) 1125 { 1126 GetIDocumentUndoRedo().AppendUndo( new SwUndoAttrTbl(*pTblNd) ); 1127 } 1128 1129 SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aBoxes.Count()) ), 255 ); 1130 for ( sal_uInt16 i = 0; i < aBoxes.Count(); ++i ) 1131 { 1132 SwTableBox *pBox = aBoxes[i]; 1133 1134 SwFrmFmt *pNewFmt; 1135 if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), 0 ))) 1136 pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt ); 1137 else 1138 { 1139 SwFrmFmt *pOld = pBox->GetFrmFmt(); 1140 SwFrmFmt *pNew = pBox->ClaimFrmFmt(); 1141 pNew->SetFmtAttr( rNew ); 1142 aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), aFmtCmp.Count()); 1143 } 1144 } 1145 1146 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); 1147 if( pTableLayout ) 1148 { 1149 SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); 1150 SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); 1151 1152 pTableLayout->Resize( 1153 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True ); 1154 } 1155 SwTblFmtCmp::Delete( aFmtCmp ); 1156 SetModified(); 1157 } 1158 } 1159 1160 /*********************************************************************** 1161 #* Class : SwDoc 1162 #* Methoden : GetBoxAttr() 1163 #* Datum : MA 01. Jun. 93 1164 #* Update : JP 29.04.98 1165 #***********************************************************************/ 1166 1167 sal_Bool SwDoc::GetBoxAttr( const SwCursor& rCursor, SfxPoolItem& rToFill ) const 1168 { 1169 sal_Bool bRet = sal_False; 1170 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 1171 SwSelBoxes aBoxes; 1172 if( pTblNd && lcl_GetBoxSel( rCursor, aBoxes )) 1173 { 1174 bRet = sal_True; 1175 sal_Bool bOneFound = sal_False; 1176 const sal_uInt16 nWhich = rToFill.Which(); 1177 for( sal_uInt16 i = 0; i < aBoxes.Count(); ++i ) 1178 { 1179 switch ( nWhich ) 1180 { 1181 case RES_BACKGROUND: 1182 { 1183 const SvxBrushItem &rBack = 1184 aBoxes[i]->GetFrmFmt()->GetBackground(); 1185 if( !bOneFound ) 1186 { 1187 (SvxBrushItem&)rToFill = rBack; 1188 bOneFound = sal_True; 1189 } 1190 else if( rToFill != rBack ) 1191 bRet = sal_False; 1192 } 1193 break; 1194 1195 case RES_FRAMEDIR: 1196 { 1197 const SvxFrameDirectionItem& rDir = 1198 aBoxes[i]->GetFrmFmt()->GetFrmDir(); 1199 if( !bOneFound ) 1200 { 1201 (SvxFrameDirectionItem&)rToFill = rDir; 1202 bOneFound = sal_True; 1203 } 1204 else if( rToFill != rDir ) 1205 bRet = sal_False; 1206 } 1207 } 1208 1209 if ( sal_False == bRet ) 1210 break; 1211 } 1212 } 1213 return bRet; 1214 } 1215 1216 /*********************************************************************** 1217 #* Class : SwDoc 1218 #* Methoden : SetBoxAlign, SetBoxAlign 1219 #* Datum : MA 18. Dec. 96 1220 #* Update : JP 29.04.98 1221 #***********************************************************************/ 1222 void SwDoc::SetBoxAlign( const SwCursor& rCursor, sal_uInt16 nAlign ) 1223 { 1224 ASSERT( nAlign == text::VertOrientation::NONE || 1225 nAlign == text::VertOrientation::CENTER || 1226 nAlign == text::VertOrientation::BOTTOM, "wrong alignment" ); 1227 SwFmtVertOrient aVertOri( 0, nAlign ); 1228 SetBoxAttr( rCursor, aVertOri ); 1229 } 1230 1231 sal_uInt16 SwDoc::GetBoxAlign( const SwCursor& rCursor ) const 1232 { 1233 sal_uInt16 nAlign = USHRT_MAX; 1234 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); 1235 SwSelBoxes aBoxes; 1236 if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes )) 1237 for( sal_uInt16 i = 0; i < aBoxes.Count(); ++i ) 1238 { 1239 const SwFmtVertOrient &rOri = 1240 aBoxes[i]->GetFrmFmt()->GetVertOrient(); 1241 if( USHRT_MAX == nAlign ) 1242 nAlign = static_cast<sal_uInt16>(rOri.GetVertOrient()); 1243 else if( rOri.GetVertOrient() != nAlign ) 1244 { 1245 nAlign = USHRT_MAX; 1246 break; 1247 } 1248 } 1249 return nAlign; 1250 } 1251 1252 1253 /*********************************************************************** 1254 #* Class : SwDoc 1255 #* Methoden : AdjustCellWidth() 1256 #* Datum : MA 20. Feb. 95 1257 #* Update : JP 29.04.98 1258 #***********************************************************************/ 1259 sal_uInt16 lcl_CalcCellFit( const SwLayoutFrm *pCell ) 1260 { 1261 SwTwips nRet = 0; 1262 const SwFrm *pFrm = pCell->Lower(); //Die ganze Zelle. 1263 SWRECTFN( pCell ) 1264 while ( pFrm ) 1265 { 1266 const SwTwips nAdd = (pFrm->Frm().*fnRect->fnGetWidth)() - 1267 (pFrm->Prt().*fnRect->fnGetWidth)(); 1268 1269 // --> FME 2005-12-02 #127801# pFrm does not necessarily have to be a SwTxtFrm! 1270 const SwTwips nCalcFitToContent = pFrm->IsTxtFrm() ? 1271 ((SwTxtFrm*)pFrm)->CalcFitToContent() : 1272 (pFrm->Prt().*fnRect->fnGetWidth)(); 1273 // <-- 1274 1275 nRet = Max( nRet, nCalcFitToContent + nAdd ); 1276 pFrm = pFrm->GetNext(); 1277 } 1278 //Umrandung und linker/rechter Rand wollen mit kalkuliert werden. 1279 nRet += (pCell->Frm().*fnRect->fnGetWidth)() - 1280 (pCell->Prt().*fnRect->fnGetWidth)(); 1281 1282 //Um Rechenungenauikeiten, die spaeter bei SwTable::SetTabCols enstehen, 1283 //auszugleichen, addieren wir noch ein bischen. 1284 nRet += COLFUZZY; 1285 return (sal_uInt16)Max( long(MINLAY), nRet ); 1286 } 1287 1288 /*Die Zelle ist in der Selektion, wird aber nicht von den TabCols beschrieben. 1289 *Das bedeutet, dass die Zelle aufgrund der zweidimensionalen Darstellung von 1290 *anderen Zellen "geteilt" wurde. Wir muessen also den Wunsch- bzw. Minimalwert 1291 *der Zelle auf die Spalten, durch die sie geteilt wurde verteilen. 1292 * 1293 *Dazu sammeln wir zuerst die Spalten - nicht die Spaltentrenner! - ein, die 1294 *sich mit der Zelle ueberschneiden. Den Wunschwert der Zelle verteilen wir 1295 *dann anhand des Betrages der Ueberschneidung auf die Zellen. 1296 *Wenn eine Zelle bereits einen groesseren Wunschwert angemeldet hat, so bleibt 1297 *dieser erhalten, kleinere Wuensche werden ueberschrieben. 1298 */ 1299 1300 void lcl_CalcSubColValues( SvUShorts &rToFill, const SwTabCols &rCols, 1301 const SwLayoutFrm *pCell, const SwLayoutFrm *pTab, 1302 sal_Bool bWishValues ) 1303 { 1304 const sal_uInt16 nWish = bWishValues ? 1305 ::lcl_CalcCellFit( pCell ) : 1306 MINLAY + sal_uInt16(pCell->Frm().Width() - pCell->Prt().Width()); 1307 1308 SWRECTFN( pTab ) 1309 1310 for ( sal_uInt16 i = 0 ; i <= rCols.Count(); ++i ) 1311 { 1312 long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1]; 1313 long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i]; 1314 nColLeft += rCols.GetLeftMin(); 1315 nColRight += rCols.GetLeftMin(); 1316 1317 //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen. 1318 if ( rCols.GetLeftMin() != sal_uInt16((pTab->Frm().*fnRect->fnGetLeft)()) ) 1319 { 1320 const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin(); 1321 nColLeft += nDiff; 1322 nColRight += nDiff; 1323 } 1324 const long nCellLeft = (pCell->Frm().*fnRect->fnGetLeft)(); 1325 const long nCellRight = (pCell->Frm().*fnRect->fnGetRight)(); 1326 1327 //Ueberschneidungsbetrag ermitteln. 1328 long nWidth = 0; 1329 if ( nColLeft <= nCellLeft && nColRight >= (nCellLeft+COLFUZZY) ) 1330 nWidth = nColRight - nCellLeft; 1331 else if ( nColLeft <= (nCellRight-COLFUZZY) && nColRight >= nCellRight ) 1332 nWidth = nCellRight - nColLeft; 1333 else if ( nColLeft >= nCellLeft && nColRight <= nCellRight ) 1334 nWidth = nColRight - nColLeft; 1335 if ( nWidth && pCell->Frm().Width() ) 1336 { 1337 long nTmp = nWidth * nWish / pCell->Frm().Width(); 1338 if ( sal_uInt16(nTmp) > rToFill[i] ) 1339 rToFill[i] = sal_uInt16(nTmp); 1340 } 1341 } 1342 } 1343 1344 /*Besorgt neue Werte zu Einstellung der TabCols. 1345 *Es wird nicht ueber die Eintrage in den TabCols itereriert, sondern 1346 *quasi ueber die Zwischenraeume, die ja die Zellen beschreiben. 1347 * 1348 *bWishValues == sal_True: Es werden zur aktuellen Selektion bzw. zur aktuellen 1349 * Zelle die Wunschwerte aller betroffen Zellen ermittelt. 1350 * Sind mehrere Zellen in einer Spalte, so wird der 1351 * groesste Wunschwert als Ergebnis geliefert. 1352 * Fuer die TabCol-Eintraege, zu denen keine Zellen 1353 * ermittelt wurden, werden 0-en eingetragen. 1354 * 1355 *bWishValues == sal_False: Die Selektion wird senkrecht ausgedehnt. Zu jeder 1356 * Spalte in den TabCols, die sich mit der Selektion 1357 * schneidet wird der Minimalwert ermittelt. 1358 */ 1359 1360 void lcl_CalcColValues( SvUShorts &rToFill, const SwTabCols &rCols, 1361 const SwLayoutFrm *pStart, const SwLayoutFrm *pEnd, 1362 sal_Bool bWishValues ) 1363 { 1364 SwSelUnions aUnions; 1365 ::MakeSelUnions( aUnions, pStart, pEnd, 1366 bWishValues ? nsSwTblSearchType::TBLSEARCH_NONE : nsSwTblSearchType::TBLSEARCH_COL ); 1367 1368 for ( sal_uInt16 i2 = 0; i2 < aUnions.Count(); ++i2 ) 1369 { 1370 SwSelUnion *pSelUnion = aUnions[i2]; 1371 const SwTabFrm *pTab = pSelUnion->GetTable(); 1372 const SwRect &rUnion = pSelUnion->GetUnion(); 1373 1374 SWRECTFN( pTab ) 1375 sal_Bool bRTL = pTab->IsRightToLeft(); 1376 1377 const SwLayoutFrm *pCell = pTab->FirstCell(); 1378 do 1379 { 1380 if ( pCell->IsCellFrm() && pCell->FindTabFrm() == pTab && ::IsFrmInTblSel( rUnion, pCell ) ) 1381 { 1382 const long nCLeft = (pCell->Frm().*fnRect->fnGetLeft)(); 1383 const long nCRight = (pCell->Frm().*fnRect->fnGetRight)(); 1384 1385 sal_Bool bNotInCols = sal_True; 1386 1387 for ( sal_uInt16 i = 0; i <= rCols.Count(); ++i ) 1388 { 1389 sal_uInt16 nFit = rToFill[i]; 1390 long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1]; 1391 long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i]; 1392 1393 if ( bRTL ) 1394 { 1395 long nTmpRight = nColRight; 1396 nColRight = rCols.GetRight() - nColLeft; 1397 nColLeft = rCols.GetRight() - nTmpRight; 1398 } 1399 1400 nColLeft += rCols.GetLeftMin(); 1401 nColRight += rCols.GetLeftMin(); 1402 1403 //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen. 1404 long nLeftA = nColLeft; 1405 long nRightA = nColRight; 1406 if ( rCols.GetLeftMin() != sal_uInt16((pTab->Frm().*fnRect->fnGetLeft)()) ) 1407 { 1408 const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin(); 1409 nLeftA += nDiff; 1410 nRightA += nDiff; 1411 } 1412 1413 //Wir wollen nicht allzu genau hinsehen. 1414 if ( ::IsSame(nCLeft, nLeftA) && ::IsSame(nCRight, nRightA)) 1415 { 1416 bNotInCols = sal_False; 1417 if ( bWishValues ) 1418 { 1419 const sal_uInt16 nWish = ::lcl_CalcCellFit( pCell ); 1420 if ( nWish > nFit ) 1421 nFit = nWish; 1422 } 1423 else 1424 { const sal_uInt16 nMin = MINLAY + sal_uInt16(pCell->Frm().Width() - 1425 pCell->Prt().Width()); 1426 if ( !nFit || nMin < nFit ) 1427 nFit = nMin; 1428 } 1429 if ( rToFill[i] < nFit ) 1430 rToFill[i] = nFit; 1431 } 1432 } 1433 if ( bNotInCols ) 1434 ::lcl_CalcSubColValues( rToFill, rCols, pCell, pTab, bWishValues ); 1435 } 1436 do { 1437 pCell = pCell->GetNextLayoutLeaf(); 1438 }while( pCell && pCell->Frm().Width() == 0 ); 1439 } while ( pCell && pTab->IsAnLower( pCell ) ); 1440 } 1441 } 1442 1443 1444 void SwDoc::AdjustCellWidth( const SwCursor& rCursor, sal_Bool bBalance ) 1445 { 1446 // pruefe ob vom aktuellen Crsr der Point/Mark in einer Tabelle stehen 1447 SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); 1448 SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; 1449 if( !pTblNd ) 1450 return ; 1451 1452 SwLayoutFrm *pStart, *pEnd; 1453 ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); 1454 1455 //TabCols besorgen, den ueber diese stellen wir die Tabelle neu ein. 1456 SwFrm* pBoxFrm = pStart; 1457 while( pBoxFrm && !pBoxFrm->IsCellFrm() ) 1458 pBoxFrm = pBoxFrm->GetUpper(); 1459 1460 if ( !pBoxFrm ) 1461 return; // robust 1462 1463 SwTabCols aTabCols; 1464 GetTabCols( aTabCols, 0, (SwCellFrm*)pBoxFrm ); 1465 1466 if ( ! aTabCols.Count() ) 1467 return; 1468 1469 const sal_uInt8 nTmp = (sal_uInt8)Max( sal_uInt16(255), sal_uInt16(aTabCols.Count() + 1) ); 1470 SvUShorts aWish( nTmp, nTmp ), 1471 aMins( nTmp, nTmp ); 1472 sal_uInt16 i; 1473 1474 for ( i = 0; i <= aTabCols.Count(); ++i ) 1475 { 1476 aWish.Insert( sal_uInt16(0), aWish.Count() ); 1477 aMins.Insert( sal_uInt16(0), aMins.Count() ); 1478 } 1479 ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, sal_True ); 1480 1481 //Es ist Robuster wenn wir die Min-Werte fuer die ganze Tabelle berechnen. 1482 const SwTabFrm *pTab = pStart->ImplFindTabFrm(); 1483 pStart = (SwLayoutFrm*)pTab->FirstCell(); 1484 pEnd = (SwLayoutFrm*)pTab->FindLastCntnt()->GetUpper(); 1485 while( !pEnd->IsCellFrm() ) 1486 pEnd = pEnd->GetUpper(); 1487 ::lcl_CalcColValues( aMins, aTabCols, pStart, pEnd, sal_False ); 1488 1489 if( bBalance ) 1490 { 1491 //Alle Spalten, die makiert sind haben jetzt einen Wunschwert 1492 //eingtragen. Wir addieren die aktuellen Werte, teilen das Ergebnis 1493 //durch die Anzahl und haben eine Wunschwert fuer den ausgleich. 1494 sal_uInt16 nWish = 0, nCnt = 0; 1495 for ( i = 0; i <= aTabCols.Count(); ++i ) 1496 { 1497 int nDiff = aWish[i]; 1498 if ( nDiff ) 1499 { 1500 if ( i == 0 ) 1501 nWish = static_cast<sal_uInt16>( nWish + aTabCols[i] - aTabCols.GetLeft() ); 1502 else if ( i == aTabCols.Count() ) 1503 nWish = static_cast<sal_uInt16>(nWish + aTabCols.GetRight() - aTabCols[i-1] ); 1504 else 1505 nWish = static_cast<sal_uInt16>(nWish + aTabCols[i] - aTabCols[i-1] ); 1506 ++nCnt; 1507 } 1508 } 1509 nWish = nWish / nCnt; 1510 for ( i = 0; i < aWish.Count(); ++i ) 1511 if ( aWish[i] ) 1512 aWish[i] = nWish; 1513 } 1514 1515 const sal_uInt16 nOldRight = static_cast<sal_uInt16>(aTabCols.GetRight()); 1516 1517 //Um die Impl. einfach zu gestalten, aber trotzdem in den meissten Faellen 1518 //den Platz richtig auszunutzen laufen wir zweimal. 1519 //Problem: Erste Spalte wird breiter, die anderen aber erst danach 1520 //schmaler. Die Wunschbreite der ersten Spalte wuerde abgelehnt, weil 1521 //mit ihr die max. Breite der Tabelle ueberschritten wuerde. 1522 for ( sal_uInt16 k= 0; k < 2; ++k ) 1523 { 1524 for ( i = 0; i <= aTabCols.Count(); ++i ) 1525 { 1526 int nDiff = aWish[i]; 1527 if ( nDiff ) 1528 { 1529 int nMin = aMins[i]; 1530 if ( nMin > nDiff ) 1531 nDiff = nMin; 1532 1533 if ( i == 0 ) 1534 { 1535 if( aTabCols.Count() ) 1536 nDiff -= aTabCols[0] - aTabCols.GetLeft(); 1537 else 1538 nDiff -= aTabCols.GetRight() - aTabCols.GetLeft(); 1539 } 1540 else if ( i == aTabCols.Count() ) 1541 nDiff -= aTabCols.GetRight() - aTabCols[i-1]; 1542 else 1543 nDiff -= aTabCols[i] - aTabCols[i-1]; 1544 1545 long nTabRight = aTabCols.GetRight() + nDiff; 1546 1547 //Wenn die Tabelle zu breit wuerde begrenzen wir die Anpassung 1548 //auf das erlaubte Maximum. 1549 if ( !bBalance && nTabRight > aTabCols.GetRightMax() ) 1550 { 1551 const long nTmpD = nTabRight - aTabCols.GetRightMax(); 1552 nDiff -= nTmpD; 1553 nTabRight -= nTmpD; 1554 } 1555 for ( sal_uInt16 i2 = i; i2 < aTabCols.Count(); ++i2 ) 1556 aTabCols[i2] += nDiff; 1557 aTabCols.SetRight( nTabRight ); 1558 } 1559 } 1560 } 1561 1562 const sal_uInt16 nNewRight = static_cast<sal_uInt16>(aTabCols.GetRight()); 1563 1564 SwFrmFmt *pFmt = pTblNd->GetTable().GetFrmFmt(); 1565 const sal_Int16 nOriHori = pFmt->GetHoriOrient().GetHoriOrient(); 1566 1567 //So, die richtige Arbeit koennen wir jetzt der SwTable ueberlassen. 1568 SetTabCols( aTabCols, sal_False, 0, (SwCellFrm*)pBoxFrm ); 1569 1570 // i54248: lijian/fme 1571 // alignment might have been changed in SetTabCols, restore old value: 1572 const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient(); 1573 SwFmtHoriOrient aHori( rHori ); 1574 if ( aHori.GetHoriOrient() != nOriHori ) 1575 { 1576 aHori.SetHoriOrient( nOriHori ); 1577 pFmt->SetFmtAttr( aHori ); 1578 } 1579 1580 //Bei Automatischer Breite wird auf Linksbuendig umgeschaltet. 1581 //Bei Randattributen wird der Rechte Rand angepasst. 1582 if( !bBalance && nNewRight < nOldRight ) 1583 { 1584 if( aHori.GetHoriOrient() == text::HoriOrientation::FULL ) 1585 { 1586 aHori.SetHoriOrient( text::HoriOrientation::LEFT ); 1587 pFmt->SetFmtAttr( aHori ); 1588 } 1589 } 1590 1591 SetModified(); 1592 } 1593 1594