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